bool CBBlockChainStorageLoadOutputs(void * validator, uint8_t * txHash, uint8_t ** data, uint32_t * dataAllocSize, uint32_t * position){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 14, 0)) { CBLogError("Could not read a transaction reference from the transaction index."); return false; } // Set position of outputs *position = CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_POSITION_OUPTUTS); // Get transaction to find position for output in the block // Reallocate transaction data memory if needed. if (CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_LENGTH_OUTPUTS) > *dataAllocSize) { *dataAllocSize = CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_LENGTH_OUTPUTS); *data = realloc(*data, *dataAllocSize); if (NOT *data) { CBLogError("Could not allocate memory for reading a transaction."); return false; } } // Read transaction from the block CB_BLOCK_KEY[2] = CB_DATA_ARRAY[CB_TRANSACTION_REF_BRANCH]; memcpy(CB_BLOCK_KEY + 3, CB_DATA_ARRAY + CB_TRANSACTION_REF_BLOCK_INDEX, 4); if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, *data, CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_LENGTH_OUTPUTS), CB_BLOCK_START + *position)) { CBLogError("Could not read a transaction from the block-chain database."); return false; } return true; }
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; }
bool CBBlockChainStorageSaveTransactionRef(void * validator, uint8_t * txHash, uint8_t branch, uint32_t blockIndex, uint32_t outputPos, uint32_t outputsLen, bool coinbase, uint32_t numOutputs){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); if (CBDatabaseGetLength(database, CB_TRANSACTION_INDEX_KEY)) { // We have the transaction already. Thus obtain the data already in the index. if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 22, 0)) { CBLogError("Could not read a transaction reference from the transaction index."); return false; } // Increase the instance count. We change nothing else as we will use the first instance for all other instances. CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_INSTANCE_COUNT, CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_INSTANCE_COUNT) + 1); }else{ // This transaction has not yet been seen in the block chain. CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_BLOCK_INDEX, blockIndex); CB_DATA_ARRAY[CB_TRANSACTION_REF_BRANCH] = branch; CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_POSITION_OUPTUTS, outputPos); CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_LENGTH_OUTPUTS, outputsLen); CB_DATA_ARRAY[CB_TRANSACTION_REF_IS_COINBASE] = coinbase; // We start with an instance count of one CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_INSTANCE_COUNT, 1); } // Always set the number of unspent outputs back to the number of outputs in the transaction CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_NUM_UNSPENT_OUTPUTS, numOutputs); // Write to the transaction index. if (NOT CBDatabaseWriteValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 22)) { CBLogError("Could not write transaction reference to transaction index."); return false; } return true; }
bool CBBlockChainStorageLoadBranch(void * validator, uint8_t branchNum){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Get simple information CB_BRANCH_KEY[2] = branchNum; if (NOT CBDatabaseReadValue(database, CB_BRANCH_KEY, CB_DATA_ARRAY, 21, 0)) { CBLogError("There was an error when reading the data for a branch's information."); return false; } validatorObj->branches[branchNum].lastRetargetTime = CBArrayToInt32(CB_DATA_ARRAY, CB_BRANCH_LAST_RETARGET); validatorObj->branches[branchNum].lastValidation = CBArrayToInt32(CB_DATA_ARRAY, CB_BRANCH_LAST_VALIDATION); validatorObj->branches[branchNum].numBlocks = CBArrayToInt32(CB_DATA_ARRAY, CB_BRANCH_NUM_BLOCKS); validatorObj->branches[branchNum].parentBlockIndex = CBArrayToInt32(CB_DATA_ARRAY, CB_BRANCH_PARENT_BLOCK_INDEX); validatorObj->branches[branchNum].parentBranch = CB_DATA_ARRAY[CB_BRANCH_PARENT_BRANCH]; validatorObj->branches[branchNum].startHeight = CBArrayToInt32(CB_DATA_ARRAY, CB_BRANCH_START_HEIGHT); validatorObj->branches[branchNum].working = false; // Start off not working on any branch. return true; }
bool CBBlockChainStorageChangeUnspentOutputsNum(CBDatabase * database, uint8_t * txHash, int8_t change){ // Place transaction hash into the key memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); // Read the number of unspent outputs to be decremented if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 18, 0)) return false; CBInt32ToArray(CB_DATA_ARRAY, CB_TRANSACTION_REF_NUM_UNSPENT_OUTPUTS, CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_NUM_UNSPENT_OUTPUTS) + change); // Now write the new value return CBDatabaseWriteValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 18); }
uint32_t CBBlockChainStorageGetBlockTarget(void * validator, uint8_t branch, uint32_t blockIndex){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_BLOCK_KEY[2] = branch; CBInt32ToArray(CB_BLOCK_KEY, 3, blockIndex); if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, CB_DATA_ARRAY, 4, CB_BLOCK_TARGET)) { CBLogError("Could not read the target for a block."); return 0; } return CBArrayToInt32(CB_DATA_ARRAY, 0); }
bool CBBlockChainStorageGetBlockLocation(void * validator, uint8_t * blockHash, uint8_t * branch, uint32_t * index){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; memcpy(CB_BLOCK_HASH_INDEX_KEY + 2, blockHash, 20); if (NOT CBDatabaseReadValue(database, CB_BLOCK_HASH_INDEX_KEY, CB_DATA_ARRAY, 5, 0)) { CBLogError("Could not read a block hash reference from the block chain database."); return false; } *branch = CB_DATA_ARRAY[CB_BLOCK_HASH_REF_BRANCH]; *index = CBArrayToInt32(CB_DATA_ARRAY, CB_BLOCK_HASH_REF_INDEX); return true; }
bool CBBlockChainStorageIsTransactionWithUnspentOutputs(void * validator, uint8_t * txHash, bool * exists){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Place transaction hash into the key memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); // See if the transaction exists if (NOT CBDatabaseGetLength(database, CB_TRANSACTION_INDEX_KEY)){ *exists = false; return true; } // Now see if the transaction has unspent outputs if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 4, CB_TRANSACTION_REF_NUM_UNSPENT_OUTPUTS)) { CBLogError("Could not read the number of unspent outputs for a transaction."); return false; } *exists = CBArrayToInt32(CB_DATA_ARRAY, 0); return true; }
bool CBAddressStorageLoadAddresses(uint64_t iself, void * addrMan){ CBDatabase * database = (CBDatabase *)iself; CBAddressManager * addrManObj = addrMan; CBPosition it; // The first element shoudl be the number of addresses so get second element to begin with. if (CBAssociativeArrayGetElement(&database->index, &it, 1)) for(;;) { uint8_t * key = it.node->elements[it.index]; CBIndexValue * val = (CBIndexValue *)(key + *key + 1); if (val->length) { // Is not deleted. // Read data uint64_t file = CBDatabaseGetFile(database, val->fileID); if (NOT file) { CBLogError("Could not open a file for loading a network address."); return false; } if (NOT CBFileSeek(file, val->pos)){ CBLogError("Could not read seek a file to a network address."); return false; } if (NOT CBFileRead(file, CB_DATA_ARRAY, 20)) { CBLogError("Could not read a network address from a file."); return false; } // Create network address object and add to the address manager. CBByteArray * ip = CBNewByteArrayWithDataCopy(key + 1, 16); CBNetworkAddress * addr = CBNewNetworkAddress(CBArrayToInt64(CB_DATA_ARRAY, 0), ip, CBArrayToInt16(key, 17), (CBVersionServices) CBArrayToInt64(CB_DATA_ARRAY, 8), true); addr->penalty = CBArrayToInt32(CB_DATA_ARRAY, 16); if (NOT CBAddressManagerTakeAddress(addrManObj, addr)) { CBLogError("Could not create and add a network address to the address manager."); return false; } CBReleaseObject(ip); } if (CBAssociativeArrayIterate(&database->index, &it)) break; } return true; }
uint64_t CBNewAddressStorage(char * dataDir){ CBAddressStore * self = malloc(sizeof(*self)); if (NOT self) { CBLogError("Could not create the address storage object."); return 0; } if (NOT CBInitDatabase(CBGetDatabase(self), dataDir, "addr")) { CBLogError("Could not create a database object for address storage."); free(self); return 0; } if (CBDatabaseGetLength(CBGetDatabase(self), CB_ADDR_NUM_KEY)) { // Get the number of addresses if (NOT CBDatabaseReadValue(CBGetDatabase(self), CB_ADDR_NUM_KEY, CB_DATA_ARRAY, 4, 0)) { CBLogError("Could not read the number of addresses from storage."); free(self); return 0; } self->numAddresses = CBArrayToInt32(CB_DATA_ARRAY, 0); }else{ self->numAddresses = 0; // Insert zero number of addresses. CBInt32ToArray(CB_DATA_ARRAY, 0, 0); if (NOT CBDatabaseWriteValue(CBGetDatabase(self), CB_ADDR_NUM_KEY, CB_DATA_ARRAY, 4)) { CBLogError("Could not write the initial number of addresses to storage."); free(self); return 0; } // Commit changes if (NOT CBDatabaseCommit(CBGetDatabase(self))) { CBLogError("Could not commit the initial number of addresses to storage."); free(self); return 0; } } return (uint64_t) self; }