Ejemplo n.º 1
0
 def _binary_encode_data(self):
     if not self._legacy:
         return super()._binary_encode_data()
     # encoding was slightly different in legacy transactions (v0)
     # (NOTE: we only support the subset of v0 transactions that are actually active on the tfchain network)
     encoder = encoder_sia_get()
     # > encode coin inputs
     encoder.add_int(len(self.coin_inputs))
     for ci in self.coin_inputs:
         encoder.add(ci.parentid)
         encoder.add_array(bytearray([1]))  # FulfillmentTypeSingleSignature
         sub_encoder = encoder_sia_get()
         sub_encoder.add(ci.fulfillment.public_key)
         encoder.add_slice(sub_encoder.data)
         encoder.add(ci.fulfillment.signature)
     # > encode coin outputs
     encoder.add_int(len(self.coin_outputs))
     for co in self.coin_outputs:
         encoder.add_all(co.value, co.condition.unlockhash)
     # > encode block stake inputs
     encoder.add_int(len(self._blockstake_inputs))
     for bsi in self._blockstake_inputs:
         encoder.add(bsi.parentid)
         encoder.add_array(bytearray([1]))  # FulfillmentTypeSingleSignature
         sub_encoder = encoder_sia_get()
         sub_encoder.add(bsi.fulfillment.public_key)
         encoder.add_slice(sub_encoder.data)
         encoder.add(bsi.fulfillment.signature)
     # > encode block stake outputs
     encoder.add_int(len(self._blockstake_outputs))
     for bso in self.blockstake_outputs:
         encoder.add_all(bso.value, bso.condition.unlockhash)
     # > encode miner fees and arbitrary data
     encoder.add_all(self.miner_fees, self.data)
     return encoder.data
Ejemplo n.º 2
0
 def unlockhash(self):
     """
     Return the unlock hash generated from this public key.
     """
     e = encoder_sia_get()
     self.sia_binary_encode(e)
     # need to encode again to add the length
     data = e.data
     e = encoder_sia_get()
     e.add_slice(data)
     hash = bytearray.fromhex(blake2_string(e.data))
     return UnlockHash(type=UnlockHashType.PUBLIC_KEY, hash=hash)
Ejemplo n.º 3
0
def test_sia_custom():
    e = encoder_sia_get()

    # a class that provides a custom encoding logic for its types,
    # required in order to be able to encode Python objects
    class Answer(BaseSiaObjectEncoder):
        def __init__(self, number=0):
            self._number = number

        def sia_binary_encode(self, encoder):
            if self._number == 42:
                return encoder.add(True)
            return encoder.add(False)

    # when we add our objects they will be encoded
    # using the method as provided by its type
    e.add(Answer())
    e.add(Answer(42))

    # this works for slices and arrays as well
    e.add_array([Answer(5), Answer(2)])

    # the result is a single bytearray
    assert e.data == b'\x00\x01\x00\x00'

    # everything has limits, so do types,
    # that is what this test is about

    # no integer can be negative
    with pytest.raises(IntegerOutOfRange):
        e.add(-1)
    # integers have an upper bound
    with pytest.raises(IntegerOutOfRange):
        e.add(1 << 64)
Ejemplo n.º 4
0
    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_sia_get()

        # encode the transaction version
        e.add_byte(self.version)

        # encode the specifier
        e.add_array(TransactionV129._SPECIFIER)

        # encode nonce
        e.add_array(self._nonce.value)

        # extra objects if any
        if extra_objects:
            e.add_all(*extra_objects)

        # encode coin outputs
        e.add_slice(self.coin_outputs)

        # encode miner fees
        e.add_slice(self.miner_fees)

        # encode custom data
        e.add(self.data)

        # return the encoded data
        return e.data
Ejemplo n.º 5
0
 def _outputid_new(self, specifier, index):
     encoder = encoder_sia_get()
     encoder.add_array(specifier)
     encoder.add_array(self._id_input_compute())
     encoder.add_int(index)
     hash = bytearray.fromhex(blake2_string(encoder.data))
     return Hash(value=hash)
Ejemplo n.º 6
0
    def _legacy_signature_hash_input_get(self, *extra_objects):
        e = encoder_sia_get()

        # encode extra objects if exists
        if extra_objects:
            e.add_all(*extra_objects)

        # encode coin inputs
        for ci in self.coin_inputs:
            e.add_all(ci.parentid, ci.fulfillment.public_key.unlockhash)

        # encode coin outputs
        e.add(len(self.coin_outputs))
        for co in self.coin_outputs:
            e.add_all(co.value, co.condition.unlockhash)

        # encode blockstake inputs
        for bsi in self.blockstake_inputs:
            e.add_all(bsi.parentid, bsi.fulfillment.public_key.unlockhash)

        # encode blockstake outputs
        e.add(len(self.blockstake_outputs))
        for bso in self.blockstake_outputs:
            e.add_all(bso.value, bso.condition.unlockhash)

        # encode miner fees
        e.add_slice(self.miner_fees)

        # encode custom data
        e.add(self.data)

        # return the encoded data
        return e.data
Ejemplo n.º 7
0
 def sia_binary_encode(self, encoder):
     """
     Encode this Fulfillment according to the Sia Binary Encoding format.
     """
     encoder.add_array(bytearray([int(self.type)]))
     data_enc = encoder_sia_get()
     self.sia_binary_encode_data(data_enc)
     encoder.add_slice(data_enc.data)
Ejemplo n.º 8
0
 def from_unlockhash(cls, unlockhash):
     """
     Create an ERC20 Address from a TFT Address (type: UnlockHash).
     """
     e = encoder_sia_get()
     unlockhash.sia_binary_encode(e)
     hash = bytes.fromhex(blake2_string(e.data))
     return cls(value=hash[Hash.SIZE - ERC20Address.SIZE:])
