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; }
uint16_t CBChainDescriptorDeserialise(CBChainDescriptor * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to deserialise a CBChainDescriptor with no bytes."); return 0; } if (bytes->length < 1) { CBLogError("Attempting to deserialise a CBChainDescriptor with no bytes"); return 0; } CBVarInt hashNum = CBVarIntDecode(bytes, 0); if (hashNum.val > 500) { CBLogError("Attempting to deserialise a CBChainDescriptor with a var int over 500."); return 0; } if (bytes->length < hashNum.size + hashNum.val * 32) { CBLogError("Attempting to deserialise a CBChainDescriptor with less bytes than required for the hashes."); return 0; } // Deserialise each hash self->hashes = malloc(sizeof(*self->hashes) * (size_t)hashNum.val); self->hashNum = hashNum.val; uint16_t cursor = hashNum.size; for (uint16_t x = 0; x < self->hashNum; x++) { self->hashes[x] = CBNewByteArraySubReference(bytes, cursor, 32); cursor += 32; } return cursor; }
CBByteArray * CBAlertGetPayload(CBAlert * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; CBVarInt payloadLen = CBByteArrayReadVarInt(bytes, 0); return CBNewByteArraySubReference(bytes, payloadLen.size, (int)payloadLen.val); }
bool CBAlertSerialisePayload(CBAlert * self) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBAlert with no bytes."); return false; } // Create varints and calculate length whilst at it. CBVarInt setCancelLen = CBVarIntFromUInt64(self->setCancelNum); CBVarInt userAgentLen = CBVarIntFromUInt64(self->userAgentNum); CBVarInt hiddenCommentLen = CBVarIntFromUInt64(self->hiddenComment ? self->hiddenComment->length : 0); CBVarInt displayedCommentLen = CBVarIntFromUInt64(self->displayedComment ? self->displayedComment->length : 0); CBVarInt reservedLen = CBVarIntFromUInt64(self->reserved ? self->reserved->length : 0); int length = 40 + setCancelLen.size + setCancelLen.val * 4 + userAgentLen.size + hiddenCommentLen.size + hiddenCommentLen.val + displayedCommentLen.size + displayedCommentLen.val + reservedLen.size + reservedLen.val; // Add user agents to length for (int x = 0; x < self->userAgentNum; x++) length += self->userAgents[x]->length + CBVarIntSizeOf(self->userAgents[x]->length); // So far length is for payload so make payload var int. CBVarInt payloadLen = CBVarIntFromUInt64(length); // Add the length of this var int. length += payloadLen.size; // Check length, with at least one byte for signature (could be 0 varint) if (bytes->length < length + 1) { CBLogError("Attempting to serialise a CBAlert with less bytes than required for the payload and a signature var int."); return false; } // Serialise the payload section. CBByteArraySetVarInt(bytes, 0, payloadLen); int cursor = payloadLen.size; CBByteArraySetInt32(bytes, cursor, self->version); cursor += 4; CBByteArraySetInt64(bytes, cursor, self->relayUntil); cursor += 8; CBByteArraySetInt64(bytes, cursor, self->expiration); cursor += 8; CBByteArraySetInt32(bytes, cursor, self->ID); cursor += 4; CBByteArraySetInt32(bytes, cursor, self->cancel); cursor += 4; // Cancel set CBByteArraySetVarInt(bytes, cursor, setCancelLen); cursor += setCancelLen.size; for (int x = 0; x < self->setCancelNum; x++) { CBByteArraySetInt32(bytes, cursor, self->setCancel[x]); cursor += 4; } CBByteArraySetInt32(bytes, cursor, self->minVer); cursor += 4; CBByteArraySetInt32(bytes, cursor, self->maxVer); cursor += 4; // User agent set CBByteArraySetVarInt(bytes, cursor, userAgentLen); cursor += userAgentLen.size; for (int x = 0; x < self->userAgentNum; x++) { CBVarInt aUserAgentLen = CBVarIntFromUInt64(self->userAgents[x]->length); CBByteArraySetVarInt(bytes, cursor, aUserAgentLen); cursor += aUserAgentLen.size; CBByteArrayCopyByteArray(bytes, cursor, self->userAgents[x]); CBByteArrayChangeReference(self->userAgents[x], bytes, cursor); cursor += aUserAgentLen.val; } CBByteArraySetInt32(bytes, cursor, self->priority); cursor += 4; // Hidden comment CBByteArraySetVarInt(bytes, cursor, hiddenCommentLen); cursor += hiddenCommentLen.size; if (self->hiddenComment) { CBByteArrayCopyByteArray(bytes, cursor, self->hiddenComment); CBByteArrayChangeReference(self->hiddenComment, bytes, cursor); cursor += hiddenCommentLen.val; } // Displayed comment CBByteArraySetVarInt(bytes, cursor, displayedCommentLen); cursor += displayedCommentLen.size; if (self->displayedComment) { CBByteArrayCopyByteArray(bytes, cursor, self->displayedComment); CBByteArrayChangeReference(self->displayedComment, bytes, cursor); cursor += displayedCommentLen.val; } // Reserved CBByteArraySetVarInt(bytes, cursor, reservedLen); cursor += reservedLen.size; if (self->reserved) { CBByteArrayCopyByteArray(bytes, cursor, self->reserved); CBByteArrayChangeReference(self->reserved, bytes, cursor); cursor += reservedLen.val; } self->payload = CBNewByteArraySubReference(bytes, payloadLen.size, cursor - payloadLen.size); return true; }
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. }