Пример #1
0
    def test_output_value(self):
        from hathor.transaction.base_transaction import bytes_to_output_value
        # first test using a small output value with 8 bytes. It should fail
        parents = [tx.hash for tx in self.genesis_txs]
        outputs = [TxOutput(1, b'')]
        tx = Transaction(outputs=outputs, parents=parents)
        original_struct = tx.get_struct()
        struct_bytes = tx.get_funds_struct()

        # we'll get the struct without the last output bytes and add it ourselves
        struct_bytes = struct_bytes[:-7]
        # add small value using 8 bytes and expect failure when trying to deserialize
        struct_bytes += (-1).to_bytes(8, byteorder='big', signed=True)
        struct_bytes += int_to_bytes(0, 1)
        struct_bytes += int_to_bytes(0, 2)
        struct_bytes += tx.get_graph_struct()
        struct_bytes += int_to_bytes(tx.nonce, tx.SERIALIZATION_NONCE_SIZE)

        len_difference = len(struct_bytes) - len(original_struct)
        assert len_difference == 4, 'new struct is incorrect, len difference={}'.format(len_difference)

        with self.assertRaises(ValueError):
            Transaction.create_from_struct(struct_bytes)

        # now use 8 bytes and make sure it's working
        outputs = [TxOutput(MAX_OUTPUT_VALUE, b'')]
        tx = Transaction(outputs=outputs, parents=parents)
        tx.update_hash()
        original_struct = tx.get_struct()
        tx2 = Transaction.create_from_struct(original_struct)
        tx2.update_hash()
        assert tx == tx2

        # Validating that all output values must be positive
        value = 1
        address = decode_address('WUDtnw3GYjvUnZmiHAmus6hhs9GoSUSJMG')
        script = P2PKH.create_output_script(address)
        output = TxOutput(value, script)
        output.value = -1
        tx = Transaction(inputs=[], outputs=[output], parents=parents, storage=self.tx_storage)
        with self.assertRaises(InvalidOutputValue):
            tx.resolve()

        # 'Manually resolving', to validate verify method
        tx.hash = bytes.fromhex('012cba011be3c29f1c406f9015e42698b97169dbc6652d1f5e4d5c5e83138858')
        with self.assertRaises(InvalidOutputValue):
            tx.verify()

        # Invalid output value
        invalid_output = bytes.fromhex('ffffffff')
        with self.assertRaises(InvalidOutputValue):
            bytes_to_output_value(invalid_output)

        # Can't instantiate an output with negative value
        with self.assertRaises(AssertionError):
            TxOutput(-1, script)
Пример #2
0
    def test_twin(self):
        # Normal twin
        params = ['--raw_tx', self.tx.get_struct().hex()]
        args = self.parser.parse_args(params)

        f = StringIO()
        with capture_logs():
            with redirect_stdout(f):
                execute(args)

        # Transforming prints str in array
        output = f.getvalue().strip().splitlines()

        twin_tx = Transaction.create_from_struct(bytes.fromhex(output[0]))
        # Parents are the same but in different order
        self.assertEqual(twin_tx.parents[0], self.tx.parents[1])
        self.assertEqual(twin_tx.parents[1], self.tx.parents[0])

        # Testing metadata creation from json
        meta_before_conflict = self.tx.get_metadata()
        meta_before_conflict_json = meta_before_conflict.to_json()
        del meta_before_conflict_json['conflict_with']
        del meta_before_conflict_json['voided_by']
        del meta_before_conflict_json['twins']
        new_meta = TransactionMetadata.create_from_json(meta_before_conflict_json)
        self.assertEqual(meta_before_conflict, new_meta)

        self.manager.propagate_tx(twin_tx)

        # Validate they are twins
        meta = self.tx.get_metadata(force_reload=True)
        self.assertEqual(meta.twins, [twin_tx.hash])

        meta2 = twin_tx.get_metadata()
        self.assertFalse(meta == meta2)
        def setUp(self):
            super().setUp()

            self.network = 'testnet'
            self.manager = self.create_peer(self.network, unlock_wallet=True)
            self.tx_storage = self.manager.tx_storage

            data = b'This is a test block.'
            self.blocks = add_new_blocks(self.manager, 3, advance_clock=15, block_data=data)

            address = self.get_address(0)
            value = 100

            outputs = [
                WalletOutputInfo(address=decode_address(address), value=int(value), timelock=None)
            ]

            self.tx1 = self.manager.wallet.prepare_transaction_compute_inputs(Transaction, outputs)
            self.tx1.weight = 10
            self.tx1.parents = self.manager.get_new_tx_parents()
            self.tx1.timestamp = int(self.clock.seconds())
            self.tx1.resolve()
            self.manager.propagate_tx(self.tx1)

            # Change of parents only, so it's a twin.
            # With less weight, so the balance will continue because tx1 will be the winner
            self.tx2 = Transaction.create_from_struct(self.tx1.get_struct())
            self.tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
            self.tx2.weight = 9
            self.tx2.resolve()

            # Propagate a conflicting twin transaction
            self.manager.propagate_tx(self.tx2)
Пример #4
0
 def test_spend_block(self):
     block = self.unspent_blocks[0]
     address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A'
     script = create_base_script(address).get_script()
     resp = (yield self.web.post('create_tx', {
         'inputs': [
             {
                 'tx_id': block.hash_hex,
                 'index': 0,
             }
         ],
         'outputs': [
             {
                 'address': address,
                 'value': 6400,
             }
         ]
     })).json_value()
     self.assertEqual(resp['success'], True)
     data = resp['data']
     hex_data = resp['hex_data']
     struct_bytes = bytes.fromhex(hex_data)
     tx = Transaction.create_from_struct(struct_bytes)
     tx_data = tx.to_json()
     del tx_data['hash']
     del tx_data['nonce']
     self.assertEqual(data, tx_data)
     self.assertEqual(len(tx.inputs), 1)
     self.assertEqual(tx.inputs[0].tx_id, block.hash)
     self.assertEqual(tx.inputs[0].index, 0)
     self.assertEqual(tx.inputs[0].data, b'')
     self.assertEqual(len(tx.outputs), 1)
     self.assertEqual(tx.outputs[0].value, 6400)
     self.assertEqual(tx.outputs[0].token_data, 0)
     self.assertEqual(tx.outputs[0].script, script)