Ejemplo n.º 9
0
 def unlockhash(self):
     e = encoder_rivine_get()
     self.sia_binary_encode_data(e)
     # need to encode again to add the length
     data = e.data
     e = encoder_sia_get()
     e.add_slice(data)
     hash = bytearray.fromhex(blake2_string(e.data))
     return UnlockHash(type=UnlockHashType.ATOMIC_SWAP, hash=hash)
Ejemplo n.º 10
0
 def _binary_encode_data(self):
     encoder = encoder_sia_get()
     encoder.add_array(self._nonce.value)
     encoder.add_all(
         self.mint_fulfillment,
         self.coin_outputs,
         self.miner_fees,
         self.data,
     )
     return encoder.data
Ejemplo n.º 11
0
 def binary_encode(self):
     """
     Binary encoding of a Transaction,
     overriden to specify the version correctly
     """
     if self._legacy:
         return bytearray([int(TransactionVersion.LEGACY)]) + self._binary_encode_data()
     encoder = encoder_sia_get()
     encoder.add_array(bytearray([int(TransactionVersion.STANDARD)]))
     encoder.add_slice(self._binary_encode_data())
     return encoder.data
Ejemplo n.º 12
0
def test_sia_basic_encoding():
    e = encoder_sia_get()

    # you can add integers, booleans, iterateble objects, strings,
    # bytes and byte arrays. Dictionaries and objects are not supported.
    e.add(False)
    e.add("a")
    e.add([1, True, "foo"])
    e.add(b"123")

    # the result is a single bytearray
    assert e.data == b'\x00\x01\x00\x00\x00\x00\x00\x00\x00a\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00foo\x03\x00\x00\x00\x00\x00\x00\x00123'
Ejemplo n.º 13
0
def test_sia_custom():
    e = encoder_sia_get()

    # everything has limits, so do types,
    # that is what this test is about

    # no integer can be negative
    with pytest.raises(IntegerOutOfRange):
        e.add(-1)
    # integers have an upper bound
    with pytest.raises(IntegerOutOfRange):
        e.add(1 << 64)
Ejemplo n.º 14
0
 def _binary_encode_data(self):
     """
     Default Binary encoding of a Transaction Data,
     can be overriden if required.
     """
     encoder = encoder_sia_get()
     encoder.add_all(
         self.coin_inputs,
         self.coin_outputs,
         self.blockstake_inputs,
         self.blockstake_outputs,
         self.miner_fees,
         self.data,
     )
     return encoder.data
Ejemplo n.º 15
0
    def _signature_hash_input_get(self, *extra_objects):
        if self._legacy:
            return self._legacy_signature_hash_input_get(*extra_objects)

        e = encoder_sia_get()

        # encode the transaction version
        e.add_byte(self.version)

        # encode extra objects if exists
        if extra_objects:
            e.add_all(*extra_objects)

        # encode the number of coins inputs
        e.add(len(self.coin_inputs))
        # encode coin inputs parent_ids
        for ci in self.coin_inputs:
            e.add(ci.parentid)

        # encode coin outputs
        e.add_slice(self.coin_outputs)

        # encode the number of blockstake inputs
        e.add(len(self.blockstake_inputs))
        # encode blockstake inputs parent_ids
        for bsi in self.blockstake_inputs:
            e.add(bsi.parentid)

        # encode blockstake outputs
        e.add_slice(self.blockstake_outputs)

        # encode miner fees
        e.add_slice(self.miner_fees)

        # encode custom data
        e.add(self.data)

        # return the encoded data
        return e.data
Ejemplo n.º 16
0
def test_sia_types():

    e = encoder_sia_get()

    # in the sia_basic test we saw we can
    # serialise anything using the add method.

    # by default strings, byte arrays and iterateable objects
    # are encoded as slices.
    #
    # array are like slices, but have no length prefix,
    # therefore this is only useful if there is a fixed amount of elements,
    # known by all parties
    e.add_array([False, True, True])

    # a single byte can be added as well
    e.add_byte(6)
    e.add_byte('4')
    e.add_byte(b'2')

    # the result is a single bytearray
    assert e.data == b'\x00\x01\x01\x0642'
Ejemplo n.º 17
0
def test_sia_custom():
    e = encoder_sia_get()

    # a class that provides a custom encoding logic for its types,
    # required in order to be able to encode Python objects
    class Answer(BaseSiaObjectEncoder):
        def __init__(self, number=0):
            self._number = number

        def sia_binary_encode(self, encoder):
            if self._number == 42:
                return encoder.add(True)
            return encoder.add(False)

    # when we add our objects they will be encoded
    # using the method as provided by its type
    e.add(Answer())
    e.add(Answer(42))

    # this works for slices and arrays as well
    e.add_array([Answer(5), Answer(2)])

    # the result is a single bytearray
    assert e.data == b'\x00\x01\x00\x00'
Ejemplo n.º 18
0
    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_sia_get()

        # encode the transaction version
        e.add_array(bytearray([int(self.version)]))

        # encode the specifier
        e.add_array(TransactionV209._SPECIFIER)

        # extra objects if any
        if extra_objects:
            e.add_all(*extra_objects)

        # encode the address and value
        e.add_all(self.address, self.value)

        # encode transaction fee
        e.add_all(self.transaction_fee)

        # encode the block- and transaction identifier
        e.add_all(self.blockid, self.transactionid)

        # return data
        return e.data
 def test_sia_encoded(obj, expected):
     test_encoded(encoder_sia_get(), obj, expected)