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; }
bool BEInitFullNode(BEFullNode * self,void (*onErrorReceived)(CBError error,char *,...)){ if (NOT CBInitNetworkCommunicator(CBGetNetworkCommunicator(self), onErrorReceived)) return false; // Set network communicator fields. CBGetNetworkCommunicator(self)->blockHeight = 0; CBGetNetworkCommunicator(self)->callbackHandler = self; CBGetNetworkCommunicator(self)->flags = CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY | CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING; CBGetNetworkCommunicator(self)->version = CB_PONG_VERSION; CBNetworkCommunicatorSetAlternativeMessages(CBGetNetworkCommunicator(self), NULL, NULL); // Find home directory. const char * homeDir; struct passwd * pwd = getpwuid(getuid()); if (NOT pwd) return false; homeDir = pwd->pw_dir; unsigned long homeLen = strlen(homeDir); // Open or create a new address store unsigned long dataDirLen = strlen(BE_DATA_DIRECTORY); char * addressFilePath = malloc(homeLen + dataDirLen + strlen(BE_ADDRESS_DATA_FILE) + 1); memcpy(addressFilePath, homeDir, homeLen); memcpy(addressFilePath + homeLen, BE_DATA_DIRECTORY, strlen(BE_DATA_DIRECTORY)); strcpy(addressFilePath + homeLen + dataDirLen, BE_ADDRESS_DATA_FILE); self->addressFile = fopen(addressFilePath, "rb+"); if (self->addressFile) { // The address store exists. free(addressFilePath); // Get the file length fseek(self->addressFile, 0, SEEK_END); unsigned long fileLen = ftell(self->addressFile); fseek(self->addressFile, 0, SEEK_SET); // Read file into a CBByteArray CBByteArray * buffer = CBNewByteArrayOfSize((uint32_t)fileLen, onErrorReceived); if (NOT buffer) { fclose(self->addressFile); return false; } if(fread(CBByteArrayGetData(buffer), fileLen, 1, self->addressFile) != fileLen){ CBReleaseObject(buffer); fclose(self->addressFile); return false; } // Create the CBAddressManager CBGetNetworkCommunicator(self)->addresses = CBNewAddressManagerFromData(buffer, onErrorReceived, BEFullNodeOnBadTime); CBReleaseObject(buffer); if (NOT CBAddressManagerDeserialise(CBGetNetworkCommunicator(self)->addresses)){ fclose(self->addressFile); CBReleaseObject(CBGetNetworkCommunicator(self)->addresses); onErrorReceived(CB_ERROR_INIT_FAIL,"There was an error when deserialising the CBAddressManager for the BEFullNode."); return false; } }else{ // The address store does not exist CBGetNetworkCommunicator(self)->addresses = CBNewAddressManager(onErrorReceived, BEFullNodeOnBadTime); if (NOT CBGetNetworkCommunicator(self)->addresses) return false; // Create the file self->addressFile = fopen(addressFilePath, "wb"); free(addressFilePath); if (NOT self->addressFile){ CBReleaseObject(CBGetNetworkCommunicator(self)->addresses); return false; } } // Create block validator return true; }
void BEFreeFullNode(void * self){ fclose(BEGetFullNode(self)->addressFile); CBReleaseObject(CBGetNetworkCommunicator(self)->addresses); CBFreeNetworkCommunicator(self); }
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; }
void CBNodeDisconnectPeer(CBPeer * peer){ CBRetainObject(peer); CBRunOnEventLoop(CBGetNetworkCommunicator(peer->nodeObj)->eventLoop, CBNodeDisconnectPeerRun, peer, false); }