Пример #5
0
 def test_tx_propagate(self):
     _set_test_mode(
         TestMode.DISABLED)  # disable test_mode so the weight is not 1
     src_tx = self.unspent_tx
     output_address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A'
     resp = (yield self.web.post(
         'create_tx', {
             'inputs': [{
                 'tx_id': src_tx.hash_hex,
                 'index': 1,
             }],
             'outputs': [{
                 'address': output_address,
                 'value': 100,
             }]
         })).json_value()
     self.assertEqual(resp['success'], True)
     data = resp['data']
     hex_data = resp['hex_data']
     struct_bytes = bytes.fromhex(hex_data)
     orig_tx = Transaction.create_from_struct(struct_bytes)
     tx = orig_tx.clone()
     tx_data = tx.to_json()
     del tx_data['hash']
     del tx_data['nonce']
     self.assertEqual(data, tx_data)
     data_to_sign = tx.get_sighash_all()
     private_key = self.manager.wallet.get_private_key(self.unspent_address)
     public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data(
         data_to_sign, private_key)
     input_data = P2PKH.create_input_data(public_key_bytes, signature_bytes)
     tx.inputs[0].data = input_data
     # XXX: tx.resolve is a bit CPU intensive, but not so much as to make this test disabled by default
     tx.resolve(False)
     self.assertTrue(self.manager.propagate_tx(tx))
Пример #6
0
 def test_spend_tx_by_script(self):
     src_tx = self.unspent_tx
     address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A'
     script = create_base_script(address).get_script()
     script_str = base64.b64encode(script).decode('utf-8')
     resp = (yield self.web.post(
         'create_tx', {
             'inputs': [{
                 'tx_id': src_tx.hash_hex,
                 'index': 1,
             }],
             'outputs': [{
                 'script': script_str,
                 'value': 100,
             }]
         })).json_value()
     self.assertEqual(resp['success'], True)
     data = resp['data']
     hex_data = resp['hex_data']
     struct_bytes = bytes.fromhex(hex_data)
     tx = Transaction.create_from_struct(struct_bytes)
     tx_data = tx.to_json()
     del tx_data['hash']
     del tx_data['nonce']
     self.assertEqual(data, tx_data)
     self.assertEqual(len(tx.inputs), 1)
     self.assertEqual(tx.inputs[0].tx_id, src_tx.hash)
     self.assertEqual(tx.inputs[0].index, 1)
     self.assertEqual(tx.inputs[0].data, b'')
     self.assertEqual(len(tx.outputs), 1)
     self.assertEqual(tx.outputs[0].value, 100)
     self.assertEqual(tx.outputs[0].token_data, 0)
     self.assertEqual(tx.outputs[0].script, script)
    def test_balance_update2(self):
        # Tx2 is twin with tx1 with equal acc weight, so both will get voided

        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        # Change of parents only, so it's a twin.
        # Same weight, so both will be voided then the balance increases
        tx2 = Transaction.create_from_struct(self.tx1.get_struct())
        tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
        tx2.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        meta1 = self.tx1.get_metadata(force_reload=True)
        self.assertEqual(meta1.twins, [tx2.hash])
        self.assertEqual(meta1.voided_by, {self.tx1.hash})

        meta2 = tx2.get_metadata()
        self.assertEqual(meta2.voided_by, {tx2.hash})

        # Balance changed
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, sum(self.blocks_tokens[:3])))
    def test_balance_update3(self):
        # Tx2 is twin with tx1 with higher acc weight, so tx1 will get voided

        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        # Change of parents only, so it's a twin.
        # With higher weight, so the balance will continue because tx2 will be the winner
        tx2 = Transaction.create_from_struct(self.tx1.get_struct())
        tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
        tx2.weight = 13
        tx2.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        meta1 = self.tx1.get_metadata(force_reload=True)
        self.assertEqual(meta1.twins, [tx2.hash])
        self.assertEqual(meta1.voided_by, {self.tx1.hash})

        meta2 = tx2.get_metadata()
        self.assertEqual(meta2.voided_by, None)

        # Balance is the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))
    def test_balance_update1(self):
        # Tx2 is twin with tx1 but less acc weight, so it will get voided

        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        # Change of parents only, so it's a twin.
        # With less weight, so the balance will continue because tx1 will be the winner
        tx2 = Transaction.create_from_struct(self.tx1.get_struct())
        tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
        tx2.weight = 9
        tx2.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        meta1 = self.tx1.get_metadata(force_reload=True)
        self.assertEqual(meta1.twins, [tx2.hash])

        meta2 = tx2.get_metadata(force_reload=True)
        self.assertEqual(meta2.voided_by, {tx2.hash})

        # Balance is the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        # Voided wallet history
        index_voided = 0
        output_voided = tx2.outputs[index_voided]
        address = output_voided.to_human_readable()['address']
        voided_unspent = UnspentTx(tx2.hash,
                                   index_voided,
                                   output_voided.value,
                                   tx2.timestamp,
                                   address,
                                   output_voided.token_data,
                                   voided=True)
        self.assertEqual(len(self.manager.wallet.voided_unspent), 1)
        voided_utxo = self.manager.wallet.voided_unspent.get(
            (voided_unspent.tx_id, index_voided))
        self.assertIsNotNone(voided_utxo)
        self.assertEqual(voided_utxo.to_dict(), voided_unspent.to_dict())

        input_voided = tx2.inputs[0]
        key = (input_voided.tx_id, input_voided.index)
        voided_spent = SpentTx(tx2.hash,
                               input_voided.tx_id,
                               input_voided.index,
                               self.blocks_tokens[0],
                               tx2.timestamp,
                               voided=True)
        self.assertEqual(len(self.manager.wallet.voided_spent), 1)
        self.assertEqual(len(self.manager.wallet.voided_spent[key]), 1)
        self.assertEqual(self.manager.wallet.voided_spent[key][0].to_dict(),
                         voided_spent.to_dict())
