uint32_t CBTransactionInputDeserialise(CBTransactionInput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBTransactionInput with no bytes."); return 0; } if (bytes->length < 41) { CBLogError("Attempting to deserialise a CBTransactionInput with less than 41 bytes."); return 0; } CBVarInt scriptLen = CBVarIntDecode(bytes, 36); if (scriptLen.val > 10000) { CBLogError("Attempting to deserialise a CBTransactionInput with too big a script."); return 0; } uint32_t reqLen = (uint32_t)(40 + scriptLen.size + scriptLen.val); if (bytes->length < reqLen) { CBLogError("Attempting to deserialise a CBTransactionInput 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->prevOut.hash = CBByteArraySubReference(bytes, 0, 32); self->prevOut.index = CBByteArrayReadInt32(bytes, 32); self->scriptObject = CBNewScriptFromReference(bytes, 36 + scriptLen.size, (uint32_t) scriptLen.val); self->sequence = CBByteArrayReadInt32(bytes, (uint32_t) (36 + scriptLen.size + scriptLen.val)); return reqLen; }
uint32_t CBInventoryBroadcastSerialise(CBInventoryBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBInventoryBroadcast with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->itemNum); if (bytes->length < num.size + 36 * self->itemNum) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { CBGetMessage(self->items[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); uint32_t len = CBInventoryItemSerialise(self->items[x]); if (NOT len) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be serialised because of an error with the CBInventoryItem number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) { CBReleaseObject(CBGetMessage(self->items[y])->bytes); } return 0; } CBGetMessage(self->items[x])->bytes->length = len; cursor += len; } return cursor; }
uint32_t CBAddressBroadcastDeserialise(CBAddressBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to deserialise a CBAddressBroadcast with no bytes."); return 0; } if (bytes->length < 26 + self->timeStamps * 4) { CBLogError("Attempting to deserialise a CBAddressBroadcast without enough bytes to cover one address."); return 0; } CBVarInt num = CBVarIntDecode(bytes, 0); /* TODO fix this, don't just hack it away if (num.val > 30) { CBLogError("Attempting to deserialise a CBAddressBroadcast with a var int over 30."); return 0; } */ self->addresses = malloc(sizeof(*self->addresses) * (size_t)num.val); if (NOT self->addresses) { CBLogError("Cannot allocate %i bytes of memory in CBAddressBroadcastDeserialise\n", sizeof(*self->addresses) * (size_t)num.val); return 0; } self->addrNum = num.val; uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { // Make new CBNetworkAddress from the rest of the data. uint8_t len; CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (data) { // Create a new network address object. It is public since it is in an address broadcast. self->addresses[x] = CBNewNetworkAddressFromData(data, true); if (self->addresses[x]){ // Deserialise len = CBNetworkAddressDeserialise(self->addresses[x], self->timeStamps); if (NOT len) CBLogError("CBAddressBroadcast cannot be deserialised because of an error with the CBNetworkAddress number %u.", x); }else{ len = 0; CBLogError("Could not create CBNetworkAddress in CBAddressBroadcastDeserialise for network address %u.", x); } }else{ len = 0; CBLogError("Could not create CBByteArray in CBAddressBroadcastDeserialise for network address %u.", x); } if (NOT len) { // Release bytes CBReleaseObject(data); return 0; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBAddressBroadcastDeserialise(CBAddressBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_NULL_BYTES,"Attempting to deserialise a CBAddressBroadcast with no bytes."); return 0; } if (bytes->length < 26 + self->timeStamps * 4) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBAddressBroadcast without enough bytes to cover one address."); return 0; } CBVarInt num = CBVarIntDecode(bytes, 0); if (num.val > 30) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBAddressBroadcast with a var int over 30."); return 0; } self->addresses = malloc(sizeof(*self->addresses) * (size_t)num.val); if (NOT self->addresses) { CBGetMessage(self)->onErrorReceived(CB_ERROR_OUT_OF_MEMORY,"Cannot allocate %i bytes of memory in CBAddressBroadcastDeserialise\n",sizeof(*self->addresses) * (size_t)num.val); return 0; } self->addrNum = num.val; uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { // Make new CBNetworkAddress from the rest of the data. uint8_t len; CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (data) { self->addresses[x] = CBNewNetworkAddressFromData(data, CBGetMessage(self)->onErrorReceived); if (self->addresses[x]){ // Deserialise len = CBNetworkAddressDeserialise(self->addresses[x], self->timeStamps); if (NOT len) CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"CBAddressBroadcast cannot be deserialised because of an error with the CBNetworkAddress number %u.",x); }else{ len = 0; CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Could not create CBNetworkAddress in CBAddressBroadcastDeserialise for network address %u.",x); } }else{ len = 0; CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Could not create CBByteArray in CBAddressBroadcastDeserialise for network address %u.",x); } if (NOT len) { // Release bytes CBReleaseObject(data); return 0; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
int CBInventoryDeserialise(CBInventory * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBInventory with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 37) { CBLogError("Attempting to deserialise a CBInventory with less bytes than required for one item."); return CB_DESERIALISE_ERROR; } CBVarInt itemNum = CBByteArrayReadVarInt(bytes, 0); if (itemNum.val > 50000) { CBLogError("Attempting to deserialise a CBInventory with a var int over 50000."); return CB_DESERIALISE_ERROR; } self->itemNum = 0; self->itemFront = NULL; // Run through the items and deserialise each one. int cursor = itemNum.size; for (int x = 0; x < itemNum.val; x++) { // Make new CBInventoryItem from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); CBInventoryItem * item = CBNewInventoryItemFromData(data); // Deserialise int len = CBInventoryItemDeserialise(item); if (len == CB_DESERIALISE_ERROR){ CBLogError("CBInventory cannot be deserialised because of an error with the CBInventoryItem number %u.", x); CBReleaseObject(data); return CB_DESERIALISE_ERROR; } // Take item CBInventoryTakeInventoryItem(self, item); // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBInventoryBroadcastDeserialise(CBInventoryBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_NULL_BYTES,"Attempting to deserialise a CBInventoryBroadcast with no bytes."); return 0; } if (bytes->length < 37) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required for one item."); return 0; } CBVarInt itemNum = CBVarIntDecode(bytes, 0); if (itemNum.val > 1388) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with a var int over 1388."); return 0; } // Run through the items and deserialise each one. self->items = malloc(sizeof(*self->items) * (size_t)itemNum.val); if (NOT self->items) { CBGetMessage(self)->onErrorReceived(CB_ERROR_OUT_OF_MEMORY,"Cannot allocate %i bytes of memory in CBInventoryBroadcastDeserialise",sizeof(*self->items) * (size_t)itemNum.val); return 0; } self->itemNum = itemNum.val; uint16_t cursor = itemNum.size; for (uint16_t x = 0; x < itemNum.val; x++) { // Make new CBInventoryItem from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Could not create a new CBByteArray in CBInventoryBroadcastDeserialise for inventory broadcast number %u.",x); return 0; } self->items[x] = CBNewInventoryItemFromData(data, CBGetMessage(self)->onErrorReceived); if (NOT self->items[x]) { CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Could not create a new CBInventoryItem in CBInventoryBroadcastDeserialise for inventory broadcast number %u.",x); CBReleaseObject(data); return 0; } // Deserialise uint8_t len = CBInventoryItemDeserialise(self->items[x]); if (NOT len){ CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be deserialised because of an error with the CBInventoryItem number %u.",x); CBReleaseObject(data); return 0; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBBlockHeadersDeserialise(CBBlockHeaders * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to deserialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 82) { CBGetMessage(self)->logError("Attempting to deserialise a CBBlockHeaders with less bytes than required for one header."); return 0; } CBVarInt headerNum = CBVarIntDecode(bytes, 0); if (headerNum.val > 2000) { CBGetMessage(self)->logError("Attempting to deserialise a CBBlockHeaders with a var int over 2000."); return 0; } // Deserialise each header self->blockHeaders = malloc(sizeof(*self->blockHeaders) * (size_t)headerNum.val); if (NOT self->blockHeaders) { CBGetMessage(self)->logError("Cannot allocate %i bytes of memory in CBBlockHeadersDeserialise\n",sizeof(*self->blockHeaders) * (size_t)headerNum.val); return 0; } self->headerNum = headerNum.val; uint16_t cursor = headerNum.size; for (uint16_t x = 0; x < headerNum.val; x++) { // Make new CBBlock from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBGetMessage(self)->logError("Cannot create a new CBByteArray in CBBlockHeadersDeserialise for the header number %u.",x); return 0; } self->blockHeaders[x] = CBNewBlockFromData(data, CBGetMessage(self)->logError); if (NOT self->blockHeaders[x]) { CBGetMessage(self)->logError("Cannot create a new CBBlock in CBBlockHeadersDeserialise for the header number %u.",x); CBReleaseObject(data); return 0; } // Deserialise uint8_t len = CBBlockDeserialise(self->blockHeaders[x], false); // false for no transactions. Only the header. if (NOT len) { CBGetMessage(self)->logError("CBBlockHeaders cannot be deserialised because of an error with the CBBlock number %u.",x); CBReleaseObject(data); return 0; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBInventoryItemDeserialise(CBInventoryItem * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to deserialise a CBInventoryItem with no bytes."); return 0; } if (bytes->length < 36) { CBGetMessage(self)->logError("Attempting to deserialise a CBInventoryItem with less than 36 bytes."); return 0; } self->type = CBByteArrayReadInt32(bytes, 0); self->hash = CBByteArraySubReference(bytes, 4, 32); if (NOT self->hash) return 0; return 36; }
uint32_t CBBlockHeadersSerialise(CBBlockHeaders * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 81 * self->headerNum) { CBLogError("Attempting to deserialise a CBBlockHeaders with less bytes than minimally required."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->headerNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->blockHeaders[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as the block headers message, re-serialise the block header, in case it got overwritten. || CBGetMessage(self->blockHeaders[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->blockHeaders[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->blockHeaders[x])->bytes); CBGetMessage(self->blockHeaders[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBGetMessage(self->blockHeaders[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBBlockHeadersSerialise for the header number %u", x); return 0; } if (! CBBlockSerialise(self->blockHeaders[x], false, force)) { // false for no transactions. CBLogError("CBBlockHeaders cannot be serialised because of an error with the CBBlock number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->blockHeaders[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->blockHeaders[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->blockHeaders[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->blockHeaders[x])->bytes->length; } // Ensure length is correct bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
int CBBlockHeadersDeserialise(CBBlockHeaders * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBBlockHeaders with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 82) { CBLogError("Attempting to deserialise a CBBlockHeaders with less bytes than required for one header."); return CB_DESERIALISE_ERROR; } CBVarInt headerNum = CBByteArrayReadVarInt(bytes, 0); if (headerNum.val > 2000) { CBLogError("Attempting to deserialise a CBBlockHeaders with a var int over 2000."); return CB_DESERIALISE_ERROR; } // Deserialise each header self->headerNum = headerNum.val; int cursor = headerNum.size; for (int x = 0; x < headerNum.val; x++) { // Make new CBBlock from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); self->blockHeaders[x] = CBNewBlockFromData(data); // Deserialise int len = CBBlockDeserialise(self->blockHeaders[x], false); // false for no transactions. Only the header. if (len == CB_DESERIALISE_ERROR){ CBLogError("CBBlockHeaders cannot be deserialised because of an error with the CBBlock number %" PRIu16 ".", x); CBReleaseObject(data); return CB_DESERIALISE_ERROR; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBInventoryBroadcastDeserialise(CBInventoryBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_NULL_BYTES,"Attempting to deserialise a CBInventoryBroadcast with no bytes."); return 0; } if (bytes->length < 37) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required for one item."); return 0; } CBVarInt itemNum = CBVarIntDecode(bytes, 0); if (itemNum.val > 1388) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with a var int over 1388."); return 0; } // Run through the items and deserialise each one. self->items = malloc(sizeof(*self->items) * (size_t)itemNum.val); self->itemNum = itemNum.val; uint16_t cursor = itemNum.size; for (uint16_t x = 0; x < itemNum.val; x++) { // Make new CBInventoryItem from the rest of the data. CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); self->items[x] = CBNewInventoryItemFromData(data, CBGetMessage(self)->events); // Deserialise uint8_t len = CBInventoryItemDeserialise(self->items[x]); if (NOT len) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be deserialised because of an error with the CBInventoryItem number %u.",x); // Release bytes CBReleaseObject(data); // Because of failure release the CBInventoryItems for (uint16_t y = 0; y < x + 1; y++) { CBReleaseObject(self->items[y]); } free(self->items); self->items = NULL; self->itemNum = 0; return 0; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBNetworkAddressListSerialise(CBNetworkAddressList * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBNetworkAddress with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->addrNum); if (bytes->length < (26 + self->timeStamps * 4) * self->addrNum + num.size) { CBLogError("Attempting to serialise a CBNetworkAddress without enough bytes."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->addresses[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this address broadcast, re-serialise the address, in case it got overwritten. || CBGetMessage(self->addresses[x])->bytes->sharedData == bytes->sharedData || (CBGetMessage(self->addresses[x])->bytes->length != 26) ^ self->timeStamps) { if (CBGetMessage(self->addresses[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->addresses[x])->bytes); CBGetMessage(self->addresses[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBNetworkAddressSerialise(self->addresses[x], self->timeStamps)) { CBLogError("CBNetworkAddress cannot be serialised because of an error with the CBNetworkAddress number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->addresses[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->addresses[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->addresses[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->addresses[x])->bytes->length; } // Change bytes length bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBBlockHeadersSerialise(CBBlockHeaders * self, bool force) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to serialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 81 * self->headerNum) { CBGetMessage(self)->logError("Attempting to deserialise a CBBlockHeaders with less bytes than minimally required."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->headerNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->blockHeaders[x])->serialised) CBReleaseObject(CBGetMessage(self->blockHeaders[x])->bytes); if (NOT CBGetMessage(self->blockHeaders[x])->serialised || force) { CBGetMessage(self->blockHeaders[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->blockHeaders[x])->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBBlockHeadersSerialise for the header number %u",x); return 0; } uint32_t len = CBBlockSerialise(self->blockHeaders[x], false, force); // false for no transactions. if (NOT len) { CBGetMessage(self)->logError("CBBlockHeaders cannot be serialised because of an error with the CBBlock number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->blockHeaders[y])->bytes); return 0; } CBGetMessage(self->blockHeaders[x])->bytes->length = len; } else if (CBGetMessage(self->blockHeaders[x])->bytes->sharedData != bytes->sharedData) { // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->blockHeaders[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->blockHeaders[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->blockHeaders[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBInventoryBroadcastSerialise(CBInventoryBroadcast * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBInventoryBroadcast with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->itemNum); if (bytes->length < num.size + 36 * self->itemNum) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->items[x])->serialised) CBReleaseObject(CBGetMessage(self->items[x])->bytes); if (NOT CBGetMessage(self->items[x])->serialised || force) { CBGetMessage(self->items[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->items[x])->bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Cannot create a new CBByteArray sub reference in CBInventoryBroadcastSerialise"); return 0; } uint32_t len = CBInventoryItemSerialise(self->items[x]); if (NOT len) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be serialised because of an error with the CBInventoryItem number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->items[y])->bytes); return 0; } CBGetMessage(self->items[x])->bytes->length = len; }else if (CBGetMessage(self->items[x])->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->items[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->items[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->items[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBNetworkAddressListDeserialise(CBNetworkAddressList * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBNetworkAddressList with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 26 + self->timeStamps * 4) { CBLogError("Attempting to deserialise a CBNetworkAddressList without enough bytes to cover one address."); return CB_DESERIALISE_ERROR; } CBVarInt num = CBVarIntDecode(bytes, 0); if (num.val > 1000) { CBLogError("Attempting to deserialise a CBNetworkAddressList with a var int over 1000."); return CB_DESERIALISE_ERROR; } self->addresses = malloc(sizeof(*self->addresses) * (size_t)num.val); self->addrNum = (uint32_t)num.val; uint16_t cursor = num.size; for (uint32_t x = 0; x < num.val; x++) { // Make new CBNetworkAddress from the rest of the data. uint32_t len; CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); // Create a new network address object. It is public since it is in an address broadcast. self->addresses[x] = CBNewNetworkAddressFromData(data, true); // Deserialise len = CBNetworkAddressDeserialise(self->addresses[x], self->timeStamps); if (len == CB_DESERIALISE_ERROR){ CBLogError("CBNetworkAddressList cannot be deserialised because of an error with the CBNetworkAddress number %u.", x); // Release bytes CBReleaseObject(data); return CB_DESERIALISE_ERROR; } // Adjust length data->length = len; CBReleaseObject(data); cursor += len; } return cursor; }
uint32_t CBAddressBroadcastSerialise(CBAddressBroadcast * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBAddressBroadcast with no bytes."); return 0; } if (bytes->length < (26 + self->timeStamps * 4) * self->addrNum) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"Attempting to serialise a CBAddressBroadcast without enough bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->addrNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->addresses[x])->serialised) CBReleaseObject(CBGetMessage(self->addresses[x])->bytes); if (NOT CBGetMessage(self->addresses[x])->serialised || force) { CBGetMessage(self->addresses[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); uint32_t len = CBNetworkAddressSerialise(self->addresses[x],self->timeStamps); if (NOT len) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBAddressBroadcast cannot be serialised because of an error with the CBNetworkAddress number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->addresses[y])->bytes); return 0; } CBGetMessage(self->addresses[x])->bytes->length = len; }else if (CBGetMessage(self->addresses[x])->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->addresses[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->addresses[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->addresses[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBTransactionInputDeserialise(CBTransactionInput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_NULL_BYTES,"Attempting to deserialise a CBTransactionInput with no bytes."); return 0; } if (bytes->length < 41) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBTransactionInput with less than 41 bytes."); return 0; } CBVarInt scriptLen = CBVarIntDecode(bytes, 36); if (scriptLen.val > 10000) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBTransactionInput with too big a script."); return 0; } uint32_t reqLen = (uint32_t)(40 + scriptLen.size + scriptLen.val); if (bytes->length < reqLen) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBTransactionInput 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->prevOut.hash = CBByteArraySubReference(bytes, 0, 32); if (NOT self->prevOut.hash){ CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Cannot create a new CBByteArray in CBTransactionInputDeserialise"); return 0; } self->prevOut.index = CBByteArrayReadInt32(bytes, 32); self->scriptObject = CBNewScriptFromReference(bytes,36 + scriptLen.size, (uint32_t) scriptLen.val); if (NOT self->scriptObject) { CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Cannot create a new CBScript in CBTransactionInputDeserialise"); CBReleaseObject(self->prevOut.hash); return 0; } self->sequence = CBByteArrayReadInt32(bytes, (uint32_t) (36 + scriptLen.size + scriptLen.val)); return reqLen; }
uint32_t CBVersionSerialise(CBVersion * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with no bytes."); return 0; } if (bytes->length < 46) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with less than 46 bytes."); return 0; } CBByteArraySetInt32(bytes, 0, self->version); CBByteArraySetInt64(bytes, 4, self->services); CBByteArraySetInt64(bytes, 12, self->time); if (force && CBGetMessage(self->addRecv)->serialised) CBReleaseObject(CBGetMessage(self->addRecv)->bytes); if (NOT CBGetMessage(self->addRecv)->serialised || force) { CBGetMessage(self->addRecv)->bytes = CBByteArraySubReference(bytes, 20, bytes->length-20); if (NOT CBGetMessage(self->addRecv)->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBVersionSerialise for receiving address."); return 0; } uint32_t len = CBNetworkAddressSerialise(self->addRecv,false); if (NOT len) { CBGetMessage(self)->logError("CBVersion cannot be serialised because of an error with the receiving CBNetworkAddress"); // Release bytes to avoid problems overwritting pointer without release, if serialisation is tried again. CBReleaseObject(CBGetMessage(self->addRecv)->bytes); return 0; } CBGetMessage(self->addRecv)->bytes->length = len; }else if (CBGetMessage(self->addRecv)->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, 20, CBGetMessage(self->addRecv)->bytes); CBByteArrayChangeReference(CBGetMessage(self->addRecv)->bytes, bytes, 20); } if (self->version >= 106) { if (bytes->length < 85) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with less than 85 bytes required."); return 0; } if (self->userAgent->length > 400) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with a userAgent over 400 bytes."); return 0; } if (force && CBGetMessage(self->addSource)->serialised) CBReleaseObject(CBGetMessage(self->addSource)->bytes); if (NOT CBGetMessage(self->addSource)->serialised || force) { CBGetMessage(self->addSource)->bytes = CBByteArraySubReference(bytes, 46, bytes->length-46); if (NOT CBGetMessage(self->addSource)->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBVersionSerialise for source address."); return 0; } uint32_t len = CBNetworkAddressSerialise(self->addSource,false); if (NOT len) { CBGetMessage(self)->logError("CBVersion cannot be serialised because of an error with the source CBNetworkAddress"); // Release bytes to avoid problems overwritting pointer without release, if serialisation is tried again. CBReleaseObject(CBGetMessage(self->addSource)->bytes); return 0; } CBGetMessage(self->addSource)->bytes->length = len; }else if (CBGetMessage(self->addSource)->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, 46, CBGetMessage(self->addSource)->bytes); CBByteArrayChangeReference(CBGetMessage(self->addSource)->bytes, bytes, 46); } CBByteArraySetInt64(bytes, 72, self->nonce); CBVarInt varInt = CBVarIntFromUInt64(self->userAgent->length); CBVarIntEncode(bytes, 80, varInt); 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; } CBByteArrayCopyByteArray(bytes, 80 + varInt.size,self->userAgent); CBByteArrayChangeReference(self->userAgent,bytes,80 + varInt.size); CBByteArraySetInt32(bytes, 80 + varInt.size + (uint32_t)varInt.val, self->blockHeight); CBGetMessage(self)->serialised = true; return 84 + varInt.size + (uint32_t)varInt.val; }else{ // Not the further message. CBGetMessage(self)->serialised = true; return 46; } }
uint32_t CBBlockSerialise(CBBlock * self, bool transactions, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBBlock with no bytes."); return 0; } CBVarInt transactionNum = CBVarIntFromUInt64(self->transactionNum); uint32_t cursor = 80 + transactionNum.size; if (bytes->length < cursor + 1) { CBLogError("Attempting to serialise a CBBlock with less bytes than required for the header, transaction number var int and at least a null byte. %i < %i", bytes->length, cursor + 1); return 0; } // Do header CBByteArraySetInt32(bytes, 0, self->version); CBByteArrayCopyByteArray(bytes, 4, self->prevBlockHash); CBByteArrayChangeReference(self->prevBlockHash, bytes, 4); CBByteArrayCopyByteArray(bytes, 36, self->merkleRoot); CBByteArrayChangeReference(self->merkleRoot, bytes, 36); CBByteArraySetInt32(bytes, 68, self->time); CBByteArraySetInt32(bytes, 72, self->target); CBByteArraySetInt32(bytes, 76, self->nonce); // Do Transactions CBVarIntEncode(bytes, 80, transactionNum); if (transactions) { for (uint32_t x = 0; x < self->transactionNum; x++) { if (NOT CBGetMessage(self->transactions[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this block, re-serialise the transaction, in case it got overwritten. || CBGetMessage(self->transactions[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->transactions[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->transactions[x])->bytes); CBGetMessage(self->transactions[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->transactions[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBBlockSerialise for the transaction number %u", x); return 0; } if (NOT CBTransactionSerialise(self->transactions[x], force)) { CBLogError("CBBlock cannot be serialised because of an error with the transaction number %u.", x); return 0; } }else{ // Move serialsed data to one location if (bytes->length < cursor + CBGetMessage(self->transactions[x])->bytes->length) { CBLogError("CBBlock cannot be serialised because there was not enough bytes for the transaction number %u (%u < %u).", x, bytes->length, cursor + CBGetMessage(self->transactions[x])->bytes->length); return 0; } CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->transactions[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->transactions[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->transactions[x])->bytes->length; } }else{ // Add null byte since there are to be no transactions (header only). CBByteArraySetByte(bytes, cursor, 0); cursor++; } // Reset hash self->hashSet = false; // Ensure data length is correct. bytes->length = cursor; // Is now serialised. CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBTransactionSerialise(CBTransaction * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBTransaction with no bytes. Now that you think about it, that was a bit stupid wasn't it?"); return 0; } if (NOT self->inputNum || NOT self->outputNum) { CBLogError("Attempting to serialise a CBTransaction with an empty output or input list."); return 0; } CBVarInt inputNum = CBVarIntFromUInt64(self->inputNum); CBVarInt outputNum = CBVarIntFromUInt64(self->outputNum); uint32_t cursor = 4 + inputNum.size; if (bytes->length < cursor + 5) { CBLogError("Attempting to serialise a CBTransaction with less bytes than required. %i < %i\n", bytes->length, cursor + 5); return 0; } // Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory. CBByteArraySetInt32(bytes, 0, self->version); CBVarIntEncode(bytes, 4, inputNum); for (uint32_t x = 0; x < self->inputNum; x++) { if (NOT CBGetMessage(self->inputs[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this transaction, re-serialise the input, in case it got overwritten. || CBGetMessage(self->inputs[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->inputs[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->inputs[x])->bytes); CBGetMessage(self->inputs[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->inputs[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBTransactionSerialise for input number %u", x); return 0; } if (NOT CBTransactionInputSerialise(self->inputs[x])) { CBLogError("CBTransaction cannot be serialised because of an error with the input number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->inputs[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->inputs[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->inputs[x])->bytes->length; } if (bytes->length < cursor + 5) { // Check room for output number and lockTime. CBLogError("Attempting to serialise a CBTransaction with less bytes than required for output number and the lockTime. %i < %i", bytes->length, cursor + 5); return 0; } CBVarIntEncode(bytes, cursor, outputNum); cursor += outputNum.size; for (uint32_t x = 0; x < self->outputNum; x++) { if (NOT CBGetMessage(self->outputs[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this transaction, re-serialise the output, in case it got overwritten. || CBGetMessage(self->outputs[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->outputs[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->outputs[x])->bytes); CBGetMessage(self->outputs[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->outputs[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBTransactionSerialise for output number %u", x); return 0; } if (NOT CBTransactionOutputSerialise(self->outputs[x])) { CBLogError("CBTransaction cannot be serialised because of an error with the output number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < self->inputNum; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); for (uint32_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->outputs[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->outputs[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->outputs[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->outputs[x])->bytes->length; } if (bytes->length < cursor + 4) { // Check room for lockTime. CBLogError("Attempting to serialise a CBTransaction with less bytes than required for the lockTime. %i < %i\n", bytes->length, cursor + 4); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < self->inputNum; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); for (uint32_t y = 0; y < self->outputNum; y++) CBReleaseObject(CBGetMessage(self->outputs[y])->bytes); return 0; } CBByteArraySetInt32(bytes, cursor, self->lockTime); // Ensure length is correct bytes->length = cursor + 4; // Is serialised CBGetMessage(self)->serialised = true; // Make the hash not set for this serialisation. self->hashSet = false; return cursor + 4; }
uint32_t CBTransactionDeserialise(CBTransaction * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to deserialise a CBTransaction with no bytes."); return 0; } if (bytes->length < 10) { CBLogError("Attempting to deserialise a CBTransaction with less than 10 bytes."); return 0; } self->version = CBByteArrayReadInt32(bytes, 0); CBVarInt inputOutputLen = CBVarIntDecode(bytes, 4); if (NOT inputOutputLen.val || inputOutputLen.val * 41 > bytes->length - 10) { CBLogError("Attempting to deserialise a CBTransaction with a bad var int for the number of inputs."); return 0; } uint32_t cursor = 4 + inputOutputLen.size; self->inputNum = (uint32_t)inputOutputLen.val; self->inputs = malloc(sizeof(*self->inputs) * self->inputNum); if (NOT self->inputs) { CBLogError("Cannot allocate %i bytes of memory in CBTransactionDeserialise for inputs.\n", sizeof(*self->inputs) * self->inputNum); return 0; } for (uint32_t x = 0; x < self->inputNum; x++) { CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBLogError("Cannot create a new CBByteArray in CBTransactionDeserialise for the input number %u.", x); return 0; } CBTransactionInput * input = CBNewTransactionInputFromData(data); if (NOT input) { CBLogError("Cannot create a new CBTransactionInput in CBTransactionDeserialise for the input number %u.", x); CBReleaseObject(data); return 0; } uint32_t len = CBTransactionInputDeserialise(input); if (NOT len){ CBLogError("CBTransaction cannot be deserialised because of an error with the input number %u.", x); CBReleaseObject(data); return 0; } // The input was deserialised correctly. Now adjust the length and add it to the transaction. data->length = len; CBReleaseObject(data); self->inputs[x] = input; cursor += len; // Move along to next input } if (bytes->length < cursor + 5) { // Needs at least 5 more for the output CBVarInt and the lockTime CBLogError("Attempting to deserialise a CBTransaction with not enough bytes for the outputs and lockTime."); return 0; } inputOutputLen = CBVarIntDecode(bytes, cursor); if (NOT inputOutputLen.val || inputOutputLen.val * 9 > bytes->length - 10) { CBLogError("Attempting to deserialise a CBTransaction with a bad var int for the number of outputs."); return 0; } cursor += inputOutputLen.size; // Move past output CBVarInt self->outputNum = (uint32_t)inputOutputLen.val; self->outputs = malloc(sizeof(*self->outputs) * self->outputNum); if (NOT self->outputs) { CBLogError("Cannot allocate %i bytes of memory in CBTransactionDeserialise for outputs.\n", sizeof(sizeof(*self->outputs) * self->outputNum)); return 0; } for (uint32_t x = 0; x < self->outputNum; x++) { CBByteArray * data = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT data) { CBLogError("Cannot create a new CBByteArray in CBTransactionDeserialise for the output number %u.", x); return 0; } CBTransactionOutput * output = CBNewTransactionOutputFromData(data); if (NOT output) { CBLogError("Cannot create a new CBTransactionOutput in CBTransactionDeserialise for the output number %u.", x); CBReleaseObject(data); return 0; } uint32_t len = CBTransactionOutputDeserialise(output); if (NOT len){ CBLogError("CBTransaction cannot be deserialised because of an error with the output number %u.", x); CBReleaseObject(data); return 0; } // The output was deserialised correctly. Now adjust the length and add it to the transaction. data->length = len; CBReleaseObject(data); self->outputs[x] = output; cursor += len; // Move along to next output } if (bytes->length < cursor + 4) { // Ensure 4 bytes are available for lockTime CBLogError("Attempting to deserialise a CBTransaction with not enough bytes for the lockTime."); return 0; } self->lockTime = CBByteArrayReadInt32(bytes, cursor); return cursor + 4; }
int CBInventorySerialise(CBInventory * self, bool force) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBInventory with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->itemNum); if (bytes->length < num.size + 36 * self->itemNum) { CBLogError("Attempting to deserialise a CBInventory with less bytes than required."); return 0; } CBByteArraySetVarInt(bytes, 0, num); int cursor = num.size; for (CBInventoryItem * item = self->itemFront; item != NULL; item = item->next) { if (! CBGetMessage(item)->serialised // Serialise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as the inventory boradcast, re-serialise the inventory item, in case it got overwritten. || CBGetMessage(item)->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(item)->serialised) // Release old byte array CBReleaseObject(CBGetMessage(item)->bytes); CBGetMessage(item)->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBInventoryItemSerialise(item)) { CBLogError("CBInventory cannot be serialised because of an error with an CBInventoryItem."); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (CBInventoryItem * item2 = self->itemFront; ; item2 = item->next){ CBReleaseObject(item2); if (item2 == item) break; } return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(item)->bytes); CBByteArrayChangeReference(CBGetMessage(item)->bytes, bytes, cursor); } cursor += CBGetMessage(item)->bytes->length; } // Ensure length is correct bytes->length = cursor; // Is now serialised. CBGetMessage(self)->serialised = true; return cursor; }
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 } }
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. }