uint8_t CBNetworkAddressDeserialise(CBNetworkAddress * self, bool timestamp){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBNetworkAddress with no bytes."); return 0; } if (bytes->length < 26 + timestamp * 4) { CBLogError("Attempting to deserialise a CBNetworkAddress with less bytes than required."); return 0; } uint8_t start; uint64_t twoHoursAgo = time(NULL) - 3600; if (timestamp) { // Make sure we do not set self->lastSeen later than one hour ago. self->lastSeen = CBByteArrayReadInt32(bytes, 0); if (self->lastSeen > twoHoursAgo) self->lastSeen = twoHoursAgo; start = 4; }else{ self->lastSeen = twoHoursAgo; start = 0; } self->services = (CBVersionServices) CBByteArrayReadInt64(bytes, start); self->ip = CBNewByteArraySubReference(bytes, start + 8, 16); // Determine IP type self->type = CBGetIPType(CBByteArrayGetData(self->ip)); self->port = CBByteArrayReadPort(bytes, start + 24); return start + 26; }
bool CBBlockChainStorageLoadOrphan(void * validator, uint8_t orphanNum){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; CB_ORPHAN_KEY[2] = orphanNum; uint32_t len = CBDatabaseGetLength(database, CB_ORPHAN_KEY); CBByteArray * orphanData = CBNewByteArrayOfSize(len); if (NOT orphanData) { CBLogError("There was an error when initialising a byte array for an orphan."); return false; } if (NOT CBDatabaseReadValue(database, CB_ORPHAN_KEY, CBByteArrayGetData(orphanData), len, 0)) { CBLogError("There was an error when reading the data for an orphan."); CBReleaseObject(orphanData); return false; } validatorObj->orphans[orphanNum] = CBNewBlockFromData(orphanData); CBBlockDeserialise(validatorObj->orphans[orphanNum], true); if (NOT validatorObj->orphans[orphanNum]) { CBLogError("There was an error when creating a block object for an orphan."); CBReleaseObject(orphanData); return false; } CBReleaseObject(orphanData); return true; }
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 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; }
bool CBDecodeBase58Checked(CBBigInt * bi, char * str){ if(NOT CBDecodeBase58(bi, str)) { CBLogError("Memory failure in CBDecodeBase58."); return false; } if (bi->length < 4){ CBLogError("The string passed into CBDecodeBase58Checked decoded into data that was too short."); return false; } // Reverse bytes for checksum generation uint8_t * reversed = malloc(bi->length - 4); if (NOT reversed) { CBLogError("Cannot allocate %i bytes of memory in CBDecodeBase58Checked", bi->length - 4); return false; } for (uint8_t x = 4; x < bi->length; x++) reversed[bi->length - 1 - x] = bi->data[x]; // The checksum uses SHA-256, twice, for some reason unknown to man. uint8_t checksum[32]; uint8_t checksum2[32]; CBSha256(reversed, bi->length - 4, checksum); free(reversed); CBSha256(checksum, 32, checksum2); bool ok = true; for (uint8_t x = 0; x < 4; x++) if (checksum2[x] != bi->data[3-x]) ok = false; if (NOT ok){ CBLogError("The data passed to CBDecodeBase58Checked is invalid. Checksum does not match."); return false; } return true; }
uint32_t CBTransactionOutputSerialise(CBTransactionOutput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBTransactionInput with no bytes."); return 0; } if (NOT self->scriptObject){ CBLogError("Attempting to serialise a CBTransactionOutput without scriptObject."); return 0; } CBVarInt scriptLen = CBVarIntFromUInt64(CBGetByteArray(self->scriptObject)->length); uint32_t reqLen = 8 + scriptLen.size + CBGetByteArray(self->scriptObject)->length; if (bytes->length < reqLen) { CBLogError("Attempting to serialise a CBTransactionOutput with less bytes than required. %i < %i", bytes->length, reqLen); return 0; } // Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory. CBByteArraySetInt64(bytes, 0, self->value); CBVarIntEncode(bytes, 8, scriptLen); CBByteArrayCopyByteArray(bytes, 8 + scriptLen.size, CBGetByteArray(self->scriptObject)); CBByteArrayChangeReference(CBGetByteArray(self->scriptObject), bytes, 8 + scriptLen.size); // Ensure length is correct bytes->length = reqLen; // Is serialised. CBGetMessage(self)->serialised = true; return reqLen; }
uint16_t CBChainDescriptorDeserialise(CBChainDescriptor * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBChainDescriptor with no bytes."); return 0; } if (bytes->length < 1) { CBLogError("Attempting to deserialise a CBChainDescriptor with no bytes"); return 0; } CBVarInt hashNum = CBVarIntDecode(bytes, 0); if (hashNum.val > 500) { CBLogError("Attempting to deserialise a CBChainDescriptor with a var int over 500."); return 0; } if (bytes->length < hashNum.size + hashNum.val * 32) { CBLogError("Attempting to deserialise a CBChainDescriptor with less bytes than required for the hashes."); return 0; } // Deserialise each hash self->hashes = malloc(sizeof(*self->hashes) * (size_t)hashNum.val); self->hashNum = hashNum.val; uint16_t cursor = hashNum.size; for (uint16_t x = 0; x < self->hashNum; x++) { self->hashes[x] = CBNewByteArraySubReference(bytes, cursor, 32); cursor += 32; } return cursor; }
uint32_t CBTransactionInputDeserialise(CBTransactionInput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBTransactionInput with no bytes."); return 0; } if (bytes->length < 41) { CBLogError("Attempting to deserialise a CBTransactionInput with less than 41 bytes."); return 0; } CBVarInt scriptLen = CBVarIntDecode(bytes, 36); if (scriptLen.val > 10000) { CBLogError("Attempting to deserialise a CBTransactionInput with too big a script."); return 0; } uint32_t reqLen = (uint32_t)(40 + scriptLen.size + scriptLen.val); if (bytes->length < reqLen) { CBLogError("Attempting to deserialise a CBTransactionInput with less bytes than needed according to the length for the script. %i < %i", bytes->length, reqLen); return 0; } // Deserialise by subreferencing byte arrays and reading integers. self->prevOut.hash = CBByteArraySubReference(bytes, 0, 32); self->prevOut.index = CBByteArrayReadInt32(bytes, 32); self->scriptObject = CBNewScriptFromReference(bytes, 36 + scriptLen.size, (uint32_t) scriptLen.val); self->sequence = CBByteArrayReadInt32(bytes, (uint32_t) (36 + scriptLen.size + scriptLen.val)); return reqLen; }
int CBAlertSerialiseSignature(CBAlert * self, int offset) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBAlert with no bytes."); return 0; } CBVarInt sigLen = CBVarIntFromUInt64(self->signature->length); if (bytes->length < offset + sigLen.size + sigLen.val) { CBLogError("Attempting to serialise a CBAlert with less bytes than required for the signature."); return 0; } CBByteArraySetVarInt(bytes, offset, sigLen); offset += sigLen.size; CBByteArrayCopyByteArray(bytes, offset, self->signature); CBByteArrayChangeReference(self->signature, bytes, offset); bytes->length = offset + (int)sigLen.val; CBGetMessage(self)->serialised = true; return bytes->length; }
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; }
uint8_t CBNetworkAddressSerialise(CBNetworkAddress * self, bool timestamp){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBNetworkAddress with no bytes."); return 0; } if (bytes->length < 26 + timestamp * 4) { CBLogError("Attempting to serialise a CBNetworkAddress with less bytes than required."); return 0; } uint8_t cursor; if (timestamp) { CBByteArraySetInt32(bytes, 0, (uint32_t)(self->lastSeen - self->penalty)); cursor = 4; }else cursor = 0; CBByteArraySetInt64(bytes, cursor, self->services); cursor += 8; CBByteArrayCopyByteArray(bytes, cursor, self->ip); CBByteArrayChangeReference(self->ip, bytes, cursor); cursor += 16; CBByteArraySetPort(bytes, cursor, self->port); bytes->length = cursor + 2; CBGetMessage(self)->serialised = true; return cursor + 2; }
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 CBInitNode(CBNode * self, CBDepObject database, CBNodeFlags flags, CBNodeCallbacks nodeCallbacks, CBNetworkCommunicatorCallbacks commCallbacks, CBOnMessageReceivedAction (*onMessageReceived)(CBNode *, CBPeer *, CBMessage *)){ self->flags = flags; self->database = database; self->callbacks = nodeCallbacks; self->onMessageReceived = onMessageReceived; // Initialise network communicator CBNetworkCommunicator * comm = CBGetNetworkCommunicator(self); commCallbacks.onMessageReceived = CBNodeOnMessageReceived; CBInitNetworkCommunicator(comm, CB_SERVICE_FULL_BLOCKS, commCallbacks); // Set network communicator fields. comm->flags = CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY | CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING; if (flags & CB_NODE_BOOTSTRAP) comm->flags |= CB_NETWORK_COMMUNICATOR_BOOTSTRAP; comm->version = CB_PONG_VERSION; comm->networkID = CB_PRODUCTION_NETWORK_BYTES; // ??? Add testnet support CBNetworkCommunicatorSetAlternativeMessages(comm, NULL, NULL); // Create address manager comm->addresses = CBNewNetworkAddressManager(CBNodeOnBadTime); comm->addresses->maxAddressesInBucket = 1000; comm->addresses->callbackHandler = self; // Initialise thread data self->shutDownThread = false; self->messageQueue = NULL; CBNewMutex(&self->blockAndTxMutex); CBNewMutex(&self->messageProcessMutex); CBNewCondition(&self->messageProcessWaitCond); CBNewThread(&self->messageProcessThread, CBNodeProcessMessages, self); // Initialise the storage objects if (CBNewBlockChainStorage(&self->blockChainStorage, database)) { if (CBNewAccounterStorage(&self->accounterStorage, database)){ if (CBNewNodeStorage(&self->nodeStorage, database)){ // Setup address storage if (CBNewAddressStorage(&comm->addrStorage, database)) { if (CBAddressStorageLoadAddresses(comm->addrStorage, comm->addresses)){ comm->useAddrStorage = true; return true; } }else CBLogError("Could not create the address storage object for a node"); CBFreeNodeStorage(self->nodeStorage); }else CBLogError("Could not create the node storage object for a node"); CBFreeAccounterStorage(self->accounterStorage); }else CBLogError("Could not create the accounter storage object for a node"); CBFreeBlockChainStorage(self->blockChainStorage); }else CBLogError("Could not create the block storage object for a node"); CBDestroyNetworkCommunicator(self); return false; }
int CBInventoryDeserialise(CBInventory * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBInventory with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 37) { CBLogError("Attempting to deserialise a CBInventory with less bytes than required for one item."); return CB_DESERIALISE_ERROR; } CBVarInt itemNum = CBByteArrayReadVarInt(bytes, 0); if (itemNum.val > 50000) { CBLogError("Attempting to deserialise a CBInventory with a var int over 50000."); return CB_DESERIALISE_ERROR; } self->itemNum = 0; self->itemFront = NULL; // Run through the items and deserialise each one. int cursor = itemNum.size; for (int x = 0; x < itemNum.val; x++) { // Make new CBInventoryItem from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); CBInventoryItem * item = CBNewInventoryItemFromData(data); // Deserialise int len = CBInventoryItemDeserialise(item); if (len == CB_DESERIALISE_ERROR){ CBLogError("CBInventory cannot be deserialised because of an error with the CBInventoryItem number %u.", x); CBReleaseObject(data); return CB_DESERIALISE_ERROR; } // Take item CBInventoryTakeInventoryItem(self, item); // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBInventoryItemDeserialise(CBInventoryItem * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to deserialise a CBInventoryItem with no bytes."); return 0; } if (bytes->length < 36) { CBLogError("Attempting to deserialise a CBInventoryItem with less than 36 bytes."); return 0; } self->type = CBByteArrayReadInt32(bytes, 0); self->hash = CBByteArraySubReference(bytes, 4, 32); if (NOT self->hash) return 0; return 36; }
void CBNodeOnValidatorError(void * vself){ CBNode * self = vself; CBMutexUnlock(CBGetNode(self)->blockAndTxMutex); CBLogError("There was a validation error."); self->callbacks.onFatalNodeError(self, CB_ERROR_VALIDATION); CBReleaseObject(self); }
bool CBInitHDKeyFromData(CBHDKey * key, uint8_t * data, CBHDKeyVersion versionBytes, CBHDKeyType type){ CBInitHDKey(key); // Set version bytes key->versionBytes = versionBytes; // Chain code memcpy(key->chainCode, data + 13, 32); if (type == CB_HD_KEY_TYPE_PRIVATE){ // Private memcpy(key->keyPair->privkey, data + 46, 32); // Calculate public key CBKeyGetPublicKey(CBHDKeyGetPrivateKey(key), CBHDKeyGetPublicKey(key)); }else // Assume public memcpy(CBHDKeyGetPublicKey(key), data + 45, 33); // Depth key->depth = data[4]; if (key->depth == 0) { // Master key->childID.priv = false; key->childID.childNumber = 0; for (uint8_t x = 5; x < 9; x++) if (data[x] != 0) { CBLogError("The fingerprint of the master key is not zero."); return false; } }else{ // Not master uint32_t childNum = CBArrayToInt32BigEndian(data, 9); key->childID.priv = childNum >> 31; key->childID.childNumber = childNum & 0x8fffffff; } return true; }
void CBNodeOnBadTime(void * vself){ CBNode * self = vself; CBMutexUnlock(CBGetNode(self)->blockAndTxMutex); CBLogError("The system time is potentially incorrect. It does not match with the network time."); self->callbacks.onFatalNodeError(self, CB_ERROR_BAD_TIME); CBReleaseObject(self); }
uint32_t CBBlockHeadersSerialise(CBBlockHeaders * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 81 * self->headerNum) { CBLogError("Attempting to deserialise a CBBlockHeaders with less bytes than minimally required."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->headerNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->blockHeaders[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as the block headers message, re-serialise the block header, in case it got overwritten. || CBGetMessage(self->blockHeaders[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->blockHeaders[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->blockHeaders[x])->bytes); CBGetMessage(self->blockHeaders[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBGetMessage(self->blockHeaders[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBBlockHeadersSerialise for the header number %u", x); return 0; } if (! CBBlockSerialise(self->blockHeaders[x], false, force)) { // false for no transactions. CBLogError("CBBlockHeaders cannot be serialised because of an error with the CBBlock number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->blockHeaders[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->blockHeaders[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->blockHeaders[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->blockHeaders[x])->bytes->length; } // Ensure length is correct bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
int CBBlockHeadersDeserialise(CBBlockHeaders * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBBlockHeaders with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 82) { CBLogError("Attempting to deserialise a CBBlockHeaders with less bytes than required for one header."); return CB_DESERIALISE_ERROR; } CBVarInt headerNum = CBByteArrayReadVarInt(bytes, 0); if (headerNum.val > 2000) { CBLogError("Attempting to deserialise a CBBlockHeaders with a var int over 2000."); return CB_DESERIALISE_ERROR; } // Deserialise each header self->headerNum = headerNum.val; int cursor = headerNum.size; for (int x = 0; x < headerNum.val; x++) { // Make new CBBlock from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); self->blockHeaders[x] = CBNewBlockFromData(data); // Deserialise int len = CBBlockDeserialise(self->blockHeaders[x], false); // false for no transactions. Only the header. if (len == CB_DESERIALISE_ERROR){ CBLogError("CBBlockHeaders cannot be deserialised because of an error with the CBBlock number %" PRIu16 ".", x); CBReleaseObject(data); return CB_DESERIALISE_ERROR; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
int CBPingPongDeserialise(CBPingPong * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBPingPong with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 8) { CBLogError("Attempting to deserialise a CBPingPong with less than 8 bytes."); return CB_DESERIALISE_ERROR; } self->ID = CBByteArrayReadInt64(bytes, 0); return 8; }
uint32_t CBInventoryItemSerialise(CBInventoryItem * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBInventoryItem with no bytes."); return 0; } if (bytes->length < 36) { CBLogError("Attempting to serialise a CBInventoryItem with less than 36 bytes."); return 0; } CBByteArraySetInt32(bytes, 0, self->type); CBByteArrayCopyByteArray(bytes, 4, self->hash); CBByteArrayChangeReference(self->hash, bytes, 4); bytes->length = 36; CBGetMessage(self)->serialised = true; return 36; }
bool CBBlockChainStorageLoadBranchWork(void * validator, uint8_t branchNum){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // Get work CB_WORK_KEY[2] = branchNum; uint8_t workLen = CBDatabaseGetLength(database, CB_WORK_KEY); if (NOT CBBigIntAlloc(&validatorObj->branches[branchNum].work, workLen)){ CBLogError("There was an error when allocating memory for a branch's work."); return false; } validatorObj->branches[branchNum].work.length = workLen; if (NOT CBDatabaseReadValue(database, CB_WORK_KEY, validatorObj->branches[branchNum].work.data, workLen, 0)) { CBLogError("There was an error when reading the work for a branch."); free(validatorObj->branches[branchNum].work.data); return false; } return true; }
uint32_t CBNetworkAddressListSerialise(CBNetworkAddressList * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBNetworkAddress with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->addrNum); if (bytes->length < (26 + self->timeStamps * 4) * self->addrNum + num.size) { CBLogError("Attempting to serialise a CBNetworkAddress without enough bytes."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->addresses[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this address broadcast, re-serialise the address, in case it got overwritten. || CBGetMessage(self->addresses[x])->bytes->sharedData == bytes->sharedData || (CBGetMessage(self->addresses[x])->bytes->length != 26) ^ self->timeStamps) { if (CBGetMessage(self->addresses[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->addresses[x])->bytes); CBGetMessage(self->addresses[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBNetworkAddressSerialise(self->addresses[x], self->timeStamps)) { CBLogError("CBNetworkAddress cannot be serialised because of an error with the CBNetworkAddress number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->addresses[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->addresses[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->addresses[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->addresses[x])->bytes->length; } // Change bytes length bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
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; }
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 CBKeyPairGenerate(CBKeyPair * keyPair){ // Generate private key from a CSPRNG. if (!CBGet32RandomBytes(keyPair->privkey)) { CBLogError("Could not generate private key from 32 random bytes"); return false; } // Get public key CBKeyGetPublicKey(keyPair->privkey, keyPair->pubkey.key); 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; }
CBHDKey * CBNewHDKeyFromData(uint8_t * data){ CBHDKeyVersion versionBytes = CBArrayToInt32BigEndian(data, 0); CBHDKeyType type = CBHDKeyGetType(versionBytes); if (type == CB_HD_KEY_TYPE_UNKNOWN) { CBLogError("Unknown key type."); return NULL; } // Allocate memory for key CBHDKey * key = CBNewHDKey(type == CB_HD_KEY_TYPE_PRIVATE); return CBInitHDKeyFromData(key, data, versionBytes, type) ? key : NULL; }