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 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; }
bool CBInitNetworkAddress(CBNetworkAddress * self, uint64_t lastSeen, CBByteArray * ip, uint16_t port, CBVersionServices services, bool isPublic){ self->lastSeen = lastSeen; self->penalty = 0; self->ip = ip; self->isPublic = isPublic; if (NOT ip) { ip = CBNewByteArrayOfSize(16); if (NOT ip) return false; memset(CBByteArrayGetData(ip), 0, 16); self->type = CB_IP_INVALID; }else{ // Determine IP type self->type = CBGetIPType(CBByteArrayGetData(ip)); CBRetainObject(ip); } self->port = port; self->services = services; self->bucketSet = false; if (NOT CBInitMessageByObject(CBGetMessage(self))){ CBReleaseObject(ip); return false; } return true; }
void * CBBlockChainStorageLoadUnspentOutput(void * validator, uint8_t * txHash, uint32_t outputIndex, bool * coinbase, uint32_t * outputHeight){ CBFullValidator * validatorObj = validator; CBDatabase * database = (CBDatabase *)validatorObj->storage; // First read data for the unspent output key. memcpy(CB_UNSPENT_OUTPUT_KEY + 2, txHash, 32); CBInt32ToArray(CB_UNSPENT_OUTPUT_KEY, 34, outputIndex); if (NOT CBDatabaseReadValue(database, CB_UNSPENT_OUTPUT_KEY, CB_DATA_ARRAY, 8, 0)) { CBLogError("Cannot read unspent output information from the block chain database"); return NULL; } uint32_t outputPosition = CBArrayToInt32(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_POSITION); uint32_t outputLength = CBArrayToInt32(CB_DATA_ARRAY, CB_UNSPENT_OUTPUT_REF_LENGTH); // Now read data for the transaction memcpy(CB_TRANSACTION_INDEX_KEY + 2, txHash, 32); if (NOT CBDatabaseReadValue(database, CB_TRANSACTION_INDEX_KEY, CB_DATA_ARRAY, 14, 0)) { CBLogError("Cannot read a transaction reference from the transaction index."); return NULL; } uint8_t outputBranch = CB_DATA_ARRAY[CB_TRANSACTION_REF_BRANCH]; uint32_t outputBlockIndex = CBArrayToInt32(CB_DATA_ARRAY, CB_TRANSACTION_REF_BLOCK_INDEX); // Set coinbase *coinbase = CB_DATA_ARRAY[CB_TRANSACTION_REF_IS_COINBASE]; // Set output height *outputHeight = validatorObj->branches[outputBranch].startHeight + outputBlockIndex; // Get the output from storage CB_BLOCK_KEY[2] = outputBranch; CBInt32ToArray(CB_BLOCK_KEY, 3, outputBlockIndex); // Get output data CBByteArray * outputBytes = CBNewByteArrayOfSize(outputLength); if (NOT outputBytes) { CBLogError("Could not create CBByteArray for an unspent output."); return NULL; } if (NOT CBDatabaseReadValue(database, CB_BLOCK_KEY, CBByteArrayGetData(outputBytes), outputLength, CB_BLOCK_START + outputPosition)) { CBLogError("Could not read an unspent output"); CBReleaseObject(outputBytes); return NULL; } // Create output object CBTransactionOutput * output = CBNewTransactionOutputFromData(outputBytes); CBReleaseObject(outputBytes); if (NOT output) { CBLogError("Could not create an object for an unspent output"); return NULL; } if (NOT CBTransactionOutputDeserialise(output)) { CBLogError("Could not deserialise an unspent output"); return NULL; } return output; }
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 BRSendAddr(BRConnection *c) { BRConnector *connector = (BRConnector *) c->connector; CBAddressBroadcast *b = CBNewAddressBroadcast(true); int i; for (i = 0; i < connector->num_conns; ++i) CBAddressBroadcastAddNetworkAddress(b, connector->conns[i]->address); /* add mine too */ CBAddressBroadcastAddNetworkAddress(b, connector->my_address); uint32_t length = CBAddressBroadcastCalculateLength(b); b->base.bytes = CBNewByteArrayOfSize(length); CBAddressBroadcastSerialise(b, false); BRSendMessage(c, &b->base, "addr"); CBFreeAddressBroadcast(b); /* update addr sent */ c->addr_sent = 1; }
/* sends a getdata if needed */ void BRHandleInv(BRConnection *c, CBByteArray *message) { BRConnector *connector = (BRConnector *) c->connector; /* find blocks that are needed */ CBInventoryBroadcast *inv = CBNewInventoryBroadcastFromData(message); CBInventoryBroadcastDeserialise(inv); CBInventoryBroadcast *new_inv = BRUnknownBlocksFromInv(connector->block_chain, inv); if (new_inv->itemNum > 0) { uint32_t length = CBInventoryBroadcastCalculateLength(new_inv); new_inv->base.bytes = CBNewByteArrayOfSize(length); CBInventoryBroadcastSerialise(new_inv, false); BRSendMessage(c, &new_inv->base, "getdata"); /* ask for more */ c->getblocks_sent = 0; } CBFreeInventoryBroadcast(new_inv); CBFreeInventoryBroadcast(inv); }
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; }
void BRSendVersion(BRConnection *c) { /* current version number according to http://bitcoin.stackexchange.com/questions/13537/how-do-i-find-out-what-the-latest-protocol-version-is */ CBVersionServices services = CB_SERVICE_FULL_BLOCKS; int64_t t = time(NULL); CBNetworkAddress *r_addr = c->address; CBNetworkAddress *s_addr = c->my_address; uint64_t nonce = rand(); CBByteArray *ua = CBNewByteArrayFromString("br_cmsc417_v0.1", false); int32_t block_height = 0; /* TODO get real number */ CBVersion *v = CBNewVersion(VERSION_NUM, services, t, r_addr, s_addr, nonce, ua, block_height); uint32_t length = CBVersionCalculateLength(v); v->base.bytes = CBNewByteArrayOfSize(length); CBVersionSerialise(v, false); BRSendMessage(c, &v->base, "version"); /* don't release remote and local addresses just yet. * need them for other messages */ CBReleaseObject(ua); CBFreeVersion(v); }
CBGetHashReturn CBTransactionGetInputHashForSignature(void * vself, CBByteArray * prevOutSubScript, uint32_t input, CBSignType signType, uint8_t * hash){ CBTransaction * self= vself; if (self->inputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for because the input index goes past the number of inputs."); return CB_TX_HASH_BAD; } uint8_t last5Bits = (signType & 0x1f); // For some reason this is what the C++ client does. CBVarInt prevOutputSubScriptVarInt = CBVarIntFromUInt64(prevOutSubScript->length); uint32_t sizeOfData = 12 + prevOutSubScript->length + prevOutputSubScriptVarInt.size; // Version, lock time and the sign type make up 12 bytes. if (signType & CB_SIGHASH_ANYONECANPAY) { sizeOfData += 41; // Just this one input. 32 bytes for outPointerHash, 4 for outPointerIndex, 4 for sequence and one for the *inputNum* var int }else{ sizeOfData += CBVarIntSizeOf(self->inputNum) + self->inputNum * 41 - 1; // All inputs with 1 byte var int except one. } if (last5Bits == CB_SIGHASH_NONE){ sizeOfData++; // Just for the CBVarInt and no outputs. }else if ((signType & 0x1f) == CB_SIGHASH_SINGLE){ if (self->outputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for CB_SIGHASH_SINGLE because there are not enough outputs."); return CB_TX_HASH_BAD; } sizeOfData += CBVarIntSizeOf(input + 1) + input * 9; // For outputs up to the input index // The size for the output at the input index. uint32_t len = CBGetByteArray(self->outputs[input]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; }else{ // All outputs. Default to SIGHASH_ALL sizeOfData += CBVarIntSizeOf(self->outputNum); for (uint32_t x = 0; x < self->outputNum; x++) { uint32_t len = CBGetByteArray(self->outputs[x]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; } } CBByteArray * data = CBNewByteArrayOfSize(sizeOfData); if (NOT data) return CB_TX_HASH_ERR; CBByteArraySetInt32(data, 0, self->version); // Copy input data. Scripts are not copied for the inputs. uint32_t cursor; if (signType & CB_SIGHASH_ANYONECANPAY) { CBVarIntEncode(data, 4, CBVarIntFromUInt64(1)); // Only the input the signature is for. CBByteArrayCopyByteArray(data, 5, self->inputs[input]->prevOut.hash); CBByteArraySetInt32(data, 37, self->inputs[input]->prevOut.index); // Add prevOutSubScript CBVarIntEncode(data, 41, prevOutputSubScriptVarInt); cursor = 41 + prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; CBByteArraySetInt32(data, cursor, self->inputs[input]->sequence); cursor += 4; }else{ CBVarInt inputNum = CBVarIntFromUInt64(self->inputNum); CBVarIntEncode(data, 4, inputNum); cursor = 4 + inputNum.size; for (uint32_t x = 0; x < self->inputNum; x++) { CBByteArrayCopyByteArray(data, cursor, self->inputs[x]->prevOut.hash); cursor += 32; CBByteArraySetInt32(data, cursor, self->inputs[x]->prevOut.index); cursor += 4; // Add prevOutSubScript if the input is for the signature. if (x == input) { CBVarIntEncode(data, cursor, prevOutputSubScriptVarInt); cursor += prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; }else{ CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } if ((signType == CB_SIGHASH_NONE || signType == CB_SIGHASH_SINGLE) && x != input) { CBByteArraySetInt32(data, cursor, 0); } else // SIGHASH_ALL or input index for signing sequence CBByteArraySetInt32(data, cursor, self->inputs[x]->sequence); cursor += 4; } } // Copy output data if (last5Bits == CB_SIGHASH_NONE){ CBVarInt varInt = CBVarIntFromUInt64(0); CBVarIntEncode(data, cursor, varInt); cursor++; }else if (last5Bits == CB_SIGHASH_SINGLE){ CBVarInt varInt = CBVarIntFromUInt64(input + 1); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < input; x++) { CBByteArraySetInt64(data, cursor, CB_OUTPUT_VALUE_MINUS_ONE); cursor += 8; CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } CBByteArraySetInt64(data, cursor, self->outputs[input]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[input]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[input]->scriptObject)); cursor += varInt.val; }else{ // SIGHASH_ALL CBVarInt varInt = CBVarIntFromUInt64(self->outputNum); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < self->outputNum; x++) { CBByteArraySetInt64(data, cursor, self->outputs[x]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[x]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[x]->scriptObject)); cursor += varInt.val; } } // Set lockTime CBByteArraySetInt32(data, cursor, self->lockTime); CBByteArraySetInt32(data, cursor + 4, signType); assert(sizeOfData == cursor + 8); // Must always be like this uint8_t firstHash[32]; CBSha256(CBByteArrayGetData(data), sizeOfData, firstHash); CBSha256(firstHash, 32, hash); return CB_TX_HASH_OK; }
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; }
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; }