Пример #1
0
    def test_simple_transfer(self):
        EXPECTED_DIGEST = "257c5e1de3a0a895d66d57792f1a44425336bb05bc6c8479be83b4572e1b4d45"
        EXPECTED_PAYLOAD = \
            "a1640000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d44235130ac5aab442e39f" \
            "9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010000000000000000000000000418c2a33af8bd2cba7f" \
            "a714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758b" \
            "cc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 256)
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        payload.sign(ENTITIES[0])

        transaction_bytes = transaction.encode_transaction(payload)
        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)
        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #2
0
    def post_test(self, function: Callable, action: str,
                  factory_function: Callable, entity: Entity, *args):
        with patch('fetchai.ledger.api.TokenApi._post_tx_json') as mock_post, \
                patch('fetchai.ledger.api.token.TokenTxFactory.' + factory_function.__name__,
                      autospec=factory_function) as mock_factory, \
                patch('fetchai.ledger.api.TokenApi._set_validity_period') as mock_set_valid, \
                patch('warnings.warn') as mock_warnings, \
                patch('fetchai.ledger.serialisation.transaction.encode_transaction') as mock_encode:
            # the transaction factory should generate a known transaction
            tx = Transaction()
            tx.sign = MagicMock()
            tx.sign.side_effect = [None]
            mock_factory.side_effect = [tx]

            mock_post.side_effect = ['result']
            mock_encode.side_effect = ['encoded']

            # run the production code
            result = function(entity, *args)

            mock_factory.assert_called_once_with(entity, *args, [entity])
            mock_set_valid.assert_called_once_with(tx)
            tx.sign.assert_called_once_with(entity)
            mock_encode.assert_called_once_with(tx)
            mock_post.assert_called_once_with('encoded', action)
            self.assertEqual(result, 'result')
Пример #3
0
    def transfer(self, entity: Entity, to: AddressLike, amount: int, fee: int):
        """
        Transfers wealth from one account to another account

        :param private_key_bin: The bytes of the private key of the source address
        :param to_address: The bytes of the targeted address to send funds to
        :param amount: The amount of funds being transfered
        :param fee: The fee associated with the transfer
        :return: The digest of the submitted transaction
        :raises: ApiError on any failures
        """
        ENDPOINT = 'transfer'

        # format the data to be closed by the transaction

        # wildcard for the moment
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(entity)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = fee
        tx.add_transfer(to, amount)
        tx.add_signer(entity)

        # encode and sign the transaction
        encoded_tx = encode_transaction(tx, [entity])

        # submit the transaction
        return self._post_tx_json(encoded_tx, ENDPOINT)
Пример #4
0
 def _create_skeleton_tx(self, fee: int, validity_period: Optional[int] = None):
     # build up the basic transaction information
     tx = Transaction()
     tx.charge_rate = 1
     tx.charge_limit = fee
     self._set_validity_period(tx, validity_period)
     return tx
Пример #5
0
    def _set_validity_period(self, tx: Transaction, validity_period: Optional[int] = None):
        validity_period = validity_period or DEFAULT_BLOCK_VALIDITY_PERIOD

        # query what the current block number is on the node
        current_block = self.current_block_number()

        # populate both the valid from and valid until
        tx.valid_from = current_block
        tx.valid_until = current_block + validity_period
        return tx.valid_until
Пример #6
0
    def test_multiple_transfers(self):
        EXPECTED_DIGEST = "7e6a95a8c773755d349209d8f3bb60ec2a5f3c683075540f953863f124eb1250"
        EXPECTED_PAYLOAD = \
            "a1460000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4014235130ac5aab442e3" \
            "9f9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010020f478c7f74b50c187bf9a8836f382bd62977bae" \
            "eaf19625608e7e912aa60098c10200da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af" \
            "6dc2000186a000000000000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe" \
            "08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 256)
        payload.add_transfer(IDENTITIES[2], 512)
        payload.add_transfer(IDENTITIES[3], 100000)
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Пример #7
0
    def _create_skeleton_tx(self, fee: int, validity_period: Optional[int] = None):
        validity_period = validity_period or DEFAULT_BLOCK_VALIDITY_PERIOD

        # query what the current block number is on the node
        current_block = self._current_block_number()

        # build up the basic transaction information
        tx = Transaction()
        tx.valid_until = current_block + validity_period
        tx.charge_rate = 1
        tx.charge_limit = fee

        return tx
