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())
    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))
Example #5
0
    def test_choose_inputs(self):
        blocks = add_new_blocks(self.manager, 1, advance_clock=15)
        blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]
        add_blocks_unlock_reward(self.manager)

        address = self.manager.wallet.get_unused_address(mark_as_used=False)

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=blocks_tokens[0],
                             timelock=int(self.clock.seconds()) + 10)
        ]

        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(1)

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

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

        with self.assertRaises(InsufficientFunds):
            self.manager.wallet.prepare_transaction_compute_inputs(
                Transaction, outputs, self.manager.tx_storage)

        self.clock.advance(10)

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        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.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, blocks_tokens[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))
Example #7
0
    def test_transaction_and_balance(self):
        # generate a new block and check if we increase balance
        new_address = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), self.TOKENS, timelock=None)
        block = add_new_block(self.manager)
        block.verify()
        utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get((block.hash, 0))
        self.assertIsNotNone(utxo)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.BLOCK_TOKENS))

        # create transaction spending this value, but sending to same wallet
        new_address2 = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address2), self.TOKENS, timelock=None)
        tx1 = self.wallet.prepare_transaction_compute_inputs(Transaction, outputs=[out])
        tx1.update_hash()
        tx1.verify_script(tx1.inputs[0], block)
        tx1.storage = self.tx_storage
        self.wallet.on_new_tx(tx1)
        self.tx_storage.save_transaction(tx1)
        self.assertEqual(len(self.wallet.spent_txs), 1)
        utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get((tx1.hash, 0))
        self.assertIsNotNone(utxo)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS))

        # pass inputs and outputs to prepare_transaction, but not the input keys
        # spend output last transaction
        input_info = WalletInputInfo(tx1.hash, 0, None)
        new_address3 = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address3), self.TOKENS, timelock=None)
        tx2 = self.wallet.prepare_transaction_incomplete_inputs(Transaction, inputs=[input_info],
                                                                outputs=[out], tx_storage=self.tx_storage)
        tx2.storage = self.tx_storage
        tx2.update_hash()
        tx2.storage = self.tx_storage
        tx2.verify_script(tx2.inputs[0], tx1)
        self.tx_storage.save_transaction(tx2)
        self.wallet.on_new_tx(tx2)
        self.assertEqual(len(self.wallet.spent_txs), 2)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS))

        # Test getting more unused addresses than the gap limit
        for i in range(3):
            kwargs = {'mark_as_used': True}
            if i == 2:
                # Last one we dont mark as used
                kwargs['mark_as_used'] = False

            self.wallet.get_unused_address(**kwargs)
    def test_tokens_balance(self):
        # create tokens and check balances

        # initial tokens
        address_b58 = self.manager.wallet.get_unused_address()
        address = decode_address(address_b58)
        tx = create_tokens(self.manager, address_b58)
        token_id = tx.tokens[0]
        amount = tx.outputs[0].value

        # initial token balance
        self.assertEqual(self.manager.wallet.balance[token_id],
                         WalletBalance(0, amount))
        # initial hathor balance
        # we don't consider HTR balance 0 because we transfer genesis tokens to this
        # wallet during token creation
        hathor_balance = self.manager.wallet.balance[settings.HATHOR_TOKEN_UID]

        # transfer token to another wallet and check balance again
        parents = self.manager.get_new_tx_parents()
        _input1 = TxInput(tx.hash, 0, b'')
        script = P2PKH.create_output_script(address)
        token_output1 = TxOutput(30, b'', 0b00000001)
        token_output2 = TxOutput(amount - 30, script, 0b00000001)
        tx2 = Transaction(weight=1,
                          inputs=[_input1],
                          outputs=[token_output1, token_output2],
                          parents=parents,
                          tokens=[token_id],
                          storage=self.manager.tx_storage,
                          timestamp=int(self.manager.reactor.seconds()))
        data_to_sign = tx2.get_sighash_all(clear_input_data=True)
        public_bytes, signature = self.manager.wallet.get_input_aux_data(
            data_to_sign, self.manager.wallet.get_private_key(address_b58))
        tx2.inputs[0].data = P2PKH.create_input_data(public_bytes, signature)
        tx2.resolve()
        tx2.verify()
        self.manager.propagate_tx(tx2)
        self.run_to_completion()
        # verify balance
        self.assertEqual(self.manager.wallet.balance[token_id],
                         WalletBalance(0, amount - 30))
        # hathor balance remains the same
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            hathor_balance)
Example #9
0
 def test_balance(self):
     self.factory.connections.add(self.protocol)
     self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN
     self.manager.pubsub.publish(HathorEvents.WALLET_BALANCE_UPDATED,
                                 balance={settings.HATHOR_TOKEN_UID: WalletBalance(10, 20)})
     self.run_to_completion()
     value = self._decode_value(self.transport.value())
     self.assertEqual(value['balance']['locked'], 10)
     self.assertEqual(value['balance']['available'], 20)
     self.assertEqual(value['type'], 'wallet:balance_updated')
    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))
