예제 #1
0
    def unmarshal_with_remainder(cls, raw: bytes):
        """Returns a new FactoidTransaction object, unmarshalling given bytes according to:
        https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#factoid-transaction

        Because FactoidTransaction is variable length, it is useful to pass a "stream" of bytes to be unmarshalled.
        This way, we don't have to know the size in advance. Just return the remainder bytes for the caller to use
        elsewhere.
        """
        data = raw[1:]  # skip single byte version, probably just 0x02 anyways
        timestamp, data = int.from_bytes(data[:6], "big",
                                         signed=False), data[6:]
        input_count, data = ord(data[:1]), data[1:]
        output_count, data = ord(data[:1]), data[1:]
        ec_purchase_count, data = ord(data[:1]), data[1:]

        inputs = []
        for i in range(input_count):
            value, data = varint.decode(data)
            fct_address, data = data[:32], data[32:]
            inputs.append({"value": value, "fct_address": fct_address})

        outputs = []
        for i in range(output_count):
            value, data = varint.decode(data)
            fct_address, data = data[:32], data[32:]
            outputs.append({"value": value, "fct_address": fct_address})

        ec_purchases = []
        for i in range(ec_purchase_count):
            value, data = varint.decode(data)
            ec_public_key, data = data[:32], data[32:]
            ec_purchases.append({
                "value": value,
                "ec_public_key": ec_public_key
            })

        rcds = primitives.FullSignatureList()
        for i in range(input_count):
            data = data[1:]  # skip 1 byte version number, always 0x01 for now
            signature, data = primitives.FullSignature.unmarshal(
                data[:96]), data[96:]
            rcds.append(signature)

        return (
            FactoidTransaction(
                timestamp=timestamp,
                inputs=inputs,
                outputs=outputs,
                ec_purchases=ec_purchases,
                rcds=rcds,
            ),
            data,
        )
예제 #2
0
    def unmarshal_with_remainder(cls, raw: bytes):
        """
        Unmarshal the byte representation into a new object and return the remaining bytes

        :param raw: marshalled bytes of the message
        :return: a tuple of (new CoinbaseDescriptorCancel message object, remaining bytes)
        """
        message_size, data = varint.decode(raw)
        message_data, data = data[:message_size], data[message_size:]
        descriptor_height, message_data = varint.decode(message_data)
        descriptor_index, message_data = message_data[:32], message_data[32:]
        assert len(message_data) == 0, "Extra bytes remaining in message data!"
        return CoinbaseDescriptorCancel(descriptor_height,
                                        descriptor_index), data
예제 #3
0
    def unmarshal_with_remainder(cls, raw: bytes):
        chain_id, data = raw[:32], raw[32:]
        assert chain_id == EntryCreditBlockHeader.CHAIN_ID
        body_hash, data = data[:32], data[32:]
        prev_header_hash, data = data[:32], data[32:]
        prev_full_hash, data = data[:32], data[32:]
        height, data = struct.unpack(">I", data[:4])[0], data[4:]

        header_expansion_size, data = varint.decode(data)
        header_expansion_area, data = (
            data[:header_expansion_size],
            data[header_expansion_size:],
        )

        object_count, data = struct.unpack(">Q", data[:8])[0], data[8:]
        body_size, data = struct.unpack(">Q", data[:8])[0], data[8:]

        return (
            EntryCreditBlockHeader(
                body_hash=body_hash,
                prev_header_hash=prev_header_hash,
                prev_full_hash=prev_full_hash,
                height=height,
                expansion_area=header_expansion_area,
                object_count=object_count,
                body_size=body_size,
            ),
            data,
        )
예제 #4
0
    def unmarshal_with_remainder(cls, raw: bytes):
        """
        Unmarshal the byte representation into a new object and return the remaining bytes

        :param raw: marshalled bytes of the message
        :return: a tuple of (new CoinbaseDescriptor message object, remaining bytes)
        """
        message_size, data = varint.decode(raw)
        message_data, data = data[:message_size], data[message_size:]
        outputs = []
        while len(message_data) > 0:
            value, message_data = varint.decode(message_data)
            fct_address, message_data = message_data[:32], message_data[32:]
            outputs.append({"value": value, "fct_address": fct_address})
        assert len(message_data) == 0, "Extra bytes remaining in message data!"
        return CoinbaseDescriptor(outputs), data