Пример #10
0
    def test_tx_methods(self):
        blocks = add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        txs = add_new_transactions(self.manager, 2, advance_clock=1)

        # Validate __str__, __bytes__, __eq__
        tx = txs[0]
        tx2 = txs[1]
        str_tx = str(tx)
        self.assertTrue(isinstance(str_tx, str))
        self.assertEqual(bytes(tx), tx.get_struct())

        tx_equal = Transaction.create_from_struct(tx.get_struct())
        self.assertTrue(tx == tx_equal)
        self.assertFalse(tx == tx2)

        tx2_hash = tx2.hash
        tx2.hash = None
        self.assertFalse(tx == tx2)
        tx2.hash = tx2_hash

        # Validate is_genesis without storage
        tx_equal.storage = None
        self.assertFalse(tx_equal.is_genesis)

        # Pow error
        tx2.verify_pow()
        tx2.weight = 100
        with self.assertRaises(PowError):
            tx2.verify_pow()

        # Get sighashall is different with and without data
        self.assertNotEqual(tx.get_sighash_all(), tx.get_sighash_all(clear_input_data=False))

        # Verify parent timestamps
        tx2.verify_parents()
        tx2_timestamp = tx2.timestamp
        tx2.timestamp = 2
        with self.assertRaises(TimestampError):
            tx2.verify_parents()
        tx2.timestamp = tx2_timestamp

        # Verify inputs timestamps
        tx2.verify_inputs()
        tx2.timestamp = 2
        with self.assertRaises(TimestampError):
            tx2.verify_inputs()
        tx2.timestamp = tx2_timestamp

        # Validate maximum distance between blocks
        block = blocks[0]
        block2 = blocks[1]
        block2.timestamp = block.timestamp + settings.MAX_DISTANCE_BETWEEN_BLOCKS
        block2.verify_parents()
        block2.timestamp += 1
        with self.assertRaises(TimestampError):
            block2.verify_parents()
Пример #11
0
    def test_tips_twin(self):
        add_new_blocks(self.manager, 6, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        self.assertEqual(
            len(self.manager.tx_storage.indexes.mempool_tips.get()), 0)

        tx1 = add_new_transactions(self.manager, 1, advance_clock=1)[0]
        tx2 = add_new_transactions(self.manager, 1, advance_clock=1)[0]
        tx3 = add_new_transactions(self.manager, 1, advance_clock=1)[0]
        # 3 txs and the last one is still a tip
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx3.hash]))

        # A new tx with custom parents, so tx3 and tx4 will become two tips
        tx4 = add_new_transactions(self.manager,
                                   1,
                                   advance_clock=1,
                                   propagate=False)[0]
        tx4.parents = [tx1.hash, tx2.hash]
        tx4.resolve()
        self.manager.propagate_tx(tx4, fails_silently=False)
        self.manager.reactor.advance(10)
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx4.hash, tx3.hash]))

        # A twin tx with tx4, that will be voided initially, then won't change the tips
        tx5 = Transaction.create_from_struct(tx4.get_struct())
        tx5.parents = [tx2.hash, tx3.hash]
        tx5.resolve()
        self.manager.propagate_tx(tx5)
        self.manager.reactor.advance(10)

        # tx4 and tx5 are twins, so both are voided
        self.assertIsNotNone(tx4.get_metadata(force_reload=True).voided_by)
        self.assertIsNotNone(tx5.get_metadata(force_reload=True).voided_by)
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx3.hash]))

        # add new tx confirming tx5, which will become valid and tx4 becomes voided
        tx6 = add_new_transactions(self.manager,
                                   1,
                                   advance_clock=1,
                                   propagate=False)[0]
        tx6.parents = [tx5.hash, tx2.hash]
        tx6.resolve()
        self.manager.propagate_tx(tx6, fails_silently=False)
        self.manager.reactor.advance(10)
        self.assertIsNotNone(tx4.get_metadata(force_reload=True).voided_by)
        self.assertIsNone(tx5.get_metadata(force_reload=True).voided_by)

        # tx6 is the only one left
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx6.hash]))
def execute(args: Namespace, priv_key_password: str) -> None:
    from hathor.transaction import Transaction
    from hathor.wallet.util import generate_signature

    tx = Transaction.create_from_struct(bytes.fromhex(args.partial_tx))
    assert isinstance(tx, Transaction)

    signature = generate_signature(tx, bytes.fromhex(args.private_key), password=priv_key_password.encode())
    print('Signature: ', signature.hex())
    def test_balance_update4(self):
        # Tx2 spends Tx1 output
        # Tx3 is twin of Tx2 with same acc weight, so both will get voided

        self.manager.reactor.advance(1)

        # Start balance
        self.assertEqual(self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
                         WalletBalance(0, self.initial_balance))

        address = self.manager.wallet.get_unused_address_bytes()
        value = self.blocks_tokens[0] - 100
        inputs = [WalletInputInfo(tx_id=self.tx1.hash, index=0, private_key=None)]
        outputs = [WalletOutputInfo(address=address, value=int(value), timelock=None)]
        tx2 = self.manager.wallet.prepare_transaction_incomplete_inputs(Transaction, inputs, outputs,
                                                                        self.manager.tx_storage)
        tx2.weight = 10
        tx2.parents = [self.tx1.hash, self.tx1.parents[0]]
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        # Test create same tx with allow double spending
        with self.assertRaises(PrivateKeyNotFound):
            self.manager.wallet.prepare_transaction_incomplete_inputs(
                Transaction,
                inputs=inputs,
                outputs=outputs,
                tx_storage=self.manager.tx_storage
            )

        self.manager.wallet.prepare_transaction_incomplete_inputs(Transaction, inputs=inputs, outputs=outputs,
                                                                  force=True, tx_storage=self.manager.tx_storage)

        # Change of parents only, so it's a twin.
        tx3 = Transaction.create_from_struct(tx2.get_struct())
        tx3.parents = [tx2.parents[1], tx2.parents[0]]
        tx3.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx3)
        self.run_to_completion()

        meta2 = tx2.get_metadata(force_reload=True)
        self.assertEqual(meta2.twins, [tx3.hash])
        self.assertEqual(meta2.voided_by, {tx2.hash})

        meta3 = tx3.get_metadata()
        self.assertEqual(meta3.voided_by, {tx3.hash})

        # Balance is the same
        self.assertEqual(self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
                         WalletBalance(0, self.initial_balance))
