int main(){ unsigned int s = (unsigned int)time(NULL); printf("Session = %ui\n", s); srand(s); // Test string char * string = "Hello World!"; CBByteArray * ba = CBNewByteArrayWithDataCopy((uint8_t *)string, (uint32_t)strlen(string) + 1); if (strcmp(string, (char *)CBByteArrayGetData(ba))) { printf("STRING COPY FAIL\n"); return 1; } return 0; }
void BRSendPing(BRConnection *c) { printf("Sending ping\n"); CBMessage *m = CBNewMessageByObject(); uint64_t nonce = rand(); CBByteArray *ba = CBNewByteArrayWithDataCopy((uint8_t *) &nonce, 8); CBInitMessageByData(m, ba); BRSendMessage(c, m, "ping"); CBReleaseObject(ba); CBFreeMessage(m); }
int main (void) { // use the default event loop unless you have special needs struct ev_loop *loop = ev_default_loop (0); printf("Type help for a list of commands\n"); CBByteArray *ip = CBNewByteArrayWithDataCopy((uint8_t [16]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 128, 8, 126, 25}, 16); CBNetworkAddress *peeraddr = CBNewNetworkAddress(0, ip, DEFAULT_PORT, CB_SERVICE_FULL_BLOCKS, false); peer = CBNewPeerByTakingNetworkAddress(peeraddr); // Create client socket if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); return -1; } memset(&addr, sizeof(addr), 0); addr.sin_family = AF_INET; addr.sin_port = htons(DEFAULT_PORT); addr.sin_addr.s_addr = (((((25 << 8) | 126) << 8) | 8) << 8) | 128; // Connect to server socket if(connect(sd, (struct sockaddr *)&addr, sizeof addr) < 0) { perror("Connect error"); return -1; } printf("Connected to %s:%d\n", DEFAULT_IP, DEFAULT_PORT); // initialise an io watcher, then start it // this one will watch for stdin to become readable ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ); ev_io_start (loop, &stdin_watcher); // io watcher for the socket ev_io_init (&sock_watcher, sockread_cb, sd, EV_READ); ev_io_start (loop, &sock_watcher); // initialise a timer watcher, then start it ev_timer_init (&timeout_watcher, timeout_cb, 2.0, 0.); ev_timer_start (loop, &timeout_watcher); // now wait for events to arrive ev_loop (loop, 0); // unloop was called, so exit return 0; }
bool CBInitBlockGenesis(CBBlock * self){ CBByteArray * data = CBNewByteArrayWithDataCopy((uint8_t [285]){0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xA3, 0xED, 0xFD, 0x7A, 0x7B, 0x12, 0xB2, 0x7A, 0xC7, 0x2C, 0x3E, 0x67, 0x76, 0x8F, 0x61, 0x7F, 0xC8, 0x1B, 0xC3, 0x88, 0x8A, 0x51, 0x32, 0x3A, 0x9F, 0xB8, 0xAA, 0x4B, 0x1E, 0x5E, 0x4A, 0x29, 0xAB, 0x5F, 0x49, 0xFF, 0xFF, 0x00, 0x1D, 0x1D, 0xAC, 0x2B, 0x7C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4D, 0x04, 0xFF, 0xFF, 0x00, 0x1D, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6D, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2F, 0x4A, 0x61, 0x6E, 0x2F, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x6C, 0x6F, 0x72, 0x20, 0x6F, 0x6E, 0x20, 0x62, 0x72, 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6C, 0x6F, 0x75, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x62, 0x61, 0x6E, 0x6B, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, 0x67, 0x8A, 0xFD, 0xB0, 0xFE, 0x55, 0x48, 0x27, 0x19, 0x67, 0xF1, 0xA6, 0x71, 0x30, 0xB7, 0x10, 0x5C, 0xD6, 0xA8, 0x28, 0xE0, 0x39, 0x09, 0xA6, 0x79, 0x62, 0xE0, 0xEA, 0x1F, 0x61, 0xDE, 0xB6, 0x49, 0xF6, 0xBC, 0x3F, 0x4C, 0xEF, 0x38, 0xC4, 0xF3, 0x55, 0x04, 0xE5, 0x1E, 0xC1, 0x12, 0xDE, 0x5C, 0x38, 0x4D, 0xF7, 0xBA, 0x0B, 0x8D, 0x57, 0x8A, 0x4C, 0x70, 0x2B, 0x6B, 0xF1, 0x1D, 0x5F, 0xAC, 0x00, 0x00, 0x00, 0x00}, 285); if (NOT data) return false; uint8_t genesisHash[32] = {0x6F, 0xE2, 0x8C, 0x0A, 0xB6, 0xF1, 0xB3, 0x72, 0xC1, 0xA6, 0xA2, 0x46, 0xAE, 0x63, 0xF7, 0x4F, 0x93, 0x1E, 0x83, 0x65, 0xE1, 0x5A, 0x08, 0x9C, 0x68, 0xD6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(self->hash, genesisHash, 32); self->hashSet = true; if (NOT CBInitMessageByData(CBGetMessage(self), data)){ CBReleaseObject(data); CBReleaseObject(self->hash); return false; } CBReleaseObject(data); CBBlockDeserialise(self, true); return true; }
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; }
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); }
void BRSendGetBlocks(BRConnection *c) { BRConnector *connector = (BRConnector *) c->connector; CBChainDescriptor *chain = BRKnownBlocks(connector->block_chain); /* 0 to get as many blocks as possible (500) */ uint8_t zero[32] = {0}; CBByteArray *stop = CBNewByteArrayWithDataCopy(zero, 32); CBGetBlocks *get_blocks = CBNewGetBlocks(VERSION_NUM, chain, stop); uint32_t length = CBGetBlocksCalculateLength(get_blocks); get_blocks->base.bytes = CBNewByteArrayOfSize(length); CBGetBlocksSerialise(get_blocks, false); BRSendMessage(c, &get_blocks->base, "getblocks"); CBReleaseObject(stop); CBReleaseObject(chain); CBFreeGetBlocks(get_blocks); /* update with sent getblocks */ c->getblocks_sent = 1; }
int main(){ unsigned int s = (unsigned int)time(NULL); s = 1337544566; printf("Session = %ui\n",s); srand(s); // Test deserialisation of real alert uint8_t data[188] = { 0x73, // Length of payload 0x01,0x00,0x00,0x00, // Version 1 0x37,0x66,0x40,0x4F,0x00,0x00,0x00,0x00, // Relay until 1329620535 0xB3,0x05,0x43,0x4F,0x00,0x00,0x00,0x00, // Expires at 1329792435 0xF2,0x03,0x00,0x00, // ID 1010 0xF1,0x03,0x00,0x00, // Cancel < 1009 0x00, // No more IDs 0x10,0x27,0x00,0x00, // Min version 10000 0x48,0xee,0x00,0x00, // Max version 61000 0x00, // No user agents 0x64,0x00,0x00,0x00, // Priority 100 0x00, // Empty hidden comment 0x46, // Displayed comment is 70 characters long // "See bitcoin.org/feb20 if you have trouble connecting after 20 February" 0x53,0x65,0x65,0x20,0x62,0x69,0x74,0x63,0x6F,0x69,0x6E,0x2E,0x6F,0x72,0x67,0x2F,0x66,0x65,0x62,0x32,0x30,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x68,0x61,0x76,0x65,0x20,0x74,0x72,0x6F,0x75,0x62,0x6C,0x65,0x20,0x63,0x6F,0x6E,0x6E,0x65,0x63,0x74,0x69,0x6E,0x67,0x20,0x61,0x66,0x74,0x65,0x72,0x20,0x32,0x30,0x20,0x46,0x65,0x62,0x72,0x75,0x61,0x72,0x79, 0x00, // No reserved // Signature 0x47, // Signature is 71 bytes long 0x30,0x45,0x02,0x21,0x00,0x83,0x89,0xdf,0x45,0xF0,0x70,0x3F,0x39,0xEC,0x8C,0x1C,0xC4,0x2C,0x13,0x81,0x0F,0xFC,0xAE,0x14,0x99,0x5B,0xB6,0x48,0x34,0x02,0x19,0xE3,0x53,0xB6,0x3B,0x53,0xEB,0x02,0x20,0x09,0xEC,0x65,0xE1,0xC1,0xAA,0xEE,0xC1,0xFD,0x33,0x4C,0x6B,0x68,0x4B,0xDE,0x2B,0x3F,0x57,0x30,0x60,0xD5,0xb7,0x0C,0x3A,0x46,0x72,0x33,0x26,0xE4,0xE8,0xA4,0xF1 }; CBByteArray * bytes = CBNewByteArrayWithDataCopy(data, 188, logError); CBAlert * alert = CBNewAlertFromData(bytes, logError); if(CBAlertDeserialise(alert) != 188){ printf("DESERIALISATION LEN FAIL\n"); return 1; } if (alert->version != 1) { printf("DESERIALISATION VERSION FAIL\n"); return 1; } if (alert->relayUntil != 1329620535) { printf("DESERIALISATION RELAY UNTIL FAIL\n"); return 1; } if (alert->expiration != 1329792435) { printf("DESERIALISATION EXPIRATION FAIL\n"); return 1; } if (alert->ID != 1010) { printf("DESERIALISATION ID FAIL\n"); return 1; } if (alert->cancel != 1009) { printf("DESERIALISATION CANCEL FAIL\n"); return 1; } if (alert->setCancelNum != 0) { printf("DESERIALISATION SET CANCEL NUM FAIL\n"); return 1; } if (alert->setCancel != NULL) { printf("DESERIALISATION SET CANCEL FAIL\n"); return 1; } if (alert->minVer != 10000) { printf("DESERIALISATION MIN VERSION FAIL\n"); return 1; } if (alert->maxVer != 61000) { printf("DESERIALISATION MAX VERSION FAIL\n"); return 1; } if (alert->userAgentNum != 0) { printf("DESERIALISATION USER AGENT NUM FAIL\n"); return 1; } if (alert->userAgents != NULL) { printf("DESERIALISATION USER AGENTS FAIL\n"); return 1; } if (alert->priority != 100) { printf("DESERIALISATION PRIORITY FAIL\n"); return 1; } if (alert->hiddenComment != NULL) { printf("DESERIALISATION HIDDEN COMMENT FAIL\n"); return 1; } if (memcmp(CBByteArrayGetData(alert->displayedComment),"See bitcoin.org/feb20 if you have trouble connecting after 20 February",70)) { printf("DESERIALISATION DISPLAYED COMMENT FAIL\n0x"); char * d = (char *)CBByteArrayGetData(alert->displayedComment); for (int x = 0; x < 70; x++) { printf("%c",d[x]); } printf("\n!=\nSee bitcoin.org/feb20 if you have trouble connecting after 20 February\n"); return 1; } if (alert->reserved != NULL) { printf("DESERIALISATION RESERVED FAIL\n"); return 1; } // Check signature CBByteArray * payload = CBAlertGetPayload(alert); uint8_t hash1[32]; CBSha256(CBByteArrayGetData(payload),payload->length,hash1); uint8_t hash2[32]; CBSha256(hash1, 32,hash2); if (NOT CBEcdsaVerify(CBByteArrayGetData(alert->signature),alert->signature->length,hash2,(uint8_t [65]){0x04,0xFC,0x97,0x02,0x84,0x78,0x40,0xAA,0xF1,0x95,0xDE,0x84,0x42,0xEB,0xEC,0xED,0xF5,0xB0,0x95,0xCD,0xBB,0x9B,0xC7,0x16,0xBD,0xA9,0x11,0x09,0x71,0xB2,0x8A,0x49,0xE0,0xEA,0xD8,0x56,0x4F,0xF0,0xDB,0x22,0x20,0x9E,0x03,0x74,0x78,0x2C,0x09,0x3B,0xB8,0x99,0x69,0x2D,0x52,0x4E,0x9D,0x6A,0x69,0x56,0xE7,0xC5,0xEC,0xBC,0xD6,0x82,0x84},65)) { printf("DESERIALISATION SIG FAIL\n"); return 1; } CBReleaseObject(payload); // Test serialisation memset(CBByteArrayGetData(bytes), 0, 188); CBReleaseObject(alert->displayedComment); alert->displayedComment = CBNewByteArrayWithDataCopy((uint8_t *)"See bitcoin.org/feb20 if you have trouble connecting after 20 February", 70, logError); CBReleaseObject(alert->signature); alert->signature = CBNewByteArrayWithDataCopy((uint8_t []){0x30,0x45,0x02,0x21,0x00,0x83,0x89,0xdf,0x45,0xF0,0x70,0x3F,0x39,0xEC,0x8C,0x1C,0xC4,0x2C,0x13,0x81,0x0F,0xFC,0xAE,0x14,0x99,0x5B,0xB6,0x48,0x34,0x02,0x19,0xE3,0x53,0xB6,0x3B,0x53,0xEB,0x02,0x20,0x09,0xEC,0x65,0xE1,0xC1,0xAA,0xEE,0xC1,0xFD,0x33,0x4C,0x6B,0x68,0x4B,0xDE,0x2B,0x3F,0x57,0x30,0x60,0xD5,0xb7,0x0C,0x3A,0x46,0x72,0x33,0x26,0xE4,0xE8,0xA4,0xF1}, 71, logError); CBAlertSerialisePayload(alert); if(CBAlertSerialiseSignature(alert, 116) != 188){ printf("SERIALISATION LEN FAIL\n"); return 1; } if (memcmp(data, CBByteArrayGetData(bytes), 188)) { printf("SERIALISATION FAIL\n0x"); uint8_t * d = CBByteArrayGetData(bytes); for (int x = 0; x < 188; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); for (int x = 0; x < 188; x++) { printf("%.2X",data[x]); } return 1; } CBReleaseObject(alert); CBReleaseObject(bytes); return 0; }
int main(){ unsigned int s = (unsigned int)time(NULL); s = 1337544566; printf("Session = %ui\n",s); srand(s); // Test genesis block CBByteArray * genesisMerkleRoot = CBNewByteArrayWithDataCopy((uint8_t []){0x3B,0xA3,0xED,0xFD,0x7A,0x7B,0x12,0xB2,0x7A,0xC7,0x2C,0x3E,0x67,0x76,0x8F,0x61,0x7F,0xC8,0x1B,0xC3,0x88,0x8A,0x51,0x32,0x3A,0x9F,0xB8,0xAA,0x4B,0x1E,0x5E,0x4A}, 32, onErrorReceived); CBByteArray * genesisInScript = CBNewByteArrayWithDataCopy((uint8_t [77]){0x04,0xFF,0xFF,0x00,0x1D,0x01,0x04,0x45,0x54,0x68,0x65,0x20,0x54,0x69,0x6D,0x65,0x73,0x20,0x30,0x33,0x2F,0x4A,0x61,0x6E,0x2F,0x32,0x30,0x30,0x39,0x20,0x43,0x68,0x61,0x6E,0x63,0x65,0x6C,0x6C,0x6F,0x72,0x20,0x6F,0x6E,0x20,0x62,0x72,0x69,0x6E,0x6B,0x20,0x6F,0x66,0x20,0x73,0x65,0x63,0x6F,0x6E,0x64,0x20,0x62,0x61,0x69,0x6C,0x6F,0x75,0x74,0x20,0x66,0x6F,0x72,0x20,0x62,0x61,0x6E,0x6B,0x73}, 77, onErrorReceived); CBByteArray * genesisOutScript = CBNewByteArrayWithDataCopy((uint8_t [67]){0x41,0x04,0x67,0x8A,0xFD,0xB0,0xFE,0x55,0x48,0x27,0x19,0x67,0xF1,0xA6,0x71,0x30,0xB7,0x10,0x5C,0xD6,0xA8,0x28,0xE0,0x39,0x09,0xA6,0x79,0x62,0xE0,0xEA,0x1F,0x61,0xDE,0xB6,0x49,0xF6,0xBC,0x3F,0x4C,0xEF,0x38,0xC4,0xF3,0x55,0x04,0xE5,0x1E,0xC1,0x12,0xDE,0x5C,0x38,0x4D,0xF7,0xBA,0x0B,0x8D,0x57,0x8A,0x4C,0x70,0x2B,0x6B,0xF1,0x1D,0x5F,0xAC}, 67, onErrorReceived); // Test hash CBBlock * genesisBlock = CBNewBlockGenesis(onErrorReceived); uint8_t calcHash[32]; CBBlockCalculateHash(genesisBlock,calcHash); if(memcmp(genesisBlock->hash, calcHash,32)){ printf("GENESIS BLOCK HASH FAIL\n0x"); uint8_t * d = genesisBlock->hash; for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = calcHash; for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } return 1; } // Test deserialised data if (genesisBlock->version != 1) { printf("GENESIS BLOCK VERSION FAIL\n"); return 1; } for (int x = 0; x < 32; x++) { if(CBByteArrayGetByte(genesisBlock->prevBlockHash, x) != 0){ printf("GENESIS BLOCK PREV FAIL\n"); return 1; } } if (CBByteArrayCompare(genesisBlock->merkleRoot, genesisMerkleRoot)) { printf("GENESIS BLOCK MERKLE ROOT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisBlock->merkleRoot); for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisMerkleRoot); for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } return 1; } if (genesisBlock->time != 1231006505) { printf("GENESIS BLOCK TIME FAIL\n0x"); return 1; } if (genesisBlock->target != 0x1D00FFFF) { printf("GENESIS BLOCK DIFFICULTY FAIL\n0x"); return 1; } if (genesisBlock->nonce != 2083236893) { printf("GENESIS BLOCK DIFFICULTY FAIL\n0x"); return 1; } if (genesisBlock->transactionNum != 1) { printf("GENESIS BLOCK TRANSACTION NUM FAIL\n0x"); return 1; } CBTransaction * genesisCoinBase = genesisBlock->transactions[0]; if (genesisCoinBase->inputNum != 1) { printf("GENESIS BLOCK TRANSACTION INPUT NUM FAIL\n0x"); return 1; } if (genesisCoinBase->outputNum != 1) { printf("GENESIS BLOCK TRANSACTION OUTPUT NUM FAIL\n0x"); return 1; } if (genesisCoinBase->version != 1) { printf("GENESIS BLOCK TRANSACTION VERSION FAIL\n0x"); return 1; } if (genesisCoinBase->lockTime != 0) { printf("GENESIS BLOCK TRANSACTION LOCK TIME FAIL\n0x"); return 1; } if (genesisCoinBase->inputs[0]->scriptObject->length != 0x4D) { printf("GENESIS BLOCK TRANSACTION INPUT SCRIPT LENGTH FAIL\n0x"); return 1; } if (genesisCoinBase->outputs[0]->scriptObject->length != 0x43) { printf("GENESIS BLOCK TRANSACTION OUTPUT SCRIPT LENGTH FAIL\n0x"); return 1; } for (int x = 0; x < 32; x++) { if(CBByteArrayGetByte(genesisCoinBase->inputs[0]->prevOut.hash, x) != 0){ printf("GENESIS BLOCK TRANSACTION INPUT OUT POINTER HASH FAIL\n"); return 1; } } if (genesisCoinBase->inputs[0]->prevOut.index != 0xFFFFFFFF) { printf("GENESIS BLOCK TRANSACTION INPUT OUT POINTER INDEX FAIL\n0x"); return 1; } if (genesisCoinBase->inputs[0]->sequence != CB_TRANSACTION_INPUT_FINAL) { printf("GENESIS BLOCK TRANSACTION INPUT SEQUENCE FAIL\n0x"); return 1; } if (CBByteArrayCompare(genesisCoinBase->inputs[0]->scriptObject, genesisInScript)) { printf("GENESIS BLOCK IN SCRIPT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisCoinBase->inputs[0]->scriptObject); for (int x = 0; x < genesisCoinBase->inputs[0]->scriptObject->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisInScript); for (int x = 0; x < genesisInScript->length; x++) { printf("%.2X",d[x]); } return 1; } if (genesisCoinBase->outputs[0]->value != 5000000000) { printf("GENESIS BLOCK TRANSACTION OUTPUT VALUE FAIL\n0x"); return 1; } if (CBByteArrayCompare(genesisCoinBase->outputs[0]->scriptObject, genesisOutScript)) { printf("GENESIS BLOCK OUT SCRIPT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisCoinBase->outputs[0]->scriptObject); for (int x = 0; x < genesisCoinBase->outputs[0]->scriptObject->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisOutScript); for (int x = 0; x < genesisOutScript->length; x++) { printf("%.2X",d[x]); } return 1; } // Test serialisation into genesis block CBBlock * block = CBNewBlock(onErrorReceived); block->version = 1; uint8_t * zeroHash = malloc(32); memset(zeroHash, 0, 32); block->prevBlockHash = CBNewByteArrayWithData(zeroHash, 32, onErrorReceived); block->merkleRoot = genesisMerkleRoot; block->target = 0x1D00FFFF; block->time = 1231006505; block->nonce = 2083236893; block->transactionNum = 1; block->transactions = malloc(sizeof(*block->transactions)); block->transactions[0] = CBNewTransaction(0, 1, onErrorReceived); CBRetainObject(block->prevBlockHash); // Retain for the zero hash in the input CBTransactionTakeInput(block->transactions[0], CBNewTransactionInput(genesisInScript, CB_TRANSACTION_INPUT_FINAL, block->prevBlockHash, 0xFFFFFFFF, onErrorReceived)); CBTransactionTakeOutput(block->transactions[0], CBNewTransactionOutput(5000000000, genesisOutScript, onErrorReceived)); CBGetMessage(block)->bytes = CBNewByteArrayOfSize(CBGetMessage(genesisBlock)->bytes->length, onErrorReceived); CBBlockSerialise(block, true, true); if (CBByteArrayCompare(CBGetMessage(block)->bytes, CBGetMessage(genesisBlock)->bytes)) { printf("SERIALISATION TO GENESIS BLOCK FAIL\n0x"); uint8_t * d = CBByteArrayGetData(CBGetMessage(block)->bytes); for (int x = 0; x < CBGetMessage(block)->bytes->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(CBGetMessage(genesisBlock)->bytes); for (int x = 0; x < CBGetMessage(genesisBlock)->bytes->length; x++) { printf("%.2X",d[x]); } return 1; } CBReleaseObject(genesisBlock); // ??? Add tests for non-genesis blocks return 0; }
/* socket_fd < 0 implies we need to use non-blocking connect * socket_fd >= 0 implies socket already bound to connection */ BRConnection *BRNewConnection(char *ip, uint16_t port, CBNetworkAddress *my_address, void *connector, int socket_fd) { int rtn; struct sockaddr_in remote; BRConnection *c = calloc(1, sizeof(BRConnection)); if (c == NULL) { perror("calloc failed"); exit(1); } if (socket_fd >= 0) { c->sock = socket_fd; c->flags = fcntl(c->sock, F_GETFL); } else { c->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (c->sock < 0) { perror("socket failed"); exit(1); } /* set to non-blocking, saving flags */ c->flags = fcntl(c->sock, F_GETFL); if (fcntl(c->sock, F_SETFL, c->flags | O_NONBLOCK) == -1) { perror("fcntl failed"); exit(1); } memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; rtn = inet_pton(AF_INET, ip, &remote.sin_addr.s_addr); if (rtn == 0) fprintf(stderr, "Address %s not valid\n", ip); else if (rtn < 0) { perror("inet_pton failed"); exit(1); } remote.sin_port = htons(port); if (connect(c->sock, (struct sockaddr *) &remote, sizeof(remote)) < 0) { if (errno == EINPROGRESS) { #ifdef BRDEBUG printf("Connection to %s:%d on socket %d in progress\n", ip, port, c->sock); #endif } else { perror("connect failed"); exit(1); } } } if (ip != NULL) { uint64_t last_seen = time(NULL); /* use IPv4 mapped IPv6 addresses as in https://en.bitcoin.it/wiki/Protocol_Specification#Network_address */ struct in_addr addr; inet_aton(ip, &addr); uint8_t *octets = (uint8_t *) &addr.s_addr; uint8_t ipmap[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, octets[0], octets[1], octets[2], octets[3]}; CBByteArray *ip_arr = CBNewByteArrayWithDataCopy(ipmap, 16); CBVersionServices services = CB_SERVICE_FULL_BLOCKS; bool is_public = true; printf("port: %d\n", port); c->address = CBNewNetworkAddress(last_seen, ip_arr, port, services, is_public); c->my_address = my_address; /* decrement reference counter */ CBReleaseObject(ip_arr); /* copy ip and port */ c->port = port; c->ip = calloc(1, strlen(ip) + 1); if (c->ip == NULL) { perror("calloc failed"); exit(1); } strcpy(c->ip, ip); } c->ver_acked = c->ver_received = 0; c->addr_sent = c->getblocks_sent = 0; c->connector = connector; /* In reality is a (BRConnector *) */ return c; }
void BRPeerCallback(void *arg) { /* adapted from pingpong.c example */ BRConnection *c = (BRConnection *) arg; char header[24]; int bytes = recv(c->sock, header, 24, 0), n; if (bytes < 0) { perror("recv failed"); exit(1); } else if (bytes == 0) { fprintf(stderr, "Connection closed on socket %d\n", c->sock); BRCloseConnection(c); return; } else if (bytes != 24) { fprintf(stderr, "Read %d bytes, not 24\n", bytes); exit(1); } /* check magic */ uint32_t magic = *(uint32_t *)(header + CB_MESSAGE_HEADER_NETWORK_ID); if (magic != NETMAGIC) { fprintf(stderr, "Netmagic %u incorrect (isn't %u)\n", magic, NETMAGIC); exit(1); } /* read message */ uint32_t length = *(uint32_t *)(header + CB_MESSAGE_HEADER_LENGTH); char *message = malloc(length); if (message == NULL) { perror("malloc failed"); exit(1); } bytes = 0; while (bytes < length) { /* TODO don't read message all at once if not ready */ n = recv(c->sock, message + bytes, length - bytes, 0); if (n < 0) { perror("recv failed"); exit(1); } else if (n == 0) { fprintf(stderr, "Connection closed on socket %d\n", c->sock); BRCloseConnection(c); return; } bytes += n; } if (bytes != length) { fprintf(stderr, "Too many bytes read (%d, not %d)\n", bytes, length); exit(1); } /* Generate CBByteArray of message for use in certain protocol commands */ CBByteArray *ba = CBNewByteArrayWithDataCopy((uint8_t *) message, length); #ifdef BRDEBUG print_header(header); printf("message len: %d\n", length); print_hex(ba); #endif /* TODO verify checksum? */ if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "version\0\0\0\0\0", 12)) { printf("Received version header\n\n"); c->ver_received = 1; /* we received their version */ BRSendVerack(c); } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "verack\0\0\0\0\0\0", 12)) { printf("Received verack header\n\n"); c->ver_acked = 1; /* they've acknowledged our version */ BRSendGetAddr(c); } if (BRVersionExchanged(c)) { if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "ping\0\0\0\0\0\0\0\0", 12)) { printf("Received ping header\n\n"); BRSendPong(c, ba, length); } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "pong\0\0\0\0\0\0\0\0", 12)) { printf("Received pong header\n\n"); /* TODO verify nonce */ } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "inv\0\0\0\0\0\0\0\0\0", 12)) { printf("Received inv header\n\n"); BRHandleInv(c, ba); /* possibly sends a getdata message in response */ } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "addr\0\0\0\0\0\0\0\0", 12)) { printf("Received addr header\n\n"); BRHandleAddr(c, ba); } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "getaddr\0\0\0\0\0", 12)) { printf("Received getaddr header\n\n"); BRSendAddr(c); } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "tx\0\0\0\0\0\0\0\0\0\0", 12)) { printf("Received tx header\n\n"); /* TODO handle transaction */ } else if (!strncmp(header + CB_MESSAGE_HEADER_TYPE, "block\0\0\0\0\0\0\0", 12)) { printf("Received block header\n\n"); BRHandleBlock(c, ba); } if (!c->addr_sent) { BRSendAddr(c); } if (!c->getblocks_sent) { /* TODO should wait for blocks instead of spamming getblocks * after every inv received; maybe change it to * blocks_received instead of getblocks_sent */ BRSendGetBlocks(c); } } /* reference counter should be 0 now */ CBReleaseObject(ba); free(message); }
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; }