void * CBBlockChainStorageLoadUnspentOutput(void * validator, uint8_t * txHash, uint32_t outputIndex, bool * coinbase, uint32_t * outputHeight){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // First read data for the unspent output key. memcpy(CB_UNSPENT_OUTPUT_KEY + 2, txHash, 32); CBInt32ToArray(CB_UNSPENT_OUTPUT_KEY, 34, outputIndex); if (NOT CBDatabaseReadValue(database, CB_UNSPENT_OUTPUT_KEY, CB_DATA_ARRAY, 8, 0)) { CBLogError("Cannot read unspent output information from the block chain database"); return NULL; } uint32_t outputPosition = CBArrayToInt32(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_POSITION); uint32_t outputLength = CBArrayToInt32(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_LENGTH); // Now read data for the transaction memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 14, 0)) { CBLogError("Cannot read a transaction reference from the transaction index."); return NULL; } uint8_t outputBranch = CB_DATA_ARRAY[CB_TRANSACTION_REF_BRANCH]; uint32_t outputBlockIndex = CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_BLOCK_INDEX); // Set coinbase *coinbase = CB_DATA_ARRAY[CB_TRANSACTION_REF_IS_COINBASE]; // Set output height *outputHeight = validatorObj->branches[outputBranch].startHeight + outputBlockIndex; // Get the output from storage CB_BLOCK_KEY[2] = outputBranch; CBInt32ToArray(CB_BLOCK_KEY, 3, outputBlockIndex); // Get output data CBByteArray * outputBytes = CBNewByteArrayOfSize(outputLength); if (NOT outputBytes) { CBLogError("Could not create CBByteArray for an unspent output."); return NULL; } if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, CBByteArrayGetData(outputBytes), outputLength, CB_BLOCK_START + outputPosition)) { CBLogError("Could not read an unspent output"); CBReleaseObject(outputBytes); return NULL; } // Create output object CBTransactionOutput * output = CBNewTransactionOutputFromData(outputBytes); CBReleaseObject(outputBytes); if (NOT output) { CBLogError("Could not create an object for an unspent output"); return NULL; } if (NOT CBTransactionOutputDeserialise(output)) { CBLogError("Could not deserialise an unspent output"); return NULL; } return output; }
uint32_t CBTransactionDeserialise(CBTransaction * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to deserialise a CBTransaction with no bytes."); return 0; } if (bytes->length < 10) { CBLogError("Attempting to deserialise a CBTransaction with less than 10 bytes."); return 0; } self->version = CBByteArrayReadInt32(bytes, 0); CBVarInt inputOutputLen = CBVarIntDecode(bytes, 4); if (NOT inputOutputLen.val || inputOutputLen.val * 41 > bytes->length - 10) { CBLogError("Attempting to deserialise a CBTransaction with a bad var int for the number of inputs."); return 0; } uint32_t cursor = 4 + inputOutputLen.size; self->inputNum = (uint32_t)inputOutputLen.val; self->inputs = malloc(sizeof(*self->inputs) * self->inputNum); if (NOT self->inputs) { CBLogError("Cannot allocate %i bytes of memory in CBTransactionDeserialise for inputs.\n", sizeof(*self->inputs) * self->inputNum); return 0; } for (uint32_t x = 0; x < self->inputNum; x++) { CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBLogError("Cannot create a new CBByteArray in CBTransactionDeserialise for the input number %u.", x); return 0; } CBTransactionInput * input = CBNewTransactionInputFromData(data); if (NOT input) { CBLogError("Cannot create a new CBTransactionInput in CBTransactionDeserialise for the input number %u.", x); CBReleaseObject(data); return 0; } uint32_t len = CBTransactionInputDeserialise(input); if (NOT len){ CBLogError("CBTransaction cannot be deserialised because of an error with the input number %u.", x); CBReleaseObject(data); return 0; } // The input was deserialised correctly. Now adjust the length and add it to the transaction. data->length = len; CBReleaseObject(data); self->inputs[x] = input; cursor += len; // Move along to next input } if (bytes->length < cursor + 5) { // Needs at least 5 more for the output CBVarInt and the lockTime CBLogError("Attempting to deserialise a CBTransaction with not enough bytes for the outputs and lockTime."); return 0; } inputOutputLen = CBVarIntDecode(bytes, cursor); if (NOT inputOutputLen.val || inputOutputLen.val * 9 > bytes->length - 10) { CBLogError("Attempting to deserialise a CBTransaction with a bad var int for the number of outputs."); return 0; } cursor += inputOutputLen.size; // Move past output CBVarInt self->outputNum = (uint32_t)inputOutputLen.val; self->outputs = malloc(sizeof(*self->outputs) * self->outputNum); if (NOT self->outputs) { CBLogError("Cannot allocate %i bytes of memory in CBTransactionDeserialise for outputs.\n", sizeof(sizeof(*self->outputs) * self->outputNum)); return 0; } for (uint32_t x = 0; x < self->outputNum; x++) { CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBLogError("Cannot create a new CBByteArray in CBTransactionDeserialise for the output number %u.", x); return 0; } CBTransactionOutput * output = CBNewTransactionOutputFromData(data); if (NOT output) { CBLogError("Cannot create a new CBTransactionOutput in CBTransactionDeserialise for the output number %u.", x); CBReleaseObject(data); return 0; } uint32_t len = CBTransactionOutputDeserialise(output); if (NOT len){ CBLogError("CBTransaction cannot be deserialised because of an error with the output number %u.", x); CBReleaseObject(data); return 0; } // The output was deserialised correctly. Now adjust the length and add it to the transaction. data->length = len; CBReleaseObject(data); self->outputs[x] = output; cursor += len; // Move along to next output } if (bytes->length < cursor + 4) { // Ensure 4 bytes are available for lockTime CBLogError("Attempting to deserialise a CBTransaction with not enough bytes for the lockTime."); return 0; } self->lockTime = CBByteArrayReadInt32(bytes, cursor); return cursor + 4; }