Пример #14
0
    def render_GET(self, request):
        """ Get request /wallet/nano-contract/decode/ that returns the tx decoded, if success

        Expects 'hex_tx' as GET parameter

        :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'GET')

        if b'hex_tx' in request.args:
            requested_decode = request.args[b'hex_tx'][0].decode('utf-8')
        else:
            return get_missing_params_msg('hex_tx')

        pattern = r'[a-fA-F\d]+'
        if re.match(pattern,
                    requested_decode) and len(requested_decode) % 2 == 0:
            tx_bytes = bytes.fromhex(requested_decode)

            try:
                tx = Transaction.create_from_struct(tx_bytes)
            except struct.error:
                data = {'success': False, 'message': 'Invalid transaction'}
                return json.dumps(data).encode('utf-8')

            outputs = []
            nano_contract = None
            for _output in tx.outputs:
                _nano_contract = NanoContractMatchValues.parse_script(
                    _output.script)
                if _nano_contract:
                    nano_contract = _nano_contract.to_human_readable()
                    nano_contract['value'] = _output.value
                    continue
                else:
                    outputs.append(_output.to_human_readable())

            my_inputs, other_inputs = self.manager.wallet.separate_inputs(
                tx.inputs, self.manager.tx_storage)

            my_inputs = [_in.to_human_readable() for _in in my_inputs]
            other_inputs = [_in.to_human_readable() for _in in other_inputs]

            data = {
                'success': True,
                'nano_contract': nano_contract,
                'outputs': outputs,
                'my_inputs': my_inputs,
                'other_inputs': other_inputs
            }
        else:
            data = {'success': False, 'message': 'Invalid transaction'}
        return json.dumps(data).encode('utf-8')
Пример #15
0
def execute(args: Namespace) -> None:
    from hathor.transaction import Transaction
    from hathor.transaction.scripts import MultiSig

    tx = Transaction.create_from_struct(bytes.fromhex(args.partial_tx))

    signatures = [bytes.fromhex(signature) for signature in args.signatures.split(',')]
    input_data = MultiSig.create_input_data(bytes.fromhex(args.redeem_script), signatures)
    tx.inputs[0].data = input_data

    tx.resolve()
    print('Transaction after POW: ', tx.get_struct().hex())
Пример #16
0
    def test_twin_different(self):
        server = run_server()

        # Unlock wallet to start mining
        request_server('wallet/unlock', 'POST', data={'passphrase': '123'})

        # Mining
        execute_mining(count=2)

        # Generating txs
        execute_tx_gen(count=4)

        response = request_server('transaction',
                                  'GET',
                                  data={
                                      b'count': 4,
                                      b'type': 'tx'
                                  })
        tx = response['transactions'][-1]

        response = request_server('transaction',
                                  'GET',
                                  data={b'id': tx['tx_id']})
        tx = response['tx']

        # Twin different weight and parents
        host = 'http://localhost:8085/{}/'.format(settings.API_VERSION_PREFIX)
        params = [
            '--url', host, '--hash', tx['hash'], '--parents', '--weight', '14'
        ]
        args = self.parser.parse_args(params)

        f = StringIO()
        with redirect_stdout(f):
            execute(args)

        # Transforming prints str in array
        output = f.getvalue().split('\n')
        # Last element is always empty string
        output.pop()

        twin_tx = Transaction.create_from_struct(bytes.fromhex(output[0]))
        # Parents are differents
        self.assertNotEqual(twin_tx.parents[0], tx['parents'][0])
        self.assertNotEqual(twin_tx.parents[0], tx['parents'][1])
        self.assertNotEqual(twin_tx.parents[1], tx['parents'][0])
        self.assertNotEqual(twin_tx.parents[1], tx['parents'][1])

        self.assertNotEqual(twin_tx.weight, tx['weight'])
        self.assertEqual(twin_tx.weight, 14.0)

        server.terminate()
Пример #17
0
    def test_tips_winner(self):
        add_new_block(self.manager, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        self.assertEqual(
            len(self.manager.tx_storage.indexes.mempool_tips.get()), 0)

        tx1 = add_new_transactions(self.manager, 1, advance_clock=1)[0]
        # tx1 will be the tip
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx1.hash]))

        tx2 = add_new_transactions(self.manager, 1, advance_clock=1)[0]
        # tx2 will be the tip now
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx2.hash]))

        tx3 = Transaction.create_from_struct(tx2.get_struct())
        tx3.parents = [tx2.parents[1], tx2.parents[0]]
        tx3.resolve()

        # Propagate a conflicting twin transaction with tx2
        self.manager.propagate_tx(tx3)

        meta1 = tx2.get_metadata(force_reload=True)
        self.assertEqual(meta1.conflict_with, [tx3.hash])
        self.assertEqual(meta1.voided_by, {tx2.hash})
        self.assertEqual(meta1.twins, [tx3.hash])
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(),
            set([tx1.hash]))

        self.manager.reactor.advance(10)

        # Creating a new block that confirms tx3, then is will become valid and voiding tx2
        new_block = add_new_block(self.manager, propagate=False)
        new_block.parents = [new_block.parents[0], tx1.hash, tx3.hash]
        new_block.resolve()
        new_block.verify()
        self.manager.propagate_tx(new_block, fails_silently=False)

        self.manager.reactor.advance(10)

        self.assertIsNone(
            self.manager.tx_storage.get_metadata(tx3.hash).voided_by)
        self.assertIsNotNone(
            self.manager.tx_storage.get_metadata(tx2.hash).voided_by)
        # The block confirms tx3, so it's not a tip
        self.assertCountEqual(
            self.manager.tx_storage.indexes.mempool_tips.get(), set())
Пример #18
0
    def test_balance_update5(self):
        # Tx2 spends Tx1 output
        # Tx3 is twin of Tx1, with less acc weight
        # So we have conflict between all three txs but tx1 and tx2 are winners and tx3 is voided

        self.clock.advance(1)

        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        address = self.manager.wallet.get_unused_address_bytes()
        value = self.blocks_tokens[0] - 100
        inputs = [
            WalletInputInfo(tx_id=self.tx1.hash, index=0, private_key=None)
        ]
        outputs = [
            WalletOutputInfo(address=address, value=int(value), timelock=None)
        ]
        tx2 = self.manager.wallet.prepare_transaction_incomplete_inputs(
            Transaction, inputs, outputs, self.manager.tx_storage)
        tx2.weight = 10
        tx2.parents = [self.tx1.hash, self.tx1.parents[0]]
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()

        # Change of parents only, so it's a twin.
        tx3 = Transaction.create_from_struct(self.tx1.get_struct())
        tx3.parents = [self.tx1.parents[1], self.tx1.parents[0]]
        tx3.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.manager.propagate_tx(tx3)
        self.run_to_completion()

        meta2 = tx2.get_metadata()
        self.assertEqual(meta2.twins, [])
        self.assertEqual(meta2.voided_by, None)

        meta3 = tx3.get_metadata()
        self.assertEqual(meta3.voided_by, {tx3.hash})
        self.assertEqual(meta3.twins, [self.tx1.hash])

        # Balance is the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))
Пример #19
0
    def test_get_one(self):
        genesis_tx = next(x for x in self.manager.tx_storage.get_all_genesis()
                          if x.is_block)
        response_success = yield self.web.get(
            "transaction", {b'id': bytes(genesis_tx.hash.hex(), 'utf-8')})
        data_success = response_success.json_value()
        self.assertTrue(data_success['success'])
        dict_test = genesis_tx.to_json(decode_script=True)
        dict_test['raw'] = genesis_tx.get_struct().hex()
        dict_test['nonce'] = str(dict_test['nonce'])
        if genesis_tx.is_block:
            dict_test['height'] = genesis_tx.calculate_height()
        self.assertEqual(data_success['tx'], dict_test)

        # Test sending hash that does not exist
        response_error1 = yield self.web.get(
            "transaction", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a5533848'
            })
        data_error1 = response_error1.json_value()
        self.assertFalse(data_error1['success'])

        # Test sending invalid hash
        response_error2 = yield self.web.get(
            "transaction", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a553384'
            })
        data_error2 = response_error2.json_value()
        self.assertFalse(data_error2['success'])

        # Adding blocks to have funds
        add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        tx = add_new_transactions(self.manager, 1)[0]

        tx2 = Transaction.create_from_struct(tx.get_struct())
        tx2.parents = [tx.parents[1], tx.parents[0]]
        tx2.resolve()

        self.manager.propagate_tx(tx2)

        # Now we get a tx with conflict, voided_by and twin
        response_conflict = yield self.web.get(
            "transaction", {b'id': bytes(tx2.hash.hex(), 'utf-8')})
        data_conflict = response_conflict.json_value()
        self.assertTrue(data_conflict['success'])
Пример #20
0
    def test_twin_tx(self):
        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)

        address = self.get_address(0)
        value1 = 100
        value2 = 101

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value1),
                             timelock=None),
            WalletOutputInfo(address=decode_address(address),
                             value=int(value2),
                             timelock=None)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()

        # Change of parents only, so it's a twin
        tx2 = Transaction.create_from_struct(tx1.get_struct())
        tx2.parents = [tx1.parents[1], tx1.parents[0]]
        tx2.resolve()
        self.assertNotEqual(tx1.hash, tx2.hash)

        self.manager.propagate_tx(tx1)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 1)
        self.assertEqual(wallet_data, [tx1.hash])

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 2)
        self.assertEqual(set(wallet_data), set([tx1.hash, tx2.hash]))
Пример #21
0
    def render_GET(self, request):
        """ Get request /decode_tx/ that returns the signed tx, if success

            Expects 'hex_tx' as GET parameter

            :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'GET')

        if b'hex_tx' in request.args:
            requested_decode = request.args[b'hex_tx'][0].decode('utf-8')
        else:
            return get_missing_params_msg('hex_tx')

        pattern = r'[a-fA-F\d]+'
        if re.match(pattern,
                    requested_decode) and len(requested_decode) % 2 == 0:
            tx_bytes = bytes.fromhex(requested_decode)

            prepare_to_send = False
            if b'prepare_to_send' in request.args:
                _prepare_to_send = request.args[b'prepare_to_send'][0].decode(
                    'utf-8')
                prepare_to_send = _prepare_to_send == 'true'

            try:
                tx = Transaction.create_from_struct(tx_bytes)
                tx.storage = self.manager.tx_storage
                self.manager.wallet.sign_transaction(tx,
                                                     self.manager.tx_storage)

                if prepare_to_send:
                    tx.parents = self.manager.get_new_tx_parents()
                    tx.update_timestamp(int(self.manager.reactor.seconds()))
                    tx.weight = self.manager.minimum_tx_weight(tx)
                    tx.resolve()

                data = {'hex_tx': tx.get_struct().hex(), 'success': True}
            except struct.error:
                data = {'success': False, 'message': 'Transaction invalid'}

        else:
            data = {'success': False, 'message': 'Transaction invalid'}
        return json.dumps(data).encode('utf-8')
