uint8_t CBNetworkAddressDeserialise(CBNetworkAddress * self, bool timestamp){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBNetworkAddress with no bytes."); return 0; } if (bytes->length < 26 + timestamp * 4) { CBLogError("Attempting to deserialise a CBNetworkAddress with less bytes than required."); return 0; } uint8_t start; uint64_t twoHoursAgo = time(NULL) - 3600; if (timestamp) { // Make sure we do not set self->lastSeen later than one hour ago. self->lastSeen = CBByteArrayReadInt32(bytes, 0); if (self->lastSeen > twoHoursAgo) self->lastSeen = twoHoursAgo; start = 4; }else{ self->lastSeen = twoHoursAgo; start = 0; } self->services = (CBVersionServices) CBByteArrayReadInt64(bytes, start); self->ip = CBNewByteArraySubReference(bytes, start + 8, 16); // Determine IP type self->type = CBGetIPType(CBByteArrayGetData(self->ip)); self->port = CBByteArrayReadPort(bytes, start + 24); return start + 26; }
int CBPingPongDeserialise(CBPingPong * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBPingPong with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 8) { CBLogError("Attempting to deserialise a CBPingPong with less than 8 bytes."); return CB_DESERIALISE_ERROR; } self->ID = CBByteArrayReadInt64(bytes, 0); return 8; }
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; }
int CBAlertDeserialise(CBAlert * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBAlert with no bytes."); return CB_DESERIALISE_ERROR; } if (bytes->length < 47) { CBLogError("Attempting to deserialise a CBAlert with less than 47 bytes minimally required."); return CB_DESERIALISE_ERROR; } CBVarInt payloadLen = CBByteArrayReadVarInt(bytes, 0); if (bytes->length < payloadLen.size + payloadLen.val + 1) { // Plus one byte for signature var int. After this check the payload size is used to check the payload contents. CBLogError("Attempting to deserialise a CBAlert with less bytes than required for payload."); return CB_DESERIALISE_ERROR; } if (payloadLen.val > 2000) { // Prevent too much memory being used. CBLogError("Attempting to deserialise a CBAlert with a payload var int larger than 2000 bytes."); return CB_DESERIALISE_ERROR; } if (payloadLen.val < 45) { CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than 45."); return CB_DESERIALISE_ERROR; } int cursor = payloadLen.size; self->version = CBByteArrayReadInt32(bytes, cursor); cursor += 4; self->relayUntil = CBByteArrayReadInt64(bytes, cursor); cursor += 8; self->expiration = CBByteArrayReadInt64(bytes, cursor); cursor += 8; self->ID = CBByteArrayReadInt32(bytes, cursor); cursor += 4; self->cancel = CBByteArrayReadInt32(bytes, cursor); cursor += 4; // Add cancel ids CBVarInt setCancelLen = CBByteArrayReadVarInt(bytes, cursor); if (payloadLen.val < 44 + setCancelLen.size + setCancelLen.val * 4) { CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the cancel set."); return CB_DESERIALISE_ERROR; } self->setCancelNum = setCancelLen.val; cursor += setCancelLen.size; if (self->setCancelNum) { self->setCancel = malloc(sizeof(*self->setCancel) * self->setCancelNum); for (int x = 0; x < self->setCancelNum; x++) { CBByteArrayReadInt32(bytes, cursor); cursor += 4; } } self->minVer = CBByteArrayReadInt32(bytes, cursor); cursor += 4; self->maxVer = CBByteArrayReadInt32(bytes, cursor); cursor += 4; // User Agent strings CBVarInt userAgentsLen = CBByteArrayReadVarInt(bytes, cursor); if (payloadLen.val < 7 + cursor + userAgentsLen.size + userAgentsLen.val - payloadLen.size) { // 7 for priority and 3 strings CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the cancel set and the user agent set assuming empty strings."); return CB_DESERIALISE_ERROR; } self->userAgentNum = userAgentsLen.val; cursor += userAgentsLen.size; if (self->userAgentNum) { self->userAgents = malloc(sizeof(*self->userAgents) * self->userAgentNum); for (int x = 0; x < self->userAgentNum; x++) { // Add each user agent checking each time for space in the payload. // No need to check space as there is enough data afterwards for safety. CBVarInt userAgentLen = CBByteArrayReadVarInt(bytes, cursor); cursor += userAgentLen.size; if (payloadLen.val < 7 + cursor + userAgentLen.val + self->userAgentNum - x - payloadLen.size) { // 7 for priority and 3 strings. The current user agent size and the rest as if empty strings. CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the cancel set and the user agent set up to user agent %" PRIu16 ".", x); return CB_DESERIALISE_ERROR; } // Enough space so set user agent if (userAgentLen.val){ self->userAgents[x] = CBNewByteArraySubReference(bytes, cursor, (int)userAgentLen.val); CBByteArraySanitise(self->userAgents[x]); }else self->userAgents[x] = NULL; cursor += userAgentLen.val; } } self->priority = CBByteArrayReadInt32(bytes, cursor); cursor += 4; // Strings. Make sure to check the first byte in the var ints to ensure enough space int size = CBByteArrayReadVarIntSize(bytes, cursor); if (payloadLen.val < cursor + size + 2u - payloadLen.size) { CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the hidden string var int."); return CB_DESERIALISE_ERROR; } CBVarInt hiddenCommentLen = CBByteArrayReadVarInt(bytes, cursor); cursor += size; if (payloadLen.val < cursor + hiddenCommentLen.val + 2 - payloadLen.size) { CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the hidden string."); return CB_DESERIALISE_ERROR; } self->hiddenComment = hiddenCommentLen.val ? CBNewByteArraySubReference(bytes, cursor, (int)hiddenCommentLen.val) : NULL; cursor += hiddenCommentLen.val; // Displayed string. size = CBByteArrayReadVarIntSize(bytes, cursor); if (payloadLen.val >= cursor + size + 1u - payloadLen.size) { CBVarInt displayedCommentLen = CBByteArrayReadVarInt(bytes, cursor); cursor += size; if (payloadLen.val >= cursor + displayedCommentLen.val + 1 - payloadLen.size) { self->displayedComment = displayedCommentLen.val ? CBNewByteArraySubReference(bytes, cursor, (int)displayedCommentLen.val) : NULL; cursor += displayedCommentLen.val; // Reserved string size = CBByteArrayReadVarIntSize(bytes, cursor); if (payloadLen.val >= cursor + size - payloadLen.size) { CBVarInt reservedLen = CBByteArrayReadVarInt(bytes, cursor); cursor += size; if (payloadLen.val == cursor + reservedLen.val - payloadLen.size) { self->reserved = reservedLen.val ? CBNewByteArraySubReference(bytes, cursor, (int)reservedLen.val) : NULL; cursor += reservedLen.val; // Finally do signature size = CBByteArrayReadVarIntSize(bytes, cursor); if (bytes->length >= cursor + size) { CBVarInt sigLen = CBByteArrayReadVarInt(bytes, cursor); cursor += size; if (bytes->length >= cursor + sigLen.val){ self->payload = CBNewByteArraySubReference(bytes, payloadLen.size, (int)payloadLen.val); self->signature = CBNewByteArraySubReference(bytes, cursor, (int)sigLen.val); // Done signature OK. Now return successfully. return cursor += sigLen.val; }else CBLogError("Attempting to deserialise a CBAlert with a byte array length smaller than required to cover the signature."); }else CBLogError("Attempting to deserialise a CBAlert with a byte array length smaller than required to cover the signature var int."); // Did not pass signature. Release third string. if (self->reserved) CBReleaseObject(self->reserved); }else CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the reserved string."); }else CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the reserved string var int."); // Did not pass third string. Release second. if (self->displayedComment) CBReleaseObject(self->displayedComment); }else CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the displayed string. %" PRIu64 " < %" PRIu64, payloadLen.val, cursor + displayedCommentLen.val + 1); }else CBLogError("Attempting to deserialise a CBAlert with a payload var int smaller than required to cover the displayed string var int."); // Did not pass second string. Release first. if (self->hiddenComment) CBReleaseObject(self->hiddenComment); // Error return CB_DESERIALISE_ERROR; }
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. }