bool CBInventoryAddInventoryItem(CBInventory * self, CBInventoryItem * item) { bool taken = CBInventoryTakeInventoryItem(self, item); if (taken) CBRetainObject(item); return taken; }
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; }
CBOnMessageReceivedAction CBNodeSendBlocksInvOrHeaders(CBNode * self, CBPeer * peer, CBGetBlocks * getBlocks, bool full){ CBChainDescriptor * chainDesc = getBlocks->chainDescriptor; if (chainDesc->hashNum == 0) // Why do this? return CB_MESSAGE_ACTION_DISCONNECT; uint8_t branch; uint32_t blockIndex; // Go though the chain descriptor until a hash is found that we own bool found = false; // Lock block mutex for block chain access CBMutexLock(self->blockAndTxMutex); for (uint16_t x = 0; x < chainDesc->hashNum; x++) { CBErrBool exists = CBBlockChainStorageGetBlockLocation(CBGetNode(self)->validator, CBByteArrayGetData(chainDesc->hashes[x]), &branch, &blockIndex); if (exists == CB_ERROR) { CBMutexUnlock(self->blockAndTxMutex); return CBNodeReturnError(self, "Could not look for block with chain descriptor hash."); } if (exists == CB_TRUE) { // We have a block that we own. found = true; break; } } // Get the chain path for the main chain CBChainPath mainChainPath = CBValidatorGetMainChainPath(self->validator); CBChainPathPoint intersection; if (found){ // Get the chain path for the block header we have found CBChainPath peerChainPath = CBValidatorGetChainPath(self->validator, branch, blockIndex); // Determine where the intersection is on the main chain intersection = CBValidatorGetChainIntersection(&mainChainPath, &peerChainPath); }else{ // Bad chain? CBMutexUnlock(self->blockAndTxMutex); return CB_MESSAGE_ACTION_DISCONNECT; } CBMessage * message; // Now provide headers from this intersection up to 2000 blocks or block inventory items up to 500, the last one we have or the stopAtHash. for (uint16_t x = 0; x < (full ? 500 : 2000); x++) { // Check to see if we reached the last block in the main chain. if (intersection.chainPathIndex == 0 && intersection.blockIndex == mainChainPath.points[0].blockIndex) { if (x == 0){ // The intersection is at the last block. The peer is up-to-date with us peer->upload = false; peer->upToDate = true; CBMutexUnlock(self->blockAndTxMutex); return CB_MESSAGE_ACTION_CONTINUE; } break; } // Move to the next block if (intersection.blockIndex == mainChainPath.points[intersection.chainPathIndex].blockIndex) { // Move to next branch intersection.chainPathIndex--; intersection.blockIndex = 0; }else // Move to the next block intersection.blockIndex++; // Get the hash uint8_t hash[32]; if (! CBBlockChainStorageGetBlockHash(self->validator, mainChainPath.points[intersection.chainPathIndex].branch, intersection.blockIndex, hash)) { if (x != 0) CBReleaseObject(message); CBMutexUnlock(self->blockAndTxMutex); return CBNodeReturnError(self, "Could not obtain a hash for a block."); } // Check to see if we are at stopAtHash if (getBlocks->stopAtHash && memcmp(hash, CBByteArrayGetData(getBlocks->stopAtHash), 32) == 0){ if (x == 0) { CBMutexUnlock(self->blockAndTxMutex); return CB_MESSAGE_ACTION_CONTINUE; } break; } if (x == 0){ // Create inventory or block headers object to send to peer. if (full) { message = CBGetMessage(CBNewInventory()); message->type = CB_MESSAGE_TYPE_INV; }else{ message = CBGetMessage(CBNewBlockHeaders()); message->type = CB_MESSAGE_TYPE_HEADERS; } } // Add block header or add inventory item if (full) { CBByteArray * hashObj = CBNewByteArrayWithDataCopy(hash, 32); char blkStr[CB_BLOCK_HASH_STR_SIZE]; CBByteArrayToString(hashObj, 0, CB_BLOCK_HASH_STR_BYTES, blkStr, true); CBInventoryTakeInventoryItem(CBGetInventory(message), CBNewInventoryItem(CB_INVENTORY_ITEM_BLOCK, hashObj)); CBReleaseObject(hashObj); }else CBBlockHeadersTakeBlockHeader(CBGetBlockHeaders(message), CBBlockChainStorageGetBlockHeader(self->validator, mainChainPath.points[intersection.chainPathIndex].branch, intersection.blockIndex)); } CBMutexUnlock(self->blockAndTxMutex); // Send the message CBNodeSendMessageOnNetworkThread(CBGetNetworkCommunicator(self), peer, message, NULL); CBReleaseObject(message); // We are uploading to the peer peer->upload = true; return CB_MESSAGE_ACTION_CONTINUE; }