Пример #22
0
    def setUp(self):
        super().setUp()
        self.resource = self.create_resource()
        self.web = StubSite(self.resource)

        # Unlocking wallet
        self.manager.wallet.unlock(b'MYPASS')

        # Creating blocks, txs and a conflict tx to test graphviz with it
        add_new_blocks(self.manager, 2, advance_clock=2)
        add_blocks_unlock_reward(self.manager)
        txs = add_new_transactions(self.manager, 2, advance_clock=2)
        tx = txs[0]

        self.tx2 = Transaction.create_from_struct(tx.get_struct())
        self.tx2.parents = [tx.parents[1], tx.parents[0]]
        self.tx2.resolve()

        self.manager.propagate_tx(self.tx2)
Пример #23
0
    def test_balance_update6(self):
        # Tx2 is twin of tx1, so both voided
        # Tx3 has tx1 as parent, so increases tx1 acc weight, then tx1 is winner against tx2

        self.manager.reactor.advance(1)

        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        # Change of parents only, so it's a twin.
        tx2 = Transaction.create_from_struct(self.tx1.get_struct())
        tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
        tx2.resolve()

        address = self.get_address(0)
        value = 100

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value),
                             timelock=None)
        ]

        tx3 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs)
        tx3.weight = 10
        tx3.parents = [self.tx1.hash, self.tx1.parents[0]]
        tx3.timestamp = int(self.clock.seconds())
        tx3.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.manager.propagate_tx(tx3)
        self.run_to_completion()

        # Balance is the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance - 100))
