示例#1
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))
示例#2
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
        add_blocks_unlock_reward(self.manager)
        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, [out], self.tx_storage)
        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)
示例#3
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)
        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)
示例#4
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, 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.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, self.manager.tx_storage)
        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))
示例#5
0
    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))
示例#6
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 self.storage.get_all_genesis() 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
        add_blocks_unlock_reward(self.manager)
        new_address = w.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), 100, timelock=None)
        tx1 = w.prepare_transaction_compute_inputs(Transaction, [out],
                                                   self.storage)
        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)