Ejemplo n.º 1
0
uint32_t CBTransactionOutputCalculateLength(CBTransactionOutput * self){
	if (CBGetMessage(self)->serialised) {
		// If it is serailised, the var int may be of a different size.
		uint8_t byte = CBByteArrayGetByte(CBGetMessage(self)->bytes, 0);
		return (byte < 253 ? 1 : (byte == 253 ? 3 : (byte == 254 ? 5 : 9))) + self->scriptObject->length + 8;
	} else return CBVarIntSizeOf(self->scriptObject->length) + self->scriptObject->length + 8;
}
Ejemplo n.º 2
0
char * CBNetworkAddressToString(CBNetworkAddress * self, char output[48]){
	if (self->type & CB_IP_IP4) {
		sprintf(output, "[::ffff:%u.%u.%u.%u]:%u",
				CBByteArrayGetByte(self->ip, 12),
				CBByteArrayGetByte(self->ip, 13),
				CBByteArrayGetByte(self->ip, 14),
				CBByteArrayGetByte(self->ip, 15),
				self->port);
		return strchr(output, '\0');
	}
	*(output++) = '[';
	uint8_t numColons = 0;
	for (uint8_t x = 0; x < 16; x += 2) {
		// Also can be used for any reading of big endian 16 bit integers
		uint16_t num = CBByteArrayReadPort(self->ip, x);
		if (num == 0) {
			// Skip
			if (numColons < 2) {
				*(output++) = ':';
				if (numColons == 0)
					*(output++) = ':';
				numColons = 2;
			}
		}else{
			// Write number
			sprintf(output, "%x", num);
			output = strchr(output, '\0');
			if (x != 14) {
				*(output++) = ':';
				numColons = 1;
			}
		}
	}
	// Add port number
	*output = ']';
	sprintf(output + 1, ":%u", self->port);
	return strchr(output, '\0');
}
Ejemplo n.º 3
0
uint32_t CBTransactionOutputDeserialise(CBTransactionOutput * self){
	CBByteArray * bytes = CBGetMessage(self)->bytes;
	if (NOT bytes) {
		CBLogError("Attempting to deserialise a CBTransactionOutput with no bytes.");
		return 0;
	}
	if (bytes->length < 9) {
		CBLogError("Attempting to deserialise a CBTransactionOutput with less than 9 bytes.");
		return 0;
	}
	uint8_t x = CBByteArrayGetByte(bytes, 8); // Check length for decoding CBVarInt
	if (x < 253)
		x = 9;
	else if (x == 253)
		x = 11;
	else if (x == 254)
		x = 13;
	else
		x = 17;
	if (bytes->length < x) {
		CBLogError("Attempting to deserialise a CBTransactionOutput with less than %i bytes required.", x);
		return 0;
	}
	CBVarInt scriptLen = CBVarIntDecode(bytes, 8); // Can now decode.
	if (scriptLen.val > 10000) {
		CBLogError("Attempting to deserialise a CBTransactionInput with too big a script.");
		return 0;
	}
	uint32_t reqLen = (uint32_t)(8 + scriptLen.size + scriptLen.val);
	if (bytes->length < reqLen) {
		CBLogError("Attempting to deserialise a CBTransactionOutput with less bytes than needed according to the length for the script. %i < %i", bytes->length, reqLen);
		return 0;
	}
	// Deserialise by subreferencing byte arrays and reading integers.
	self->value = CBByteArrayReadInt64(bytes, 0);
	self->scriptObject = CBNewScriptFromReference(bytes, 8 + scriptLen.size, (uint32_t) scriptLen.val);
	if (NOT self->scriptObject){
		CBLogError("Cannot create a new CBScript in CBTransactionOutputDeserialise");
		return 0;
	}
	return reqLen;
}
Ejemplo n.º 4
0
uint8_t CBVersionChecksumBytesGetVersion(CBVersionChecksumBytes * self) {
    return CBByteArrayGetByte(CBGetByteArray(self), 0);
}
Ejemplo n.º 5
0
uint32_t CBVersionDeserialise(CBVersion * self){
	CBByteArray * bytes = CBGetMessage(self)->bytes;
	if (NOT bytes) {
		CBGetMessage(self)->logError("Attempting to deserialise a CBVersion with no bytes.");
		return 0;
	}
	if (bytes->length < 46) {
		CBGetMessage(self)->logError("Attempting to deserialise a CBVersion with less than 46 bytes.");
		return 0;
	}
	self->version = CBByteArrayReadInt32(bytes, 0);
	self->services = (CBVersionServices) CBByteArrayReadInt64(bytes, 4);
	self->time = CBByteArrayReadInt64(bytes, 12);
	CBByteArray * data = CBByteArraySubReference(bytes, 20, bytes->length-20); // Get data from 20 bytes to the end of the byte array to deserialise the recieving network address.
	if (NOT data) {
		CBGetMessage(self)->logError("Cannot create a new CBByteArray in CBVersionDeserialise for the receiving address.");
		return 0;
	}
	self->addRecv = CBNewNetworkAddressFromData(data, CBGetMessage(self)->logError);
	if (NOT self->addRecv) {
		CBGetMessage(self)->logError("Cannot create a new CBNetworkAddress in CBVersionDeserialise for the receiving address.");
		CBReleaseObject(data);
		return 0;
	}
	uint32_t len = CBNetworkAddressDeserialise(self->addRecv, false); // No time from version message.
	if (NOT len){
		CBGetMessage(self)->logError("CBVersion cannot be deserialised because of an error with the receiving address.");
		CBReleaseObject(data);
		return 0;
	}
	// Readjust CBByteArray length for recieving address
	data->length = len;
	CBReleaseObject(data);
	if (self->version >= 106) { // ??? Very old. No need for backwards compatibility? Might as well.
		if (bytes->length < 85) {
			CBGetMessage(self)->logError("Attempting to deserialise a CBVersion with less than 85 bytes required.");
			return 0;
		}
		// Source address deserialisation
		data = CBByteArraySubReference(bytes, 46, bytes->length-46);
		if (NOT data) {
			CBGetMessage(self)->logError("Cannot create a new CBByteArray in CBVersionDeserialise for the source address.");
			return 0;
		}
		self->addSource = CBNewNetworkAddressFromData(data, CBGetMessage(self)->logError);
		if (NOT self->addSource) {
			CBGetMessage(self)->logError("Cannot create a new CBNetworkAddress in CBVersionDeserialise for the source address.");
			CBReleaseObject(data);
			return 0;
		}
		uint32_t len = CBNetworkAddressDeserialise(self->addSource, false); // No time from version message.
		if (NOT len){
			CBGetMessage(self)->logError("CBVersion cannot be deserialised because of an error with the source address.");
			CBReleaseObject(data);
			return 0;
		}
		// Readjust CBByteArray length for source address
		data->length = len;
		CBReleaseObject(data);
		self->nonce = CBByteArrayReadInt64(bytes, 72);
		uint8_t x = CBByteArrayGetByte(bytes, 80); // Check length for decoding CBVarInt
		if (x > 253){
			CBGetMessage(self)->logError("Attempting to deserialise a CBVersion with a var string that is too big.");
			return 0;
		}
		CBVarInt varInt = CBVarIntDecode(bytes, 80);
		if (bytes->length < 84 + varInt.size + varInt.val) {
			CBGetMessage(self)->logError("Attempting to deserialise a CBVersion without enough space to cover the userAgent and block height.");
			return 0;
		}
		if (varInt.val > 400) { // cbitcoin accepts userAgents upto 400 bytes
			CBGetMessage(self)->logError("Attempting to deserialise a CBVersion with a userAgent over 400 bytes.");
			return 0;
		}
		self->userAgent = CBNewByteArraySubReference(bytes, 80 + varInt.size, (uint32_t)varInt.val);
		if (NOT self->userAgent) {
			CBGetMessage(self)->logError("Cannot create a new CBByteArray in CBVersionDeserialise");
			return 0;
		}
		self->blockHeight = CBByteArrayReadInt32(bytes, 80 + varInt.size + (uint32_t)varInt.val);
		return 84 + varInt.size + (uint32_t)varInt.val;
	}else return 46; // Not the further message.
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
0
int main(){
	printf("OpenSSL version: %s\n", OPENSSL_VERSION_TEXT);
	printf("Enter the number of keys: ");
	fflush(stdout);
	char stringMatch[31];
	getLine(stringMatch);
	unsigned long int i = strtol(stringMatch, NULL, 0);
	printf("Enter a string of text for the key (30 max): ");
	fflush(stdout);
	getLine(stringMatch);
	printf("Waiting for entropy... Move the cursor around...\n");
	fflush(stdout);
	char entropy[32];
	FILE * f = fopen("/dev/random", "r");
	if (fread(entropy, 32, 1, f) != 1){
		printf("FAILURING GETTING ENTROPY!");
		return 1;
	}
	RAND_add(entropy, 32, 32);
	fclose(f);
	printf("Making %lu addresses for \"%s\"\n\n", i, stringMatch);
	EC_KEY * key = EC_KEY_new_by_curve_name(NID_secp256k1);
	uint8_t * pubKey = NULL;
	int pubSize = 0;
	uint8_t * privKey = NULL;
	int privSize = 0;
	uint8_t * shaHash = malloc(32);
	uint8_t * ripemdHash = malloc(20);
	for (unsigned int x = 0; x < i;) {
		if(! EC_KEY_generate_key(key)){
			printf("GENERATE KEY FAIL\n"); 
			return 1;
		}
		int pubSizeNew = i2o_ECPublicKey(key, NULL);
		if(! pubSizeNew){
			printf("PUB KEY TO DATA ZERO\n"); 
			return 1;
		}
		if (pubSizeNew != pubSize) {
			pubSize = pubSizeNew;
			pubKey = realloc(pubKey, pubSize);
		}
		uint8_t * pubKey2 = pubKey;
		if(i2o_ECPublicKey(key, &pubKey2) != pubSize){
			printf("PUB KEY TO DATA FAIL\n");
			return 1;
		}
		SHA256(pubKey, pubSize, shaHash);
		RIPEMD160(shaHash, 32, ripemdHash);
		CBAddress * address = CBNewAddressFromRIPEMD160Hash(ripemdHash, CB_PRODUCTION_NETWORK_BYTE, false, err);
		CBByteArray * string = CBChecksumBytesGetString(CBGetChecksumBytes(address));
		CBReleaseObject(address);
		bool match = true;
		uint8_t offset = 1;
		size_t matchSize = strlen(stringMatch);
		for (uint8_t y = 0; y < matchSize;) {
			char other = islower(stringMatch[y]) ? toupper(stringMatch[y]) : (isupper(stringMatch[y])? tolower(stringMatch[y]) : '\0');
			if (CBByteArrayGetByte(string, y+offset) != stringMatch[y] && CBByteArrayGetByte(string, y+offset) != other) {
				offset++;
				y = 0;
				if (string->length < matchSize + offset) {
					match = false;
					break;
				}
			}else y++;
		}
		if (match) {
			// Get private key
			const BIGNUM * privKeyNum = EC_KEY_get0_private_key(key);
			if (! privKeyNum) {
				printf("PRIV KEY TO BN FAIL\n");
			}
			int privSizeNew = BN_num_bytes(privKeyNum);
			if (privSizeNew != privSize) {
				privSize = privSizeNew;
				privKey = realloc(privKey, privSize);
			}
			int res = BN_bn2bin(privKeyNum, privKey);
			if (res != privSize) {
				printf("PRIV KEY TO DATA FAIL\n");
			}
			// Print data to stdout
			printf("Private key (hex): ");
			for (int x = 0; x < privSize; x++) {
				printf(" %.2X", privKey[x]);
			}
			printf("\nPublic key (hex): ");
			for (int x = 0; x < pubSize; x++) {
				printf(" %.2X", pubKey[x]);
			}
			printf("\nAddress (base-58): %s\n\n", CBByteArrayGetData(string));
			x++; // Move to next
		}
		CBReleaseObject(string);
	}
	free(shaHash);
	free(ripemdHash);
	EC_KEY_free(key);
	return 0;
}
Ejemplo n.º 8
0
uint32_t CBBlockDeserialise(CBBlock * self, bool transactions){
	CBByteArray * bytes = CBGetMessage(self)->bytes;
	if (NOT bytes) {
		CBLogError("Attempting to deserialise a CBBlock with no bytes.");
		return 0;
	}
	if (bytes->length < 82) {
		CBLogError("Attempting to deserialise a CBBlock with less than 82 bytes. Minimum for header (With null byte).");
		return 0;
	}
	self->version = CBByteArrayReadInt32(bytes, 0);
	self->prevBlockHash = CBByteArraySubReference(bytes, 4, 32);
	if (NOT self->prevBlockHash){
		CBLogError("Cannot create the previous block hash CBByteArray in CBBlockDeserialise.");
		return 0;
	}
	self->merkleRoot = CBByteArraySubReference(bytes, 36, 32);
	if (NOT self->merkleRoot){
		CBLogError("Cannot create the merkle root CBByteArray in CBBlockDeserialise.");
		return 0;
	}
	self->time = CBByteArrayReadInt32(bytes, 68);
	self->target = CBByteArrayReadInt32(bytes, 72);
	self->nonce = CBByteArrayReadInt32(bytes, 76);
	// If first VarInt byte is zero, then stop here for headers, otherwise look for 8 more bytes and continue
	uint8_t firstByte = CBByteArrayGetByte(bytes, 80);
	if (transactions && firstByte) {
		// More to come
		if (bytes->length < 89) {
			CBLogError("Attempting to deserialise a CBBlock with a non-zero varint with less than 89 bytes.");
			return 0;
		}
		CBVarInt transactionNumVarInt = CBVarIntDecode(bytes, 80);
		if (transactionNumVarInt.val*60 > bytes->length - 81) {
			CBLogError("Attempting to deserialise a CBBlock with too many transactions for the byte data length.");
			return 0;
		}
		self->transactionNum = (uint32_t)transactionNumVarInt.val;
		self->transactions = malloc(sizeof(*self->transactions) * self->transactionNum);
		if (NOT self->transactionNum) {
			CBLogError("Cannot allocate %i bytes of memory in CBBlockDeserialise\n", sizeof(*self->transactions) * self->transactionNum);
			return 0;
		}
		uint32_t cursor = 80 + transactionNumVarInt.size;
		for (uint16_t x = 0; x < self->transactionNum; x++) {
			CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor);
			if (NOT data) {
				CBLogError("Could not create a new CBByteArray in CBBlockDeserialise for the transaction number %u.", x);
			}
			CBTransaction * transaction = CBNewTransactionFromData(data);
			if (NOT transaction){
				CBLogError("Could not create a new CBTransaction in CBBlockDeserialise for the transaction number %u.", x);
				CBReleaseObject(data);
				return 0;
			}
			uint32_t len = CBTransactionDeserialise(transaction);
			if (NOT len){
				CBLogError("CBBlock cannot be deserialised because of an error with the transaction number %u.", x);
				CBReleaseObject(data);
				return 0;
			}
			// Read just the CBByteArray length
			data->length = len;
			CBReleaseObject(data);
			self->transactions[x] = transaction;
			cursor += len;
		}
		return cursor;
	}else{ // Just header
		uint8_t x;
		if (firstByte < 253) {
			x = 1;
		}else if (firstByte == 253){
			x = 2;
		}else if (firstByte == 254){
			x = 4;
		}else{
			x = 8;
		}
		if (bytes->length < 80 + x + 1) {
			CBLogError("Attempting to deserialise a CBBlock header with not enough space to cover the var int.");
			return 0;
		}
		self->transactionNum = (uint32_t)CBVarIntDecode(bytes, 80).val; // This value is undefined in the protocol. Should best be zero when getting the headers since there is not supposed to be any transactions. Would have probably been better if the var int was dropped completely for headers only.
		// Ensure null byte is null. This null byte is a bit of a nuissance but it exists in the protocol when there are no transactions.
		if (CBByteArrayGetByte(bytes, 80 + x) != 0) {
			CBLogError("Attempting to deserialise a CBBlock header with a final byte which is not null. This is not what it is supposed to be but you already knew that right?");
			return 0;
		}
		return 80 + x + 1; // 80 header bytes, the var int and the null byte
	}
}