def get_broadcast_message_preview( self, input_buffer: InputBuffer) -> BroadcastMessagePreview: """ Peeks the hash and network number from hashed messages. Currently, only Broadcast messages are supported here. :param input_buffer :return: is full header, message hash, network number, source id, payload length """ # -1 for control flag length broadcast_header_length = self.base_message_type.HEADER_LENGTH + AbstractBroadcastMessage.PAYLOAD_LENGTH - \ constants.CONTROL_FLAGS_LEN is_full_header = input_buffer.length >= broadcast_header_length if not is_full_header: return BroadcastMessagePreview(False, None, None, None, None, None, None) else: _is_full_message, _command, payload_length = self.get_message_header_preview_from_input_buffer( input_buffer) broadcast_header = input_buffer.peek_message( broadcast_header_length) offset = self.base_message_type.HEADER_LENGTH block_hash = broadcast_header[offset:offset + crypto.SHA256_HASH_LEN] block_hash_with_network_num = broadcast_header[ offset:offset + crypto.SHA256_HASH_LEN + constants.NETWORK_NUM_LEN] offset += crypto.SHA256_HASH_LEN network_num, = struct.unpack_from( "<L", broadcast_header[offset:offset + constants.NETWORK_NUM_LEN]) offset += constants.NETWORK_NUM_LEN source_id = uuid_pack.from_bytes( struct.unpack_from( "<16s", broadcast_header[offset:offset + constants.NODE_ID_SIZE_IN_BYTES])[0]) offset += constants.NODE_ID_SIZE_IN_BYTES broadcast_type_bytearray = broadcast_header[offset:offset + constants. BROADCAST_TYPE_LEN] broadcast_type_in_str = struct.unpack_from( "<4s", broadcast_type_bytearray)[0].decode( constants.DEFAULT_TEXT_ENCODING) broadcast_type = BroadcastMessageType(broadcast_type_in_str) message_id = ConcatHash( bytearray(block_hash_with_network_num) + broadcast_type_bytearray, 0) return BroadcastMessagePreview(is_full_header, Sha256Hash(block_hash), broadcast_type, message_id, network_num, source_id, payload_length)
def _unpack_buffer(self): off = VersionMessage.BASE_LENGTH self._ip, self._port = message_utils.unpack_ip_port(self._memoryview[off:].tobytes()) off += constants.IP_ADDR_SIZE_IN_BYTES + constants.UL_SHORT_SIZE_IN_BYTES self._ordering, = struct.unpack_from("<L", self._memoryview, off) off += constants.UL_INT_SIZE_IN_BYTES _node_id, = struct.unpack_from("%ss" % constants.NODE_ID_SIZE_IN_BYTES, self._memoryview, off) self._node_id = uuid_pack.from_bytes(_node_id)
def source_id(self) -> str: if self._source_id is None: off = self.SOURCE_ID_OFFSET self._source_id = uuid_pack.from_bytes( struct.unpack_from("<16s", self.buf, off)[0]) if self._source_id is None: self._source_id = constants.DECODED_EMPTY_SOURCE_ID source_id = self._source_id assert source_id is not None return source_id
def origin_node_id(self) -> str: if self._origin_node_id is None: off = (self.HEADER_LENGTH + AbstractBroadcastMessage.PAYLOAD_LENGTH - constants.CONTROL_FLAGS_LEN) origin_node_id = uuid_pack.from_bytes( struct.unpack_from("<16s", self.buf, off)[0]) self._origin_node_id = origin_node_id origin_node_id = self._origin_node_id assert origin_node_id is not None return origin_node_id
def forwarding_node_id(self) -> str: if self._forwarding_node_id is None: off = (self.HEADER_LENGTH + AbstractBroadcastMessage.PAYLOAD_LENGTH - constants.CONTROL_FLAGS_LEN + constants.NODE_ID_SIZE_IN_BYTES) forwarding_node_id = uuid_pack.from_bytes( struct.unpack_from("<16s", self.buf, off)[0]) self._forwarding_node_id = forwarding_node_id forwarding_node_id = self._forwarding_node_id assert forwarding_node_id is not None return forwarding_node_id
class HelloMessage(VersionMessage): """ BloXroute relay hello message type. node_id: the id of the node """ MESSAGE_TYPE = BloxrouteMessageType.HELLO HELLO_MESSAGE_BLOCK = PayloadBlock( VersionMessage.BASE_LENGTH, "HelloMessage", PROTOCOL_VERSION, PayloadElement(name="node_id", structure="%ss" % constants.NODE_ID_SIZE_IN_BYTES, encode=lambda x: uuid_pack.to_bytes(x), decode=lambda x: uuid_pack.from_bytes(x))) HELLO_MESSAGE_LENGTH = VersionMessage.VERSION_MESSAGE_BLOCK.size + HELLO_MESSAGE_BLOCK.size + constants.CONTROL_FLAGS_LEN def __init__(self, protocol_version: Optional[int] = None, network_num: Optional[int] = None, node_id: str = None, buf: bytearray = None): if buf is None: buf = bytearray(self.HEADER_LENGTH + self.HELLO_MESSAGE_LENGTH) buf = self.HELLO_MESSAGE_BLOCK.build(buf, node_id=node_id) self.buf = buf self._node_id = None self._network_num = None self._memoryview = memoryview(buf) super(HelloMessage, self).__init__(self.MESSAGE_TYPE, self.HELLO_MESSAGE_LENGTH, protocol_version, network_num, buf) def __unpack(self): contents = self.HELLO_MESSAGE_BLOCK.read(self._memoryview) self._node_id = contents.get("node_id") def node_id(self): if self._node_id is None: self.__unpack() return self._node_id
def routing_update(self) -> List[str]: if self._routing_update is None: off = (self.HEADER_LENGTH + AbstractBroadcastMessage.PAYLOAD_LENGTH - constants.CONTROL_FLAGS_LEN + 2 * constants.NODE_ID_SIZE_IN_BYTES + crypto.SHA256_HASH_LEN) route_count, = struct.unpack_from("<I", self.buf, off) off += constants.UL_INT_SIZE_IN_BYTES routes = [] for _ in range(route_count): route_id = uuid_pack.from_bytes( struct.unpack_from("<16s", self.buf, off)[0]) off += constants.NODE_ID_SIZE_IN_BYTES routes.append(route_id) self._routing_update = routes routing_update = self._routing_update assert routing_update is not None return routing_update
def setUp(self): self.MESSAGE_BLOCK_HDR = PayloadBlock(0, "HDR", 0, PayloadElement(name="msg_type", structure="<12s",), PayloadElement(name="payload_len", structure="<L",) ) self.MESSAGE_BLOCK_VERSION = PayloadBlock(0, "VersionMessage", 0, self.MESSAGE_BLOCK_HDR, PayloadElement(structure="<L", name="protocol_version"), PayloadElement(structure="<L", name="network_num") ) self.MESSAGE_BLOCK_HELLO = PayloadBlock(0, "HelloMessage", 3, self.MESSAGE_BLOCK_VERSION, PayloadElement(name="node_id", structure="<16s", encode=lambda x: uuid_pack.to_bytes(x), decode=lambda x: uuid_pack.from_bytes(x)) ) self.kwargs = { "node_id": "31f93bcc-ad56-431f-9c14-28ffb0e8e41a", "msg_type": b"HelloMessage", "protocol_version": 3, "network_num": 12345 }
def test_hello_block_build_read(self): self.kwargs["payload_len"] = self.MESSAGE_BLOCK_HELLO.size - self.MESSAGE_BLOCK_HDR.size # build message buf = bytearray(self.MESSAGE_BLOCK_HELLO.size) self.MESSAGE_BLOCK_HELLO.build(buf=buf, **self.kwargs) # verify buffer msg_type, payload_len, protocol_version, network_num, node_id = struct.unpack_from("<12sLLL16s", buf) self.assertEqual(len(buf), self.MESSAGE_BLOCK_HELLO.size) self.assertEqual(msg_type, b"HelloMessage") self.assertEqual(payload_len, 24) self.assertEqual(protocol_version, 3) self.assertEqual(network_num, 12345) self.assertEqual(uuid_pack.from_bytes(node_id), "31f93bcc-ad56-431f-9c14-28ffb0e8e41a") # verify read result = self.MESSAGE_BLOCK_HELLO.read(buf) for item in self.MESSAGE_BLOCK_HELLO: self.assertEqual(result.pop(item.name), self.kwargs.pop(item.name)) self.assertFalse(self.kwargs) # check that all inputs were matched to the outputs self.assertFalse(result) # check that all outputs were matched to the inputs
from bxcommon.messages.bloxroute.block_holding_message import BlockHoldingMessage from bxcommon.messages.bloxroute.bloxroute_version_manager import bloxroute_version_manager from bxcommon.messages.bloxroute.broadcast_message import BroadcastMessage from bxcommon.messages.bloxroute.key_message import KeyMessage from bxcommon.messages.bloxroute.tx_message import TxMessage from bxcommon.messages.bloxroute.v5.block_holding_message_v5 import BlockHoldingMessageV5 from bxcommon.messages.bloxroute.v5.broadcast_message_converter_v5 import broadcast_message_converter_v5 from bxcommon.messages.bloxroute.v5.broadcast_message_v5 import BroadcastMessageV5 from bxcommon.messages.bloxroute.v5.key_message_v5 import KeyMessageV5 from bxcommon.messages.bloxroute.v5.tx_message_v5 import TxMessageV5 from bxcommon.test_utils import helpers from bxcommon.test_utils.abstract_test_case import AbstractTestCase from bxcommon.utils import crypto, uuid_pack from bxcommon.utils.object_hash import Sha256Hash NEW_VERSION_SOURCE_ID = uuid_pack.from_bytes(b"\x01" * 16) EMPTY_SOURCE_ID_STR = EMPTY_SOURCE_ID.decode() class BloxrouteVersionManagerV5Test(AbstractTestCase): def test_tx_message(self): tx_hash = Sha256Hash(helpers.generate_bytes(crypto.SHA256_HASH_LEN)) tx_contents = helpers.generate_bytes(250) network_num = 1234 self._test_to_old_version( TxMessage(message_hash=tx_hash, network_num=network_num, source_id=NEW_VERSION_SOURCE_ID, tx_val=tx_contents)) self._test_to_new_version( TxMessageV5(tx_hash=tx_hash,