Пример #24
0
    def test_spend_multisig(self):
        # Adding funds to the wallet
        # XXX: note further down the test, 20.00 HTR will be used, block_count must yield at least that amount
        block_count = 3  # 3 * 8.00 -> 24.00 HTR is enough
        blocks = add_new_blocks(self.manager, block_count, advance_clock=15)
        add_blocks_unlock_reward(self.manager)
        blocks_tokens = [sum(txout.value for txout in blk.outputs) for blk in blocks]
        available_tokens = sum(blocks_tokens)
        self.assertEqual(self.manager.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, available_tokens))

        # First we send tokens to a multisig address
        block_reward = blocks_tokens[0]
        outputs = [WalletOutputInfo(address=self.multisig_address, value=block_reward, timelock=None)]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()
        self.manager.propagate_tx(tx1)
        self.clock.advance(10)

        wallet_balance = WalletBalance(0, available_tokens - block_reward)
        self.assertEqual(self.manager.wallet.balance[settings.HATHOR_TOKEN_UID], wallet_balance)

        # Then we create a new tx that spends this tokens from multisig wallet
        tx = Transaction.create_from_struct(tx1.get_struct())
        tx.weight = 10
        tx.parents = self.manager.get_new_tx_parents()
        tx.timestamp = int(self.clock.seconds())

        multisig_script = create_output_script(self.multisig_address)

        multisig_output = TxOutput(200, multisig_script)
        wallet_output = TxOutput(300, create_output_script(self.address))
        outside_output = TxOutput(block_reward - 200 - 300, create_output_script(self.outside_address))

        tx.outputs = [multisig_output, wallet_output, outside_output]

        tx_input = TxInput(tx1.hash, 0, b'')
        tx.inputs = [tx_input]

        signatures = []
        for private_key_hex in self.private_keys:
            signature = generate_signature(tx, bytes.fromhex(private_key_hex), password=b'1234')
            signatures.append(signature)

        parser = create_parser()
        # Generate spend tx
        args = parser.parse_args([
            tx.get_struct().hex(), '{},{}'.format(signatures[0].hex(), signatures[1].hex()),
            self.redeem_script.hex()
        ])
        f = StringIO()
        with capture_logs():
            with redirect_stdout(f):
                execute(args)
        # Transforming prints str in array
        output = f.getvalue().strip().splitlines()

        tx_raw = output[0].split(':')[1].strip()

        tx = Transaction.create_from_struct(bytes.fromhex(tx_raw))
        self.assertTrue(self.manager.propagate_tx(tx, False))
