Ejemplo n.º 1
0
def test_sia_custom():
    e = SiaBinaryEncoder()

    # a class that provides a custom encoding logic for its types,
    # required in order to be able to encode Python objects
    class Answer(SiaBinaryObjectEncoderBase):
        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
    jsass.equals(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
    jsass.raises(IntegerOutOfRange, lambda _: e.add(-1))
Ejemplo n.º 2
0
 def _binary_encode_data(self):
     """
     Default Binary encoding of a Transaction Data,
     can be overriden if required.
     """
     encoder = SiaBinaryEncoder()
     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.º 3
0
def test_sia_basic_encoding():
    e = SiaBinaryEncoder()

    # 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
    jsass.equals(
        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.º 4
0
 def _id_new(self, specifier=None, index=None):
     encoder = SiaBinaryEncoder()
     if specifier != None:
         encoder.add_array(specifier)
     encoder.add_array(self._id_input_compute())
     if index != None:
         encoder.add_int(index)
     hash = blake2b(encoder.data)
     return Hash(value=hash)
 def sia_binary_encode(self, encoder):
     """
     Encode this Condition according to the Sia Binary Encoding format.
     """
     encoder.add_array(bytes([self.ctype]))
     data_enc = SiaBinaryEncoder()
     self.sia_binary_encode_data(data_enc)
     encoder.add_slice(data_enc.data)
Ejemplo n.º 6
0
 def sia_binary_encode(self, encoder):
     """
     Encode this Fulfillment according to the Sia Binary Encoding format.
     """
     encoder.add_array(bytearray([int(self.ftype)]))
     data_enc = SiaBinaryEncoder()
     self.sia_binary_encode_data(data_enc)
     encoder.add_slice(data_enc.data)
 def _custom_unlockhash_getter(self):
     e = RivineBinaryEncoder()
     self.sia_binary_encode_data(e)
     # need to encode again to add the length
     data = e.data
     e = SiaBinaryEncoder()
     e.add_slice(data)
     hash = jscrypto.blake2b(e.data)
     return UnlockHash(uhtype=UnlockHashType.ATOMIC_SWAP, uhhash=hash)
Ejemplo n.º 8
0
 def from_unlockhash(cls, unlockhash):
     """
     Create an ERC20 Address from a TFT Address (type: UnlockHash).
     """
     if isinstance(unlockhash, str):
         raise TypeError("unlockhash has to be already decoded from str before calling this func")
     e = SiaBinaryEncoder()
     unlockhash.sia_binary_encode(e)
     hash = jscrypto.blake2b(e.data)
     return cls(value=jsarr.slice_array(hash, Hash.SIZE-ERC20Address.SIZE))
Ejemplo n.º 9
0
def test_sia_types():
    e = SiaBinaryEncoder()

    # 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
    jsass.equals(e.data, b'\x00\x01\x01\x0642')
Ejemplo n.º 10
0
 def _binary_encode_data(self):
     encoder = SiaBinaryEncoder()
     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 jsarr.concat(bytearray([TransactionVersion.LEGACY.__int__()]), self._binary_encode_data())
     encoder = SiaBinaryEncoder()
     encoder.add_array(bytearray([TransactionVersion.STANDARD.__int__()]))
     encoder.add_slice(self._binary_encode_data())
     return encoder.data
Ejemplo n.º 12
0
 def unlockhash(self):
     """
     Return the unlock hash generated from this public key.
     """
     e = SiaBinaryEncoder()
     self.sia_binary_encode(e)
     # need to encode again to add the length
     data = e.data
     e = SiaBinaryEncoder()
     e.add_slice(data)
     hash = jscrypto.blake2b(e.data)
     return UnlockHash(uhtype=UnlockHashType.PUBLIC_KEY, uhhash=hash)
Ejemplo n.º 13
0
    def _legacy_signature_hash_input_get(self, *extra_objects):
        e = SiaBinaryEncoder()

        # 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.º 14
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 = SiaBinaryEncoder()
     # > 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 = SiaBinaryEncoder()
         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 = SiaBinaryEncoder()
         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.º 15
0
    def _signature_hash_input_get(self, *extra_objects):
        e = SiaBinaryEncoder()

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

        # 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.º 16
0
 def test_sia_encoded(obj, expected):
     test_encoded(SiaBinaryEncoder(), obj, expected)
Ejemplo n.º 17
0
    def _signature_hash_input_get(self, *extra_objects):
        if self._legacy:
            return self._legacy_signature_hash_input_get(*extra_objects)

        e = SiaBinaryEncoder()

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

        # 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