Exemple #1
0
def test_rivine_types():
    e = encoder_rivine_get()

    # in the rivine_basic test we saw we can
    # serialise anything using the add method.
    # One can however also directly encode the specific type as desired,
    # which allows for example the encoding of an integer as a specific byte size.
    e.add_int8(1)
    e.add_int16(2)
    e.add_int24(3)
    e.add_int32(4)
    e.add_int64(5)

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

    # 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])

    # the result is a single bytearray
    assert e.data == b'\x01\x02\x00\x03\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x0642\x00\x01\x01'
Exemple #2
0
    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_rivine_get()

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

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

        # encode the public key
        e.add_all(self.public_key)

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

        # encode coin inputs
        e.add(len(self.coin_inputs))
        for ci in self.coin_inputs:
            e.add(ci.parentid)

        # encode registration and transaction fee
        e.add_all(self.registration_fee, self.transaction_fee)

        # encode refund coin output
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return data
        return e.data
Exemple #3
0
def test_rivine_limits():
    e = encoder_rivine_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)
    with pytest.raises(IntegerOutOfRange):
        e.add_int64(-1)
    with pytest.raises(IntegerOutOfRange):
        e.add_int32(-1)
    with pytest.raises(IntegerOutOfRange):
        e.add_int24(-1)
    with pytest.raises(IntegerOutOfRange):
        e.add_int16(-1)
    with pytest.raises(IntegerOutOfRange):
        e.add_int8(-1)

    # integers have upper limits as well
    with pytest.raises(IntegerOutOfRange):
        e.add(1 << 64)
    with pytest.raises(IntegerOutOfRange):
        e.add_int64(1 << 64)
    with pytest.raises(IntegerOutOfRange):
        e.add_int32(1 << 32)
    with pytest.raises(IntegerOutOfRange):
        e.add_int24(1 << 24)
    with pytest.raises(IntegerOutOfRange):
        e.add_int16(1 << 16)
    with pytest.raises(IntegerOutOfRange):
        e.add_int8(1 << 8)
Exemple #4
0
 def _checksum(self):
     if self._type == UnlockHashType.NIL:
         return b'\x00'*UnlockHash._CHECKSUM_SIZE
     e = encoder_rivine_get()
     e.add_int8(int(self._type))
     e.add(self._hash)
     return bytearray.fromhex(blake2_string(e.data))
Exemple #5
0
 def sia_binary_encode(self, encoder):
     """
     Sia binary encoding uses the Rivine Encoder for binary-encoding
     a network address, as it is only supported for backwards compatibility.
     """
     renc = encoder_rivine_get()
     self.rivine_binary_encode_data(renc)
     encoder.add_array(renc.data)
Exemple #6
0
 def sia_binary_encode(self, encoder):
     """
     Sia binary encodes a BotMonthsAndFlagsData as a one-byte flag,
     uses the Rivine Encoder. See rivine_binary_encode for more information.
     """
     e = encoder_rivine_get()
     self.rivine_binary_encode(e)
     encoder.add_array(e.data)
 def rivine_binary_encode(self, encoder):
     """
     Encode this Fulfillment according to the Rivine Binary Encoding format.
     """
     encoder.add_int8(int(self.type))
     data_enc = encoder_rivine_get()
     self.rivine_binary_encode_data(data_enc)
     encoder.add_slice(data_enc.data)
Exemple #8
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)
Exemple #9
0
def test_rivine_basic_encoding():
    e = encoder_rivine_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\x02a\x06\x01\x00\x00\x00\x00\x00\x00\x00\x01\x06foo\x06123'
Exemple #10
0
    def _binary_encode_data(self):
        e = encoder_rivine_get()
        # encode all properties
        e.add_all(
            self.address,
            self.value,
            self.transaction_fee,
            self.blockid,
            self.transactionid,
        )

        # return encoded data
        return e.data