예제 #5
0
    def unmarshal_with_remainder(cls, raw: bytes):
        chain_id, data = raw[:32], raw[32:]
        assert chain_id == FactoidBlockHeader.CHAIN_ID
        body_mr, data = data[:32], data[32:]
        prev_keymr, data = data[:32], data[32:]
        prev_ledger_keymr, data = data[:32], data[32:]
        ec_exchange_rate, data = struct.unpack(">Q", data[:8])[0], data[8:]
        height, data = struct.unpack(">I", data[:4])[0], data[4:]

        header_expansion_size, data = varint.decode(data)
        header_expansion_area, data = (
            data[:header_expansion_size],
            data[header_expansion_size:],
        )

        tx_count, data = struct.unpack(">I", data[:4])[0], data[4:]
        body_size, data = struct.unpack(">I", data[:4])[0], data[4:]
        return (
            FactoidBlockHeader(
                body_mr=body_mr,
                prev_keymr=prev_keymr,
                prev_ledger_keymr=prev_ledger_keymr,
                ec_exchange_rate=ec_exchange_rate,
                height=height,
                expansion_area=header_expansion_area,
                tx_count=tx_count,
                body_size=body_size,
            ),
            data,
        )
예제 #6
0
    def unmarshal_with_remainder(cls, raw: bytes):
        """Returns a new BalanceIncrease object along with any remaining data, unmarshalling given bytes according to:
        https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#balance-increase

        Because BalanceIncrease is variable length, it is useful to pass a "stream" of bytes to be unmarshalled.
        This way, we don't have to know the size in advance. Just return the remainder bytes for the caller to use
        elsewhere.
        """
        ec_public_key, data = raw[:32], raw[32:]
        tx_id, data = data[:32], data[32:]
        index, data = varint.decode(data)
        quantity, data = varint.decode(data)

        return (
            BalanceIncrease(ec_public_key=ec_public_key,
                            tx_id=tx_id,
                            index=index,
                            quantity=quantity),
            data,
        )
예제 #7
0
    def unmarshal_with_remainder(cls, raw: bytes):
        chain_id, data = raw[:32], raw[32:]
        assert chain_id == AdminBlockHeader.CHAIN_ID
        prev_back_reference_hash, data = data[:32], data[32:]
        height, data = struct.unpack(">I", data[:4])[0], data[4:]

        expansion_size, data = varint.decode(data)
        expansion_area, data = data[:expansion_size], data[expansion_size:]
        # TODO: unmarshal header expansion area

        message_count, data = struct.unpack(">I", data[:4])[0], data[4:]
        body_size, data = struct.unpack(">I", data[:4])[0], data[4:]
        return (
            AdminBlockHeader(
                prev_back_reference_hash=prev_back_reference_hash,
                height=height,
                expansion_area=expansion_area,
                message_count=message_count,
                body_size=body_size,
            ),
            data,
        )
예제 #8
0
    def unmarshal(cls, raw: bytes):
        msg_type, data = raw[0], raw[1:]
        if msg_type != cls.TYPE:
            raise ValueError("Invalid message type ({})".format(msg_type))

        vm_index, data = data[0], data[1:]
        timestamp, data = data[:6], data[6:]
        salt, data = data[:8], data[8:]
        salt_number, data = struct.unpack(">I", data[:4])[0], data[4:]
        message_hash, data = data[:32], data[32:]
        full_message_hash, data = data[:32], data[32:]
        leader_chain_id, data = data[:32], data[32:]
        height, data = struct.unpack(">I", data[:4])[0], data[4:]
        process_list_height, data = struct.unpack(">I", data[:4])[0], data[4:]
        minute, data = data[0], data[1:]
        serial_hash, data = data[:32], data[32:]
        data_area_size, data = varint.decode(data)
        data_area, data = data[:data_area_size], data[data_area_size:]
        # TODO: unmarshal the data area in Ack message

        signature, data = primitives.FullSignature.unmarshal(
            data[:96]), data[96:]

        return Ack(
            vm_index=vm_index,
            timestamp=timestamp,
            salt=salt,
            salt_number=salt_number,
            message_hash=message_hash,
            full_message_hash=full_message_hash,
            leader_chain_id=leader_chain_id,
            height=height,
            process_list_height=process_list_height,
            minute=minute,
            serial_hash=serial_hash,
            data_area=data_area,
            signature=signature,
        )
예제 #9
0
 def test_decode(self):
     for expected_int, value_varint in TestVarInt.mapping.items():
         observed_int, remainder = varint.decode(value_varint)
         assert observed_int == expected_int, "{} != {}".format(
             observed_int, expected_int)
         assert len(remainder) == 0