Пример #25
0
    def test_spend_multisig(self):
        # Adding funds to the wallet
        blocks = add_new_blocks(self.manager, 2, advance_clock=15)
        add_blocks_unlock_reward(self.manager)
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, sum(blk.outputs[0].value for blk in blocks)))

        first_block_amount = blocks[0].outputs[0].value

        # First we send tokens to a multisig address
        outputs = [
            WalletOutputInfo(address=self.multisig_address,
                             value=first_block_amount,
                             timelock=int(self.clock.seconds()) + 15)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()
        self.manager.propagate_tx(tx1)
        self.clock.advance(10)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, first_block_amount))

        # Then we create a new tx that spends this tokens from multisig wallet
        tx = Transaction.create_from_struct(tx1.get_struct())
        tx.weight = 10
        tx.parents = self.manager.get_new_tx_parents()
        tx.timestamp = int(self.clock.seconds())

        multisig_script = create_output_script(self.multisig_address)

        multisig_output = TxOutput(200, multisig_script)
        wallet_output = TxOutput(300, create_output_script(self.address))
        outside_output = TxOutput(first_block_amount - 200 - 300,
                                  create_output_script(self.outside_address))

        tx.outputs = [multisig_output, wallet_output, outside_output]

        tx_input = TxInput(tx1.hash, 0, b'')
        tx.inputs = [tx_input]

        signatures = []
        for private_key_hex in self.private_keys:
            signature = generate_signature(tx,
                                           bytes.fromhex(private_key_hex),
                                           password=b'1234')
            signatures.append(signature)

        input_data = MultiSig.create_input_data(self.redeem_script, signatures)
        tx.inputs[0].data = input_data

        tx.resolve()
        # Transaction is still locked
        self.assertFalse(self.manager.propagate_tx(tx))

        self.clock.advance(6)
        tx.timestamp = int(self.clock.seconds())
        tx.resolve()

        # First we try to propagate with a P2PKH input
        private_key_obj = get_private_key_from_bytes(bytes.fromhex(
            self.private_keys[0]),
                                                     password=b'1234')
        pubkey_obj = private_key_obj.public_key()
        public_key_compressed = get_public_key_bytes_compressed(pubkey_obj)
        p2pkh_input_data = P2PKH.create_input_data(public_key_compressed,
                                                   signatures[0])
        tx2 = Transaction.create_from_struct(tx.get_struct())
        tx2.inputs[0].data = p2pkh_input_data
        tx2.resolve()
        self.assertFalse(self.manager.propagate_tx(tx2))

        # Now we propagate the correct
        self.assertTrue(self.manager.propagate_tx(tx))

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, first_block_amount + 300))

        # Testing the MultiSig class methods
        cls_script = parse_address_script(multisig_script)
        self.assertTrue(isinstance(cls_script, MultiSig))
        self.assertEqual(cls_script.address, self.multisig_address_b58)

        expected_dict = {
            'type': 'MultiSig',
            'address': self.multisig_address_b58,
            'timelock': None
        }
        self.assertEqual(cls_script.to_human_readable(), expected_dict)

        script_eval(tx, tx_input, tx1)

        # Script error
        with self.assertRaises(ScriptError):
            create_output_script(
                base58.b58decode('55d14K5jMqsN2uwUEFqiPG5SoD7Vr1BfnH'))
Пример #26
0
    def test_balance_update_twin_tx(self):
        # Start balance
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))

        wallet_address = self.manager.wallet.get_unused_address()

        outputs2 = [
            WalletOutputInfo(address=decode_address(wallet_address),
                             value=500,
                             timelock=None)
        ]

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs2)
        tx2.weight = 10
        tx2.parents = self.manager.get_new_tx_parents()
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        outputs3 = [
            WalletOutputInfo(address=decode_address(wallet_address),
                             value=self.blocks_tokens[0],
                             timelock=None)
        ]
        tx3 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs3)
        tx3.weight = 10
        tx3.parents = self.manager.get_new_tx_parents()
        tx3.timestamp = int(self.clock.seconds())
        tx3.resolve()
        self.manager.propagate_tx(tx3)
        self.run_to_completion()

        self.clock.advance(1)
        new_address = self.manager.wallet.get_unused_address_bytes()
        inputs = [WalletInputInfo(tx_id=tx3.hash, index=0, private_key=None)]
        outputs = [
            WalletOutputInfo(address=new_address,
                             value=self.blocks_tokens[0],
                             timelock=None)
        ]
        tx4 = self.manager.wallet.prepare_transaction_incomplete_inputs(
            Transaction, inputs, outputs, self.manager.tx_storage)
        tx4.weight = 10
        tx4.parents = [tx3.hash, tx3.parents[0]]
        tx4.timestamp = int(self.clock.seconds())
        tx4.resolve()
        self.manager.propagate_tx(tx4)
        self.run_to_completion()

        # Change of parents only, so it's a twin.
        tx5 = Transaction.create_from_struct(tx4.get_struct())
        tx5.parents = [tx4.parents[1], tx4.parents[0]]
        tx5.weight = 10
        tx5.resolve()

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx5)
        self.run_to_completion()

        meta4 = tx4.get_metadata(force_reload=True)
        self.assertEqual(meta4.twins, [tx5.hash])

        meta5 = tx5.get_metadata(force_reload=True)
        self.assertEqual(meta5.voided_by, {tx5.hash})

        # Balance is the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, self.initial_balance))