Exemple #11
0
    def _binary_encode_data(self):
        e = encoder_rivine_get()

        # get addresses and names
        addresses_to_add = self.addresses_to_add
        addresses_to_remove = self.addresses_to_remove
        names_to_add = self.names_to_add
        names_to_remove = self.names_to_remove
        addresses_to_add_length = len(addresses_to_add)
        addresses_to_remove_length = len(addresses_to_remove)
        names_to_add_length = len(names_to_add)
        names_to_remove_length = len(names_to_remove)

        # encode the identifier
        e.add_int32(self.botid)

        # encode bot binary encoding prefix (containing length and refund info)
        maf = BotMonthsAndFlagsData(
            number_of_months=self.number_of_months,
            has_addresses=(addresses_to_add_length > 0
                           or addresses_to_remove_length > 0),
            has_names=(names_to_add_length > 0 or names_to_remove_length > 0),
            has_refund=(self._refund_coin_output is not None),
        )
        e.add(maf)

        # if we have addresses, encode it
        if maf.has_addresses:
            e.add_int8(addresses_to_add_length
                       | (addresses_to_remove_length << 4))
            e.add_array(addresses_to_add)
            e.add_array(addresses_to_remove)

        # if we have names, encode it
        if maf.has_names:
            e.add_int8(names_to_add_length | (names_to_remove_length << 4))
            e.add_array(names_to_add)
            e.add_array(names_to_remove)

        # encode transaction fee and coin inputs
        e.add_all(self.transaction_fee, self.coin_inputs)

        # encode refund coin output, if defined
        if maf.has_refund:
            e.add(self._refund_coin_output)

        # encode the signature at the end
        e.add(self.signature)

        # return encoded data
        return e.data
Exemple #12
0
    def _binary_encode_data(self):
        e = encoder_rivine_get()
        # encode all easy properties
        e.add_all(self.public_key, self.signature, self.registration_fee,
                  self.transaction_fee, self.coin_inputs)
        # encode the only "pointer" property
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return encoded data
        return e.data
Exemple #13
0
    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_rivine_get()

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

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

        # encode the botID
        e.add_int32(self.botid)

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

        # encode addresses, names and number of months
        e.add_all(self.addresses_to_add, self.addresses_to_remove)
        e.add_all(self.names_to_add, self.names_to_remove)
        e.add_int8(self.number_of_months)

        # encode coin inputs
        e.add(len(self.coin_inputs))
        for ci in self.coin_inputs:
            e.add(ci.parentid)

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

        # encode refund coin output
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return data
        return e.data
Exemple #14
0
    def _binary_encode_data(self):
        e = encoder_rivine_get()

        # get names
        names = self.names
        names_length = len(names)
        info_value = names_length

        # get has refund status
        has_refund = False
        if self._refund_coin_output is not None:
            has_refund = True
            info_value |= 16

        # encode sender bot info
        e.add_int32(self.sender_botid)
        e.add(self.sender_signature)

        # encode receiver bot info
        e.add_int32(self.receiver_botid)
        e.add(self.receiver_signature)

        # encode info value
        e.add_int8(info_value)

        # encode the names
        e.add_array(names)
        
        # encode transaction fee and coin inputs
        e.add_all(self.transaction_fee, self.coin_inputs)

        # encode refund coin output, if defined
        if has_refund:
            e.add(self._refund_coin_output)

        # return encoded data
        return e.data
Exemple #15
0
    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_rivine_get()

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

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

        # encode the bot identifiers
        e.add_int32(self.sender_botid)
        e.add_int32(self.receiver_botid)

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

        # encode names
        e.add(self.names)

        # encode coin inputs
        e.add(len(self.coin_inputs))
        for ci in self.coin_inputs:
            e.add(ci.parentid)

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

        # encode refund coin output
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return data
        return e.data
Exemple #16
0
def test_rivine_custom():
    e = encoder_rivine_get()

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

        def rivine_binary_encode(self, encoder):
            if self._number % 2 != 0:
                return encoder.add_int24(self._number - 1)
            return encoder.add_int24(self._number)

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

    # 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\x00\x00\x2A\x00\x00\x04\x00\x00\x02\x00\x00'
Exemple #17
0
    def _binary_encode_data(self):
        e = encoder_rivine_get()

        # get addresses and names
        addresses = self.addresses
        names = self.names
        addresses_length = len(addresses)
        names_length = len(names)

        # encode bot binary encoding prefix (containing length and refund info)
        maf = BotMonthsAndFlagsData(
            number_of_months=self.number_of_months,
            has_addresses=(addresses_length>0),
            has_names=(names_length>0),
            has_refund=(self._refund_coin_output is not None),
        )
        e.add(maf)
        # encode the address and name length
        e.add_int8(addresses_length | (names_length<< 4))
        
        # encode all addresses and names
        e.add_array(addresses)
        e.add_array(names)
        
        # encode transaction fee and coin inputs
        e.add_all(self.transaction_fee, self.coin_inputs)

        # encode refund coin output, if defined
        if maf.has_refund:
            e.add(self._refund_coin_output)
    
        # encode the identification at the end
        e.add_all(self.public_key, self.signature)

        # return encoded data
        return e.data
 def test_rivine_encoded(obj, expected):
     test_encoded(encoder_rivine_get(), obj, expected)