Example #11
0
 def test_block_increase_balance(self):
     # generate a new block and check if we increase balance
     w = Wallet(directory=self.directory)
     w.unlock(PASSWORD)
     new_address = w.get_unused_address()
     key = w.keys[new_address]
     out = WalletOutputInfo(decode_address(key.address),
                            BLOCK_REWARD,
                            timelock=None)
     tx = w.prepare_transaction(Transaction, inputs=[], outputs=[out])
     tx.update_hash()
     w.on_new_tx(tx)
     utxo = w.unspent_txs[settings.HATHOR_TOKEN_UID].get((tx.hash, 0))
     self.assertIsNotNone(utxo)
     self.assertEqual(w.balance[settings.HATHOR_TOKEN_UID],
                      WalletBalance(0, BLOCK_REWARD))
Example #12
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))
Example #13
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'))
    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))
Example #15
0
    def test_wallet_create_transaction(self):
        genesis_private_key_bytes = get_private_key_bytes(
            self.genesis_private_key,
            encryption_algorithm=serialization.BestAvailableEncryption(
                PASSWORD))
        genesis_address = get_address_b58_from_public_key(
            self.genesis_public_key)
        # create wallet with genesis block key
        key_pair = KeyPair(private_key_bytes=genesis_private_key_bytes,
                           address=genesis_address,
                           used=True)
        keys = {}
        keys[key_pair.address] = key_pair
        w = Wallet(keys=keys, directory=self.directory)
        w.unlock(PASSWORD)
        genesis_blocks = [
            tx for tx in get_genesis_transactions(None) if tx.is_block
        ]
        genesis_block = genesis_blocks[0]
        genesis_value = sum([output.value for output in genesis_block.outputs])

        # wallet will receive genesis block and store in unspent_tx
        w.on_new_tx(genesis_block)
        for index in range(len(genesis_block.outputs)):
            utxo = w.unspent_txs[settings.HATHOR_TOKEN_UID].get(
                (genesis_block.hash, index))
            self.assertIsNotNone(utxo)
        self.assertEqual(w.balance[settings.HATHOR_TOKEN_UID],
                         WalletBalance(0, genesis_value))

        # create transaction spending this value, but sending to same wallet
        new_address = w.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), 100, timelock=None)
        tx1 = w.prepare_transaction_compute_inputs(Transaction, outputs=[out])
        tx1.storage = self.storage
        tx1.update_hash()
        self.storage.save_transaction(tx1)
        w.on_new_tx(tx1)
        self.assertEqual(len(w.spent_txs), 1)
        self.assertEqual(w.balance[settings.HATHOR_TOKEN_UID],
                         WalletBalance(0, genesis_value))

        # pass inputs and outputs to prepare_transaction, but not the input keys
        # spend output last transaction
        input_info = WalletInputInfo(tx1.hash, 1, None)
        new_address = w.get_unused_address()
        key2 = w.keys[new_address]
        out = WalletOutputInfo(decode_address(key2.address),
                               100,
                               timelock=None)
        tx2 = w.prepare_transaction_incomplete_inputs(Transaction,
                                                      inputs=[input_info],
                                                      outputs=[out],
                                                      tx_storage=self.storage)
        tx2.storage = self.storage
        tx2.update_hash()
        self.storage.save_transaction(tx2)
        w.on_new_tx(tx2)
        self.assertEqual(len(w.spent_txs), 2)
        self.assertEqual(w.balance[settings.HATHOR_TOKEN_UID],
                         WalletBalance(0, genesis_value))

        # test keypair exception
        with self.assertRaises(WalletLocked):
            key_pair.get_private_key(None)