Пример #8
0
    def test_merge_tx_signatures(self):
        payload = self.mstx.encode_payload()

        partials = []
        for signer in self.multi_sig_board:
            tx = Transaction.decode_payload(payload)
            tx.sign(signer)
            partials.append(tx.encode_partial())

        for partial in partials:
            _, partial_tx = Transaction.decode_partial(partial)
            self.assertTrue(self.mstx.merge_signatures(partial_tx))

        self.assertTrue(self.mstx.is_valid())
Пример #9
0
    def test_invalid_sig(self):
        self.mstx.add_signature(self.multi_sig_board[0], b'invalid')

        encoded = self.mstx.encode_partial()

        success, tx2 = Transaction.decode_partial(encoded)
        self.assertFalse(success)
        self.assertFalse(tx2.is_valid())
Пример #10
0
    def test_encoding_of_complete_tx(self):
        self.tx.sign(self.source_identity)
        self.assertFalse(self.tx.is_incomplete)

        encoded = self.tx.encode()
        recovered_tx = Transaction.decode(encoded)
        self.assertIsNotNone(recovered_tx)
        self.assertEqual(self.tx, recovered_tx)
Пример #11
0
    def test_simple_transfer(self):
        EXPECTED_DIGEST = "7fff24ca77fbb23b9b3c460104ab1a74011bafe3965e15dc6ea6f25a4ac44392"
        EXPECTED_PAYLOAD = \
            "a1440000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d44235130ac5aab442e39f" \
            "9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010000000000000000000000000418c2a33af8bd2cba7f" \
            "a714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758b" \
            "cc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 256)
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Пример #12
0
    def test_partial_serialize(self):
        self.mstx.sign(self.multi_sig_board[0])
        self.mstx.sign(self.multi_sig_board[2])
        self.assertEqual(len(self.mstx.present_signers), 2)

        encoded = self.mstx.encode_partial()

        success, tx2 = Transaction.decode_partial(encoded)

        self.assertFalse(success)  # not all the signatures are populated
        self.assertEqual(self.mstx, tx2)  # the body of the payload should be the same
        self.assertEqual(list(self.mstx.signatures),
                         list(tx2.signatures))  # the signature present should all be the same
        self.assertEqual(len(tx2.present_signers), 2)
Пример #13
0
    def test_multiple_transfers(self):
        EXPECTED_PAYLOAD = "a12600532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4014235130ac5aab442e39f9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010020f478c7f74b50c187bf9a8836f382bd62977baeeaf19625608e7e912aa60098c10200da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af6dc2000186a00000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 256)
        payload.add_transfer(IDENTITIES[2], 512)
        payload.add_transfer(IDENTITIES[3], 100000)
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)
Пример #14
0
    def test_simple_transfer(self):
        EXPECTED_PAYLOAD = "a12400532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d44235130ac5aab442e39f9aa27118956695229212dd2f1ab5b714e9f6bd581511c101000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 256)
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)
Пример #15
0
    def action(self, contract_digest: Address, contract_owner: Address,
               action: str, fee: int, signers: EntityList, *args):
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(contract_owner)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = int(fee)
        tx.target_contract(contract_digest, contract_owner, shard_mask)
        tx.action = str(action)
        tx.data = self._encode_msgpack_payload(*args)

        for signer in signers:
            tx.add_signer(signer)

        encoded_tx = encode_transaction(tx, signers)

        return self._post_tx_json(encoded_tx, None)
Пример #16
0
    def create(self, owner: Entity, contract: 'SmartContract', fee: int):
        ENDPOINT = 'create'
        # format the data to be closed by the transaction

        # wildcard for the moment
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(owner)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = fee
        tx.target_chain_code(self.API_PREFIX, shard_mask)
        tx.action = ENDPOINT
        tx.data = self._encode_json({
            'text': contract.encoded_source,
            'digest': contract.digest.to_hex(),
        })
        tx.add_signer(owner)

        # encode and sign the transaction
        encoded_tx = encode_transaction(tx, [owner])

        # update the contracts owner
        contract.owner = owner

        # submit the transaction
        return self._post_tx_json(encoded_tx, ENDPOINT)