Пример #27
0
    def test_tx_tips_voided(self):
        from hathor.wallet.base_wallet import WalletOutputInfo

        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)

        address1 = self.get_address(0)
        address2 = self.get_address(1)
        address3 = self.get_address(2)
        output1 = WalletOutputInfo(address=decode_address(address1),
                                   value=123,
                                   timelock=None)
        output2 = WalletOutputInfo(address=decode_address(address2),
                                   value=234,
                                   timelock=None)
        output3 = WalletOutputInfo(address=decode_address(address3),
                                   value=345,
                                   timelock=None)
        outputs = [output1, output2, output3]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 2.0
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()
        self.assertTrue(self.manager.propagate_tx(tx1, False))
        self.assertEqual(
            {
                tx.hash
                for tx in self.manager.tx_storage.indexes.mempool_tips.iter(
                    self.manager.tx_storage)
            }, {tx1.hash})

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx2.weight = 2.0
        tx2.parents = [tx1.hash] + self.manager.get_new_tx_parents()[1:]
        self.assertIn(tx1.hash, tx2.parents)
        tx2.timestamp = int(self.clock.seconds()) + 1
        tx2.resolve()
        self.assertTrue(self.manager.propagate_tx(tx2, False))
        self.assertEqual(
            {
                tx.hash
                for tx in self.manager.tx_storage.indexes.mempool_tips.iter(
                    self.manager.tx_storage)
            }, {tx2.hash})

        tx3 = Transaction.create_from_struct(tx2.get_struct())
        tx3.weight = 3.0
        # tx3.timestamp = tx2.timestamp + 1
        tx3.parents = tx1.parents
        # self.assertIn(tx1.hash, tx3.parents)
        tx3.resolve()
        self.assertNotEqual(tx2.hash, tx3.hash)
        self.assertTrue(self.manager.propagate_tx(tx3, False))
        # self.assertIn(tx3.hash, tx2.get_metadata().voided_by)
        self.assertIn(tx3.hash, tx2.get_metadata().conflict_with)
        self.assertEqual(
            {
                tx.hash
                for tx in self.manager.tx_storage.indexes.mempool_tips.iter(
                    self.manager.tx_storage)
            },
            # XXX: what should we expect here? I don't think we should exclude both tx2 and tx3, but maybe let the
            # function using the index decide
            {tx1.hash, tx3.hash})
Пример #28
0
    def test_struct(self):
        tx = self._gen_tx_spending_genesis_block()
        data = tx.get_struct()
        tx_read = Transaction.create_from_struct(data)

        self.assertEqual(tx, tx_read)
Пример #29
0
    def render_PUT(self, request):
        """ Updates a nano contract tx and returns it in hexadecimal format.

        Post data should be a json with the following items:
        hex_tx: tx being updated, in hex value
        new_values: List[{'address', 'value'}], with bet address and value
        input_value: amount this wallet should stake in the nano contract

        :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'PUT')

        try:
            data = json.loads(request.content.read().decode('utf-8'))
        except json.JSONDecodeError:
            return json.dumps({'success': False, 'message': 'Invalid format for post data'}).encode('utf-8')

        for param in PARAMS_PUT:
            if param not in data:
                return get_missing_params_msg(param)

        try:
            decoded_params = self.decode_put_params(data)
        except ValueError as e:
            return json.dumps({'success': False, 'message': e.message}).encode('utf-8')

        try:
            tx = Transaction.create_from_struct(decoded_params.tx_bytes)
        except struct.error:
            return json.dumps({'success': False, 'message': 'Could not decode hex transaction'}).encode('utf-8')

        tx_outputs = []
        nano_contract = None
        for _output in tx.outputs:
            _nano_contract = NanoContractMatchValues.parse_script(_output.script)
            if _nano_contract:
                total_value = _output.value
                nano_contract = _nano_contract
            else:
                tx_outputs.append(_output)

        if not nano_contract:
            return json.dumps({'success': False, 'message': 'Nano contract not found'}).encode('utf-8')

        for address, value in decoded_params.new_value_dict.items():
            nano_contract.value_dict[address] = value

        tx.outputs = tx_outputs

        inputs, total_inputs_amount = self.manager.wallet.get_inputs_from_amount(
            decoded_params.input_value,
            self.manager.tx_storage
        )
        change_tx = self.manager.wallet.handle_change_tx(total_inputs_amount, decoded_params.input_value)
        if change_tx:
            tx.outputs.append(TxOutput(change_tx.value, P2PKH.create_output_script(change_tx.address)))

        tx.outputs.insert(0, TxOutput(total_value, nano_contract.create_output_script()))

        for txin in inputs:
            tx.inputs.append(TxInput(txin.tx_id, txin.index, b''))

        ret = {'success': True, 'hex_tx': tx.get_struct().hex()}
        return json.dumps(ret).encode('utf-8')
Пример #30
0
def execute(args: Namespace) -> None:
    from hathor.transaction import Transaction

    # Get tx you want to create a twin
    if args.url and args.hash:
        get_tx_url = urllib.parse.urljoin(args.url, 'transaction/')
        response = requests.get(get_tx_url, {b'id': bytes(args.hash, 'utf-8')})

        try:
            data = response.json()
        except JSONDecodeError as e:
            print('Error decoding transaction data')
            print(e)
            return

        tx_bytes = bytes.fromhex(data['tx']['raw'])
    elif args.raw_tx:
        tx_bytes = bytes.fromhex(args.raw_tx)
    else:
        print('The command expects raw_tx or hash and url as parameters')
        return

    try:
        # Create new tx from the twin
        twin = Transaction.create_from_struct(tx_bytes)

        assert len(twin.parents) == 2

        if args.parents:
            # If we want new parents we get the tips and select new ones
            get_tips_url = urllib.parse.urljoin(args.url, 'tips/')

            response = requests.get(get_tips_url)

            try:
                data = response.json()
            except JSONDecodeError as e:
                print('Error decoding tips')
                print(e)
                return

            parents = data[:2]
            if len(parents) == 0:
                print('No available tips to be selected as parents')
                return
            elif len(parents) == 1:
                parents = [parents[0], twin.parents[0].hex()]

            twin.parents = [
                bytes.fromhex(parents[0]),
                bytes.fromhex(parents[1])
            ]
        else:
            # Otherwise we just change the parents position, so we can have a different hash
            twin.parents = [twin.parents[1], twin.parents[0]]

        if args.weight:
            twin.weight = args.weight

        twin.resolve()
        if args.human:
            print(twin.to_json())
        else:
            print(twin.get_struct().hex())
    except (struct.error, ValueError):
        print('Error getting transaction from bytes')
        return