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); }
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); }
CBPeer * CBNewNodeByTakingNetworkAddress(CBNetworkAddress * addr){ CBPeer * self = CBGetNode(addr); self = realloc(self, sizeof(*self)); if (NOT self) { CBLogError("Cannot reallocate to %i bytes of memory in CBNewNodeByTakingNetworkAddress\n", sizeof(*self)); return NULL; } CBGetObject(self)->free = CBFreeNode; if(CBInitNodeByTakingNetworkAddress(self)) return self; free(self); return NULL; }
CBOnMessageReceivedAction CBNodeOnMessageReceived(CBNetworkCommunicator * comm, CBPeer * peer, CBMessage * message){ CBNode * self = CBGetNode(comm); // Add message to queue CBRetainObject(message); CBRetainObject(peer); CBMutexLock(self->messageProcessMutex); if (self->messageQueue == NULL) self->messageQueue = self->messageQueueBack = malloc(sizeof(*self->messageQueueBack)); else{ self->messageQueueBack->next = malloc(sizeof(*self->messageQueueBack)); self->messageQueueBack = self->messageQueueBack->next; } self->messageQueueBack->peer = peer; self->messageQueueBack->message = message; self->messageQueueBack->next = NULL; // Wakeup thread if this is the first in the queue if (self->messageQueue == self->messageQueueBack) // We have just added a block to the queue when there was not one before so wake-up the processing thread. CBConditionSignal(self->messageProcessWaitCond); CBMutexUnlock(self->messageProcessMutex); return CB_MESSAGE_ACTION_CONTINUE; }
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; }