Пример #17
0
    def test_contract_with_large_shard_mask(self):
        EXPECTED_DIGEST = "86a1c9e380fe5154243af3d50603aadb75327513373c0e2917b8319d3391b3ae"
        EXPECTED_PAYLOAD = \
            "a1618000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "4041eaab0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840" \
            "a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bb" \
            "dc75a0251c"

        mask = BitVector(16)
        mask.set(15, 1)
        mask.set(14, 1)
        mask.set(13, 1)
        mask.set(11, 1)
        mask.set(9, 1)
        mask.set(7, 1)
        mask.set(5, 1)
        mask.set(3, 1)
        mask.set(1, 1)
        mask.set(0, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        payload.sign(ENTITIES[0])
        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #18
0
    def test_contract_with_4bit_shard_mask(self):
        EXPECTED_DIGEST = "7915d6393fb07dbb4ff6896ef0f57025e5153b744d3a652b0f4815f129a9033c"
        EXPECTED_PAYLOAD = \
            "a1418000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "401c0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        mask = BitVector(4)
        mask.set(3, 1)
        mask.set(2, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Пример #19
0
 def _create_skeleton_tx(cls, fee: int) -> Transaction:
     # build up the basic transaction information
     tx = Transaction()
     tx.charge_rate = 1
     tx.charge_limit = fee
     return tx
Пример #20
0
    def test_synergetic_data_submission(self):
        EXPECTED_DIGEST = "261ba516c9b7b4d3ecb39f349dbb0a35db0d9fc362f2b9cc81c7d844be4d0081"
        EXPECTED_PAYLOAD = \
            "a160c000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4c1271001c3000000e8d4" \
            "a5100080e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df204646174610f7b227661" \
            "6c7565223a20313233347d00000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4f" \
            "dffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()

        payload.from_address = IDENTITIES[0]
        payload.valid_until = 10000
        payload.target_synergetic_data(Address(IDENTITIES[4]), BitVector())
        payload.charge_rate = 1
        payload.charge_limit = 1000000000000
        payload.action = 'data'
        payload.data = json.dumps({'value': 1234}).encode('ascii')
        payload.add_signer(IDENTITIES[0])

        # sign the final transaction
        payload.sign(ENTITIES[0])

        transaction_bytes = transaction.encode_transaction(payload)
        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #21
0
    def submit_signed_tx(self, tx: Transaction):
        if not tx.is_valid():
            raise RuntimeError('Signed transaction failed validation checks')

        return self.tokens.submit_signed_tx(tx)
Пример #22
0
def main():
    # create the APIs
    api = LedgerApi(HOST, PORT)

    # we generate an identity from a known key, which contains funds.
    multi_sig_identity = Entity.from_hex(
        "6e8339a0c6d51fc58b4365bf2ce18ff2698d2b8c40bb13fcef7e1ba05df18e4b")

    # generate a board to control multi-sig account, with variable voting weights
    board = [
        Entity.from_hex(
            "e833c747ee0aeae29e6823e7c825d3001638bc30ffe50363f8adf2693c3286f8"
        ),
        Entity.from_hex(
            "4083a476c4872f25cb40839ac8d994924bcef12d83e2ba4bd3ed6c9705959860"
        ),
        Entity.from_hex(
            "20293422c4b5faefba3422ed436427f2d37f310673681e98ac8637b04e756de3"
        ),
        Entity.from_hex(
            "d5f10ad865fff147ae7fcfdc98b755452a27a345975c8b9b3433ff16f23495fb"
        ),
    ]

    voting_weights = {
        board[0]: 1,
        board[1]: 1,
        board[2]: 1,
        board[3]: 2,
    }

    # generate another entity as a target for transfers
    other_identity = Entity.from_hex(
        "7da0e3fa62a916238decd4f54d43301c809595d66dd469f82f29e076752b155c")

    # submit deed
    print("\nCreating deed...")
    deed = Deed()
    for sig, weight in voting_weights.items():
        deed.set_signee(sig, weight)
    deed.set_operation(Operation.amend, 4)
    deed.set_operation(Operation.transfer, 3)

    api.sync(api.tokens.deed(multi_sig_identity, deed, 500))

    # display balance before
    print("\nBefore remote-multisig transfer")
    print('Balance 1:', api.tokens.balance(multi_sig_identity))
    print('Balance 2:', api.tokens.balance(other_identity))
    print()

    # scatter/gather example
    print("Generating transaction and distributing to signers...")

    # add intended signers to transaction
    ref_tx = TokenTxFactory.transfer(multi_sig_identity,
                                     other_identity,
                                     250,
                                     20,
                                     signatories=board)
    api.set_validity_period(ref_tx)

    # make a reference payload that can be used in this script for validation
    reference_payload = ref_tx.encode_payload()

    # have signers individually sign transaction
    signed_txs = []
    for signer in board:
        # signer builds their own transaction to compare to note that each of the signers will need to agree on all
        # parts of the message including the validity period and the counter
        signer_tx = TokenTxFactory.transfer(multi_sig_identity,
                                            other_identity,
                                            250,
                                            20,
                                            signatories=board)
        signer_tx.counter = ref_tx.counter
        signer_tx.valid_until = ref_tx.valid_until
        signer_tx.valid_from = ref_tx.valid_from

        # sanity check each of the signers payload should match the reference payload
        assert signer_tx.encode_payload() == reference_payload

        # signers locally sign there version of the transaction
        signer_tx.sign(signer)

        # simulate distribution of signed partial transactions
        signed_txs.append(signer_tx.encode_partial())

    # gather and encode final transaction - this step in theory can be done by all the signers provided they are
    # received all the signature shares
    print("Gathering and combining signed transactions...")
    partial_txs = [Transaction.decode_partial(s)[1] for s in signed_txs]

    # merge them together into one fully signed transaction
    success, tx = Transaction.merge(partial_txs)
    assert success  # this indicates that all the signatures have been merged and that the transaction now validates

    # submit the transaction
    api.sync(api.submit_signed_tx(tx))

    print("\nAfter remote multisig-transfer")
    print('Balance 1:', api.tokens.balance(multi_sig_identity))
    print('Balance 2:', api.tokens.balance(other_identity))

    # round-robin example
    print("\nGenerating transaction and sending down the line of signers...")

    # create the basis for the transaction
    tx = TokenTxFactory.transfer(multi_sig_identity,
                                 other_identity,
                                 250,
                                 20,
                                 signatories=board)
    api.set_validity_period(tx)

    # serialize and send to be signed
    tx_payload = tx.encode_payload()

    # have signers individually sign transaction and pass on to next signer
    for signer in board:
        # build the target transaction
        signer_tx = Transaction.decode_payload(tx_payload)

        # Signer decodes payload to inspect transaction
        signer_tx.sign(signer)

        # ensure that when we merge the signers signature into the payload that it is correct
        assert tx.merge_signatures(signer_tx)

    # once all the partial signatures have been merged then it makes sense
    print("Collecting final signed transaction...")
    assert tx.is_valid()
    api.sync(api.submit_signed_tx(tx))

    print("\nAfter remote multisig-transfer")
    print('Balance 1:', api.tokens.balance(multi_sig_identity))
    print('Balance 2:', api.tokens.balance(other_identity))
Пример #23
0
    def wealth(self, entity: Entity, amount: int):
        """
        Creates wealth for specified account

        :param private_key_bin: The bytes of the private key of the targeted address
        :param amount: The amount of wealth to be generated
        :param fee: The fee value to be used for the transaction
        :return: The digest of the submitted transaction
        :raises: ApiError on any failures
        """
        ENDPOINT = 'wealth'

        # format the data to be closed by the transaction

        # wildcard for the moment
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(entity)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = 10
        tx.target_chain_code(self.API_PREFIX, shard_mask)
        tx.action = 'wealth'
        tx.add_signer(entity)

        # format the transaction payload
        tx.data = self._encode_json({
            'address': entity.public_key,
            'amount': amount
        })

        # encode and sign the transaction
        encoded_tx = encode_transaction(tx, [entity])

        # submit the transaction
        return self._post_tx_json(encoded_tx, ENDPOINT)
Пример #24
0
    def test_validity_ranges(self):
        EXPECTED_DIGEST = "5451e302ba1fd323b623c1c9a0fc626b9c9249bb5d91ec60be1bb924efa3f1ac"
        EXPECTED_PAYLOAD = \
            "a1670000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4024235130ac5aab442e3" \
            "9f9aa27118956695229212dd2f1ab5b714e9f6bd581511c103e820f478c7f74b50c187bf9a8836f382bd62977bae" \
            "eaf19625608e7e912aa60098c103e8da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af" \
            "6dc103e8e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df2c103e864c0c8c103e8c2" \
            "000f424000000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f" \
            "4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_transfer(IDENTITIES[1], 1000)
        payload.add_transfer(IDENTITIES[2], 1000)
        payload.add_transfer(IDENTITIES[3], 1000)
        payload.add_transfer(IDENTITIES[4], 1000)
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200

        # sign the final transaction
        payload.sign(ENTITIES[0])
        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(tx, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #25
0
    def submit_data(self, entity: Entity, digest: Address, **kwargs):
        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(entity)
        tx.valid_until = 10000
        tx.target_contract(digest, Address(entity), BitVector())
        tx.charge_rate = 1
        tx.charge_limit = 1000000000000
        tx.action = 'data'
        tx.synergetic_data_submission = True
        tx.data = self._encode_json(dict(**kwargs))
        tx.add_signer(entity)

        # encode the transaction
        encoded_tx = encode_transaction(tx, [entity])

        # submit the transaction to the catch-all endpoint
        return self._post_tx_json(encoded_tx, None)
Пример #26
0
    def test_contract_with_4bit_shard_mask(self):
        EXPECTED_DIGEST = "e1ac018356792e492aaac92bf6928af1e47ed987761b81cafb51f1106f403eee"
        EXPECTED_PAYLOAD = \
            "a1618000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "401c0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        mask = BitVector(4)
        mask.set(3, 1)
        mask.set(2, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        payload.sign(ENTITIES[0])
        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #27
0
    def test_chain_code(self):
        EXPECTED_DIGEST = "25cc72ca7d4871aaaabd027af129ecd4327adde5ec0c9977bfe11018d4bab64a"

        EXPECTED_PAYLOAD = \
            "a1608000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \
            "0b666f6f2e6261722e62617a066c61756e636802676f00000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.target_chain_code('foo.bar.baz', BitVector())
        payload.action = 'launch'
        payload.data = 'go'.encode('ascii')

        # sign the final transaction
        payload.sign(ENTITIES[0])

        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Пример #28
0
    def test_smart_contract(self):
        EXPECTED_DIGEST = "032a72029ae2ac5cdbf9e07cf57d9ecab97a6de34ed5cdf785d1d98037cd5dcd"
        EXPECTED_PAYLOAD = \
            "a1404000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \
            "da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af6de6672a9d98da667e5dc25b2bca8a" \
            "cf9644a7ac0797f01cb5968abf39de011df2066c61756e636802676f00000000000000000418c2a33af8bd2cba7f" \
            "a714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758b" \
            "cc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.target_contract(IDENTITIES[3], IDENTITIES[4], BitVector())
        payload.action = 'launch'
        payload.data = 'go'.encode('ascii')

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Пример #29
0
def decode_transaction(stream: io.BytesIO) -> (bool, Transaction):
    # ensure the at the magic is correctly configured
    magic = stream.read(1)[0]
    if magic != MAGIC:
        raise RuntimeError('Unable to parse transaction from stream, invalid magic')

    # extract the header bytes
    header = stream.read(2)

    # parse the header types
    version = (header[0] & 0xE0) >> 5
    charge_unit_flag = bool((header[0] & 0x08) >> 3)
    transfer_flag = bool((header[0] & 0x04) >> 2)
    multiple_transfers_flag = bool((header[0] & 0x02) >> 1)
    valid_from_flag = bool((header[0] & 0x01))

    contract_type = (header[1] & 0xC0) >> 6
    signature_count_minus1 = (header[1] & 0x3F)

    num_signatures = signature_count_minus1 + 1

    # ensure that the version is correct
    if version != VERSION:
        raise RuntimeError('Unable to parse transaction from stream, incompatible version')

    # Ready empty reserved byte
    stream.read(1)

    tx = Transaction()

    # decode the address from the thread
    tx.from_address = address.decode(stream)

    if transfer_flag:

        # determine the number of transfers that are present in the transaction
        if multiple_transfers_flag:
            transfer_count = integer.decode(stream) + 2
        else:
            transfer_count = 1

        for n in range(transfer_count):
            to = address.decode(stream)
            amount = integer.decode(stream)

            tx.add_transfer(to, amount)

    if valid_from_flag:
        tx.valid_from = integer.decode(stream)

    tx.valid_until = integer.decode(stream)
    tx.charge_rate = integer.decode(stream)

    assert not charge_unit_flag, "Currently the charge unit field is not supported"

    tx.charge_limit = integer.decode(stream)

    if contract_type != NO_CONTRACT:
        contract_header = int(stream.read(1)[0])

        wildcard = bool(contract_header & 0x80)

        shard_mask = BitVector()
        if not wildcard:
            extended_shard_mask_flag = bool(contract_header & 0x40)

            if not extended_shard_mask_flag:

                if contract_header & 0x10:
                    mask = 0xf
                    bit_size = 4
                else:
                    mask = 0x3
                    bit_size = 2

                # extract the shard mask from the header
                shard_mask = BitVector.from_bytes(bytes([contract_header & mask]), bit_size)

            else:
                bit_length = 1 << ((contract_header & 0x3F) + 3)
                byte_length = bit_length // 8

                assert (bit_length % 8) == 0  # this should be enforced as part of the spec

                # extract the mask from the next N bytes
                shard_mask = BitVector.from_bytes(stream.read(byte_length), bit_length)

        if contract_type == SMART_CONTRACT or contract_type == SYNERGETIC:
            contract_digest = address.decode(stream)
            contract_address = address.decode(stream)

            tx.target_contract(contract_digest, contract_address, shard_mask)

        elif contract_type == CHAIN_CODE:
            encoded_chain_code_name = bytearray.decode(stream)

            tx.target_chain_code(encoded_chain_code_name.decode('ascii'), shard_mask)

        else:
            # this is mostly a guard against a desync between this function and `_map_contract_mode`
            raise RuntimeError("Unhandled contract type")

        tx.action = bytearray.decode(stream).decode('ascii')
        tx.data = bytearray.decode(stream)

    # Read counter value
    tx.counter = struct.unpack('<Q', stream.read(8))[0]

    if signature_count_minus1 == 0x3F:
        additional_signatures = integer.decode(stream)
        num_signatures += additional_signatures

    # extract all the signing public keys from the stream
    public_keys = [identity.decode(stream) for _ in range(num_signatures)]

    # extract full copy of the payload
    payload_bytes = stream.getvalue()[:stream.tell()]

    verified = []
    for ident in public_keys:
        # for n in range(num_signatures):

        # extract the signature from the stream
        signature = bytearray.decode(stream)

        # verify if this signature is correct
        verified.append(ident.verify(payload_bytes, signature))

        # build a metadata object to store in the tx
        tx._signers[ident] = {
            'signature': signature,
            'verified': verified[-1],
        }

    return all(verified), tx
Пример #30
0
    def test_smart_contract(self):
        EXPECTED_DIGEST = "9ea094e71cbe846192429db3d7e8b02b649730c8b525c3268eb9ff5633c27130"
        EXPECTED_PAYLOAD = \
            "a1604000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \
            "e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df2066c61756e636802676f00000000" \
            "000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c25" \
            "8cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.target_contract(Address(IDENTITIES[4]), BitVector())
        payload.action = 'launch'
        payload.data = 'go'.encode('ascii')

        # sign the final transaction
        payload.sign(ENTITIES[0])
        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)