Example #1
0
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;
}
Example #2
0
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;
	
}
Example #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;
}
Example #4
0
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;
}
Example #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.
}