Example #16
0
    def test_timelock(self):
        blocks = add_new_blocks(self.manager, 5, advance_clock=15)
        blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]
        add_blocks_unlock_reward(self.manager)

        address = self.manager.wallet.get_unused_address()
        outside_address = self.get_address(0)

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=500,
                             timelock=int(self.clock.seconds()) + 10),
            WalletOutputInfo(address=decode_address(address),
                             value=700,
                             timelock=int(self.clock.seconds()) - 10),
            WalletOutputInfo(address=decode_address(address),
                             value=sum(blocks_tokens[:2]) - 500 - 700,
                             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.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(500,
                          sum(blocks_tokens) - 500))

        self.clock.advance(1)

        outputs1 = [
            WalletOutputInfo(address=decode_address(outside_address),
                             value=500,
                             timelock=None)
        ]

        inputs1 = [WalletInputInfo(tx_id=tx1.hash, index=0, private_key=None)]

        tx2 = self.manager.wallet.prepare_transaction_incomplete_inputs(
            Transaction, inputs1, outputs1, self.manager.tx_storage)
        tx2.weight = 10
        tx2.parents = self.manager.get_new_tx_parents()
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        propagated = self.manager.propagate_tx(tx2)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(500,
                          sum(blocks_tokens) - 500))
        self.assertFalse(propagated)

        self.clock.advance(1)

        outputs2 = [
            WalletOutputInfo(address=decode_address(outside_address),
                             value=700,
                             timelock=None)
        ]

        inputs2 = [WalletInputInfo(tx_id=tx1.hash, index=1, private_key=None)]

        tx3 = self.manager.wallet.prepare_transaction_incomplete_inputs(
            Transaction, inputs2, outputs2, self.manager.tx_storage)
        tx3.weight = 10
        tx3.parents = self.manager.get_new_tx_parents()
        tx3.timestamp = int(self.clock.seconds())
        tx3.resolve()
        propagated = self.manager.propagate_tx(tx3, False)
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(500,
                          sum(blocks_tokens) - 500 - 700))
        self.assertTrue(propagated)
        self.clock.advance(1)

        outputs3 = [
            WalletOutputInfo(address=decode_address(outside_address),
                             value=sum(blocks_tokens[:2]) - 500 - 700,
                             timelock=None)
        ]

        inputs3 = [WalletInputInfo(tx_id=tx1.hash, index=2, private_key=None)]

        tx4 = self.manager.wallet.prepare_transaction_incomplete_inputs(
            Transaction, inputs3, outputs3, self.manager.tx_storage)
        tx4.weight = 10
        tx4.parents = self.manager.get_new_tx_parents()
        tx4.timestamp = int(self.clock.seconds())
        tx4.resolve()
        propagated = self.manager.propagate_tx(tx4, False)
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(500, sum(blocks_tokens[:3])))
        self.assertTrue(propagated)

        self.clock.advance(8)
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        propagated = self.manager.propagate_tx(tx2, False)
        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, sum(blocks_tokens[:3])))
        self.assertTrue(propagated)