bool CBAddressStorageSaveAddress(uint64_t iself, void * address){ CBAddressStore * self = (CBAddressStore *)iself; CBNetworkAddress * addrObj = address; // Create key memcpy(CB_ADDRESS_KEY + 1, CBByteArrayGetData(addrObj->ip), 16); CBInt16ToArray(CB_ADDRESS_KEY, 17, addrObj->port); // Create data CBInt64ToArray(CB_DATA_ARRAY, 0, addrObj->lastSeen); CBInt64ToArray(CB_DATA_ARRAY, 8, (uint64_t) addrObj->services); CBInt32ToArray(CB_DATA_ARRAY, 16, addrObj->penalty); // Write data if (NOT CBDatabaseWriteValue(CBGetDatabase(self), CB_ADDRESS_KEY, CB_DATA_ARRAY, 20)) { CBLogError("Could not write an address to storage."); return false; } // Increase the number of addresses CBInt32ToArray(CB_DATA_ARRAY, 0, --self->numAddresses); if (NOT CBDatabaseWriteValue(CBGetDatabase(self), CB_ADDR_NUM_KEY, CB_DATA_ARRAY, 4)) { CBLogError("Could not write the new number of addresses to storage."); return false; } // Commit changes if (NOT CBDatabaseCommit(CBGetDatabase(self))) { CBLogError("Could not commit adding a new network address to storage."); return false; } return true; }
bool CBBlockChainStorageDeleteTransactionRef(void * validator, uint8_t * txHash){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Place transaction hash into the key memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); // Read the instance count if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 22, 0)) { CBLogError("Could not read a transaction reference from storage."); return false; } uint32_t txInstanceNum = CB_DATA_ARRAY[CB_TRANSACTION_REF_INSTANCE_COUNT] - 1; if (txInstanceNum) { // There are still more instances of this transaction. Do not remove the transaction, only make the unspent output number equal to zero and decrement the instance count. CB_DATA_ARRAY[CB_TRANSACTION_REF_NUM_UNSPENT_OUTPUTS] = 0; CB_DATA_ARRAY[CB_TRANSACTION_REF_INSTANCE_COUNT] = txInstanceNum; // Write to storage. if (NOT CBDatabaseWriteValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 22)) { CBLogError("Could not update a transaction reference for deleting an instance."); return false; } }else{ // This was the last instance. // Remove from storage if (NOT CBDatabaseRemoveValue(database, CB_TRANSACTION_INDEX_KEY)) { CBLogError("Could not remove a transaction reference from storage."); return false; } } return true; }
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 CBBlockChainStorageSaveBranchWork(void * validator, uint8_t branch){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_WORK_KEY[2] = branch; if (NOT CBDatabaseWriteValue(database, CB_WORK_KEY, validatorObj->branches[branch].work.data, validatorObj->branches[branch].work.length)) { CBLogError("Could not write branch work."); return false; } 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); }
bool CBBlockChainStorageSaveOrphan(void * validator, void * block, uint8_t orphanNum){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CBBlock * blockObj = block; CB_ORPHAN_KEY[2] = orphanNum; if (NOT CBDatabaseWriteValue(database, CB_ORPHAN_KEY, CBByteArrayGetData(CBGetMessage(blockObj)->bytes), CBGetMessage(blockObj)->bytes->length)) { CBLogError("Could not write an orphan."); return false; } return true; }
bool CBBlockChainStorageSaveBasicValidator(void * validator){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_DATA_ARRAY[CB_VALIDATION_FIRST_ORPHAN] = validatorObj->firstOrphan; CB_DATA_ARRAY[CB_VALIDATION_NUM_ORPHANS] = validatorObj->numOrphans; CB_DATA_ARRAY[CB_VALIDATION_MAIN_BRANCH] = validatorObj->mainBranch; CB_DATA_ARRAY[CB_VALIDATION_NUM_BRANCHES] = validatorObj->numBranches; if (NOT CBDatabaseWriteValue(database, CB_VALIDATOR_INFO_KEY, CB_DATA_ARRAY, 4)) { CBLogError("Could not write the initial basic validation data."); return false; } return true; }
bool CBBlockChainStorageSaveBranch(void * validator, uint8_t branch){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_BRANCH_KEY[2] = branch; // Make data CBInt32ToArray(CB_DATA_ARRAY, CB_BRANCH_LAST_RETARGET, validatorObj->branches[branch].lastRetargetTime); CBInt32ToArray(CB_DATA_ARRAY, CB_BRANCH_LAST_VALIDATION, validatorObj->branches[branch].lastValidation); CBInt32ToArray(CB_DATA_ARRAY, CB_BRANCH_NUM_BLOCKS, validatorObj->branches[branch].numBlocks); CBInt32ToArray(CB_DATA_ARRAY, CB_BRANCH_PARENT_BLOCK_INDEX, validatorObj->branches[branch].parentBlockIndex); CB_DATA_ARRAY[CB_BRANCH_PARENT_BRANCH] = validatorObj->branches[branch].parentBranch; CBInt32ToArray(CB_DATA_ARRAY, CB_BRANCH_START_HEIGHT, validatorObj->branches[branch].startHeight); // Write data if (NOT CBDatabaseWriteValue(database, CB_BRANCH_KEY, CB_DATA_ARRAY, 21)) { CBLogError("Could not write branch information."); return false; } return true; }
bool CBBlockChainStorageSaveUnspentOutput(void * validator, uint8_t * txHash, uint32_t outputIndex, uint32_t position, uint32_t length, bool increment){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; memcpy(CB_UNSPENT_OUTPUT_KEY + 2, txHash, 32); CBInt32ToArray(CB_UNSPENT_OUTPUT_KEY, 34, outputIndex); CBInt32ToArray(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_POSITION, position); CBInt32ToArray(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_LENGTH, length); // Add to storage if (NOT CBDatabaseWriteValue(database, CB_UNSPENT_OUTPUT_KEY, CB_DATA_ARRAY, 8)) { CBLogError("Could not write new unspent output reference into the database."); return false; } if (increment // For the transaction, increment the number of unspent outputs && NOT CBBlockChainStorageChangeUnspentOutputsNum(database, txHash, +1)) { CBLogError("Could not increment the number of unspent outputs for a transaction."); return false; } return true; }
bool CBBlockChainStorageSaveBlock(void * validator, void * block, uint8_t branch, uint32_t blockIndex){ CBFullValidator * validatorObj = validator; CBBlock * blockObj = block; // Write the block data CB_BLOCK_KEY[2] = branch; CBInt32ToArray(CB_BLOCK_KEY, 3, blockIndex); uint8_t * dataParts[2] = {CBBlockGetHash(blockObj), CBByteArrayGetData(CBGetMessage(blockObj)->bytes)}; uint32_t dataSizes[2] = {20, CBGetMessage(blockObj)->bytes->length}; if (NOT CBDatabaseWriteConcatenatedValue((CBDatabase *)validatorObj->storage, CB_BLOCK_KEY, 2, dataParts, dataSizes)) { CBLogError("Could not write a block to the block-chain database."); return false; } // Write to the block hash index memcpy(CB_BLOCK_HASH_INDEX_KEY + 2, CBBlockGetHash(blockObj), 20); CB_DATA_ARRAY[CB_BLOCK_HASH_REF_BRANCH] = branch; CBInt32ToArray(CB_DATA_ARRAY, CB_BLOCK_HASH_REF_INDEX, blockIndex); if (NOT CBDatabaseWriteValue((CBDatabase *)validatorObj->storage, CB_BLOCK_HASH_INDEX_KEY, CB_DATA_ARRAY, 5)) { CBLogError("Could not write a block hash to the block-chain database block hash index."); return false; } return true; }
bool CBAddressStorageDeleteAddress(uint64_t iself, void * address){ CBAddressStore * self = (CBAddressStore *)iself; CBNetworkAddress * addrObj = address; memcpy(CB_ADDRESS_KEY + 1, CBByteArrayGetData(addrObj->ip), 16); CBInt16ToArray(CB_ADDRESS_KEY, 17, addrObj->port); // Remove address if (NOT CBDatabaseRemoveValue(CBGetDatabase(self), CB_ADDRESS_KEY)) { CBLogError("Could not remove an address from storage."); return false; } // Decrease number of addresses CBInt32ToArray(CB_DATA_ARRAY, 0, --self->numAddresses); if (NOT CBDatabaseWriteValue(CBGetDatabase(self), CB_ADDR_NUM_KEY, CB_DATA_ARRAY, 4)) { CBLogError("Could not write the new number of addresses to storage."); return false; } // Commit changes if (NOT CBDatabaseCommit(CBGetDatabase(self))) { CBLogError("Could not commit the removal of a network address."); return false; } 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; }