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; }
void BRSendMessage(BRConnection *c, CBMessage *message, char *command) { /* partially adapted from examples/pingpong.c */ char header[24] = {0}; /* zeros help us out places */ memcpy(header + CB_MESSAGE_HEADER_TYPE, command, strlen(command)); uint8_t hash[32]; uint8_t hash2[32]; if (message->bytes) CBSha256(CBByteArrayGetData(message->bytes), message->bytes->length, hash); else { /* Get the checksum right -- handles problem where checksum not calculated * for messages with no payload */ CBSha256(NULL, 0, hash); } CBSha256(hash, 32, hash2); message->checksum[0] = hash2[0]; message->checksum[1] = hash2[1]; message->checksum[2] = hash2[2]; message->checksum[3] = hash2[3]; CBInt32ToArray(header, CB_MESSAGE_HEADER_NETWORK_ID, NETMAGIC); if (message->bytes) { CBInt32ToArray(header, CB_MESSAGE_HEADER_LENGTH, message->bytes->length); } memcpy(header + CB_MESSAGE_HEADER_CHECKSUM, message->checksum, 4); int sent = send(c->sock, header, 24, 0); if (sent < 0) { perror("send failed"); exit(1); } if (sent != 24) { fprintf(stderr, "send sent %d, not 24 bytes\n", sent); exit(1); } if (message->bytes) { sent = send(c->sock, message->bytes->sharedData->data + message->bytes->offset, message->bytes->length, 0); if (sent < 0) { perror("send failed"); exit(1); } if (sent != message->bytes->length) { fprintf(stderr, "send sent %d, not %d bytes\n", sent, message->bytes->length); exit(1); } } #ifdef BRDEBUG print_header(header); printf("message len: %d\n", message->bytes ? message->bytes->length : 0); printf("checksum: %x\n", *((uint32_t *) message->checksum)); print_hex(message->bytes); printf("\n"); #endif }
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; }
void * CBBlockChainStorageLoadBlock(void * validator, uint32_t blockID, uint32_t branch){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_BLOCK_KEY[2] = branch; CBInt32ToArray(CB_BLOCK_KEY, 3, blockID); uint32_t blockDataLen = CBDatabaseGetLength(database, CB_BLOCK_KEY); if (NOT blockDataLen) return NULL; blockDataLen -= CB_BLOCK_START; // Get block data CBByteArray * data = CBNewByteArrayOfSize(blockDataLen); if (NOT data) { CBLogError("Could not initialise a byte array for loading a block."); return NULL; } if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, CBByteArrayGetData(data), blockDataLen, CB_BLOCK_START)){ CBLogError("Could not read a block from the database."); CBReleaseObject(data); return NULL; } // Make and return the block CBBlock * block = CBNewBlockFromData(data); CBReleaseObject(data); if (NOT block) { CBLogError("Could not create a block object when loading a block."); return NULL; } return block; }
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; }
static void send_version() { CBByteArray *ip = CBNewByteArrayWithDataCopy((uint8_t [16]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 127, 0, 0, 1}, 16); CBByteArray *ua = CBNewByteArrayFromString("cmsc417versiona", '\00'); CBNetworkAddress * sourceAddr = CBNewNetworkAddress(0, ip, 0, CB_SERVICE_FULL_BLOCKS, false); int32_t vers = 70001; int nonce = rand(); CBVersion * version = CBNewVersion(vers, CB_SERVICE_FULL_BLOCKS, time(NULL), &peer->base, sourceAddr, nonce, ua, 0); CBMessage *message = CBGetMessage(version); char header[24]; memcpy(header + CB_MESSAGE_HEADER_TYPE, "version\0\0\0\0\0", 12); /* Compute length, serialized, and checksum */ uint32_t len = CBVersionCalculateLength(version); message->bytes = CBNewByteArrayOfSize(len); len = CBVersionSerialise(version, false); if (message->bytes) { // Make checksum uint8_t hash[32]; uint8_t hash2[32]; CBSha256(CBByteArrayGetData(message->bytes), message->bytes->length, hash); CBSha256(hash, 32, hash2); message->checksum[0] = hash2[0]; message->checksum[1] = hash2[1]; message->checksum[2] = hash2[2]; message->checksum[3] = hash2[3]; } CBInt32ToArray(header, CB_MESSAGE_HEADER_NETWORK_ID, NETMAGIC); CBInt32ToArray(header, CB_MESSAGE_HEADER_LENGTH, message->bytes->length); // Checksum memcpy(header + CB_MESSAGE_HEADER_CHECKSUM, message->checksum, 4); // Send the header send(sd, header, 24, 0); // Send the message printf("message len: %d\n", message->bytes->length); printf("checksum: %x\n", *((uint32_t *) message->checksum)); send(sd, message->bytes->sharedData->data+message->bytes->offset, message->bytes->length, 0); print_hex(message->bytes); }
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; }
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 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 CBBlockChainStorageMoveBlock(void * validator, uint8_t branch, uint32_t blockIndex, uint8_t newBranch, uint32_t newIndex){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_BLOCK_KEY[2] = branch; CBInt32ToArray(CB_BLOCK_KEY, 3, blockIndex); CB_NEW_BLOCK_KEY[2] = newBranch; if (NOT CBDatabaseChangeKey(database, CB_BLOCK_KEY, CB_NEW_BLOCK_KEY)) { CBLogError("Could not move a block location in the block-chain database."); 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 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 CBBlockChainStorageDeleteUnspentOutput(void * validator, uint8_t * txHash, uint32_t outputIndex, bool decrement){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Place transaction hash into the key memcpy(CB_UNSPENT_OUTPUT_KEY + 2, txHash, 32); // Place output index into the key CBInt32ToArray(CB_UNSPENT_OUTPUT_KEY, 34, outputIndex); // Remove from storage if (NOT CBDatabaseRemoveValue(database, CB_UNSPENT_OUTPUT_KEY)) { CBLogError("Could not remove an unspent output reference from storage."); return false; } if (decrement // For the transaction, decrement the number of unspent outputs && NOT CBBlockChainStorageChangeUnspentOutputsNum(database, txHash, -1)) { CBLogError("Could not decrement the number of unspent outputs for a transaction."); 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; }
bool CBBlockChainStorageDeleteBlock(void * validator, uint8_t branch, uint32_t blockIndex){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Delete from storage CB_BLOCK_KEY[2] = branch; CBInt32ToArray(CB_BLOCK_KEY, 3, blockIndex); // Get hash if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, CB_DATA_ARRAY, 20, CB_BLOCK_HASH)) { CBLogError("Could not obtain a block hash from the block chain database."); return false; } // Remove data if (NOT CBDatabaseRemoveValue(database, CB_BLOCK_KEY)){ CBLogError("Could not remove block value from database."); return false; } // Remove hash index reference memcpy(CB_BLOCK_HASH_INDEX_KEY + 2, CB_DATA_ARRAY, 20); if (NOT CBDatabaseRemoveValue(database, CB_BLOCK_HASH_INDEX_KEY)){ CBLogError("Could not remove block hash index reference from database."); return false; } return true; }
bool CBBlockChainStorageUnspentOutputExists(void * validator, uint8_t * txHash, uint32_t outputIndex){ CBFullValidator * validatorObj = validator; memcpy(CB_UNSPENT_OUTPUT_KEY + 2, txHash, 32); CBInt32ToArray(CB_UNSPENT_OUTPUT_KEY, 34, outputIndex); return CBDatabaseGetLength((CBDatabase *)validatorObj->storage, CB_UNSPENT_OUTPUT_KEY); }