Ejemplo n.º 1
0
    def run_test(self):
        node0_address = self.nodes[0].getnewaddress()
        # Spend block 1/2/3's coinbase transactions
        # Mine a block.
        # Create three more transactions, spending the spends
        # Mine another block.
        # ... make sure all the transactions are confirmed
        # Invalidate both blocks
        # ... make sure all the transactions are put back in the mempool
        # Mine a new block
        # ... make sure all the transactions are confirmed again.

        b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
        spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]

        blocks = []
        blocks.extend(self.nodes[0].generate(1))

        spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.98) for txid in spends1_id]
        spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]

        blocks.extend(self.nodes[0].generate(1))

        # mempool should be empty, all txns confirmed
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        for txid in spends1_id+spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert(tx["confirmations"] > 0)

        # Use invalidateblock to re-org back; all transactions should
        # end up unconfirmed and back in the mempool
        for node in self.nodes:
            node.invalidateblock(blocks[0])

        # mempool should be empty, all txns confirmed
        assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
        for txid in spends1_id+spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert(tx["confirmations"] == 0)

        # Generate another block, they should all get mined
        self.nodes[0].generate(1)
        # mempool should be empty, all txns confirmed
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        for txid in spends1_id+spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert(tx["confirmations"] > 0)
Ejemplo n.º 2
0
    def run_test(self):
        chain_height = self.nodes[0].getblockcount()
        assert_equal(chain_height, 200)
        node0_address = self.nodes[0].getnewaddress()

        # Coinbase at height chain_height-100+1 ok in mempool, should
        # get mined. Coinbase at height chain_height-100+2 is
        # is too immature to spend.
        b = [self.nodes[0].getblockhash(n) for n in range(101, 103)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spends_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]

        spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])

        # coinbase at height 102 should be too immature to spend
        assert_raises_rpc_error(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1])

        # mempool should have just spend_101:
        assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])

        # mine a block, spend_101 should get confirmed
        self.nodes[0].generate(1)
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        # ... and now height 102 can be spent:
        spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
        assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
Ejemplo n.º 3
0
    def run_test(self):
        # Start with a 200 block chain
        assert_equal(self.nodes[0].getblockcount(), 200)

        # Mine four blocks. After this, nodes[0] blocks
        # 101, 102, and 103 are spend-able.
        new_blocks = self.nodes[1].generate(4)
        self.sync_all()

        node0_address = self.nodes[0].getnewaddress()
        node1_address = self.nodes[1].getnewaddress()

        # Three scenarios for re-orging coinbase spends in the memory pool:
        # 1. Direct coinbase spend  :  spend_101
        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
        # and make sure the mempool code behaves correctly.
        b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ]
        coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
        spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99, fee=0.01)
        spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99, fee=0.01)
        spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99, fee=0.01)

        # Create a transaction which is time-locked to two blocks in the future
        timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99, "fee": 0.01})
        # Set the time lock
        timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
        timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
        timelock_tx = self.nodes[0].signrawtransactionwithwallet(timelock_tx)["hex"]
        # This will raise an exception because the timelock transaction is too immature to spend
        assert_raises_rpc_error(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx)

        # Broadcast and mine spend_102 and 103:
        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
        self.nodes[0].generate(1)
        # Time-locked transaction is still too immature to spend
        assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx)

        # Create 102_1 and 103_1:
        spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98, fee=0.01)
        spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98, fee=0.01)

        # Broadcast and mine 103_1:
        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
        last_block = self.nodes[0].generate(1)
        # Time-locked transaction can now be spent
        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)

        # ... now put spend_101 and spend_102_1 in memory pools:
        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)

        self.sync_all()

        assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id})

        for node in self.nodes:
            node.invalidateblock(last_block[0])
        # Time-locked transaction is now too immature and has been removed from the mempool
        # spend_103_1 has been re-orged out of the chain and is back in the mempool
        assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})

        # Use invalidateblock to re-org back and make all those coinbase spends
        # immature/invalid:
        for node in self.nodes:
            node.invalidateblock(new_blocks[0])

        self.sync_all()

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())
Ejemplo n.º 4
0
    def run_test(self):
        # Start with a 200 block chain
        assert_equal(self.nodes[0].getblockcount(), 200)

        # Mine four blocks. After this, nodes[0] blocks
        # 101, 102, and 103 are spend-able.
        new_blocks = self.nodes[1].generate(4)
        self.sync_all()

        node0_address = self.nodes[0].getnewaddress()
        node1_address = self.nodes[1].getnewaddress()

        # Three scenarios for re-orging coinbase spends in the memory pool:
        # 1. Direct coinbase spend  :  spend_101
        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
        # and make sure the mempool code behaves correctly.
        b = [self.nodes[0].getblockhash(n) for n in range(101, 105)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spend_101_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[1],
                                               node1_address, 49.99)
        spend_102_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[2],
                                               node0_address, 49.99)
        spend_103_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[3],
                                               node0_address, 49.99)

        # Create a transaction which is time-locked to two blocks in the future
        timelock_tx = self.nodes[0].createrawtransaction(
            [{
                "txid": coinbase_txids[0],
                "vout": 0
            }], {node0_address: 49.99})
        # Set the time lock
        timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
        timelock_tx = timelock_tx[:-8] + \
            hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
        timelock_tx = self.nodes[0].signrawtransactionwithwallet(
            timelock_tx)["hex"]
        # This will raise an exception because the timelock transaction is too
        # immature to spend
        assert_raises_rpc_error(-26, "bad-txns-nonfinal",
                                self.nodes[0].sendrawtransaction, timelock_tx)

        # Broadcast and mine spend_102 and 103:
        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
        self.nodes[0].generate(1)
        # Time-locked transaction is still too immature to spend
        assert_raises_rpc_error(-26, 'bad-txns-nonfinal',
                                self.nodes[0].sendrawtransaction, timelock_tx)

        # Create 102_1 and 103_1:
        spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id,
                                                 node1_address, 49.98)
        spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id,
                                                 node1_address, 49.98)

        # Broadcast and mine 103_1:
        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
        last_block = self.nodes[0].generate(1)
        # Sync blocks, so that peer 1 gets the block before timelock_tx
        # Otherwise, peer 1 would put the timelock_tx in recentRejects
        self.sync_all()

        # Time-locked transaction can now be spent
        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)

        # ... now put spend_101 and spend_102_1 in memory pools:
        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)

        self.sync_all()

        assert_equal(set(self.nodes[0].getrawmempool()),
                     {spend_101_id, spend_102_1_id, timelock_tx_id})

        for node in self.nodes:
            node.invalidateblock(last_block[0])
        # Time-locked transaction is now too immature and has been removed from the mempool
        # spend_103_1 has been re-orged out of the chain and is back in the
        # mempool
        assert_equal(set(self.nodes[0].getrawmempool()),
                     {spend_101_id, spend_102_1_id, spend_103_1_id})

        # Use invalidateblock to re-org back and make all those coinbase spends
        # immature/invalid:
        for node in self.nodes:
            node.invalidateblock(new_blocks[0])

        self.sync_all()

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())
Ejemplo n.º 5
0
    def run_test(self):
        node0_address = self.nodes[0].getnewaddress()
        # Spend block 1/2/3's coinbase transactions
        # Mine a block.
        # Create three more transactions, spending the spends
        # Mine another block.
        # ... make sure all the transactions are confirmed
        # Invalidate both blocks
        # ... make sure all the transactions are put back in the mempool
        # Mine a new block
        # ... make sure all the transactions are confirmed again.

        b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spends1_raw = [
            create_raw_transaction(self.nodes[0],
                                   txid,
                                   node0_address,
                                   amount=49.99) for txid in coinbase_txids
        ]
        spends1_id = [
            self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw
        ]

        blocks = []
        blocks.extend(self.nodes[0].generate(1))

        spends2_raw = [
            create_raw_transaction(self.nodes[0],
                                   txid,
                                   node0_address,
                                   amount=49.98) for txid in spends1_id
        ]
        spends2_id = [
            self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw
        ]

        blocks.extend(self.nodes[0].generate(1))

        # mempool should be empty, all txns confirmed
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        for txid in spends1_id + spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert tx["confirmations"] > 0

        # Use invalidateblock to re-org back
        for node in self.nodes:
            node.invalidateblock(blocks[0])

        # All txns should be back in mempool with 0 confirmations
        assert_equal(set(self.nodes[0].getrawmempool()),
                     set(spends1_id + spends2_id))
        for txid in spends1_id + spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert tx["confirmations"] == 0

        # Generate another block, they should all get mined
        self.nodes[0].generate(1)
        # mempool should be empty, all txns confirmed
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        for txid in spends1_id + spends2_id:
            tx = self.nodes[0].gettransaction(txid)
            assert tx["confirmations"] > 0
Ejemplo n.º 6
0
    def run_test(self):
        for node in self.nodes:
            node.generate(25)
            self.sync_all()
        self.nodes[0].generate(COINBASE_MATURITY)
        self.sync_all()

        start_count = self.nodes[0].getblockcount()

        # Mine three blocks. After this, nodes[0] blocks
        # 101, 102, and 103 are spend-able.
        new_blocks = self.nodes[1].generate(4)
        self.sync_all()
        assert_equal(self.nodes[0].getblockcount(),
                     self.nodes[1].getblockcount())

        node0_address = self.nodes[0].getnewaddress()
        node1_address = self.nodes[1].getnewaddress()

        # Three scenarios for re-orging coinbase spends in the memory pool:
        # 1. Direct coinbase spend  :  spend_101
        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
        # and make sure the mempool code behaves correctly.
        b = [self.nodes[0].getblockhash(n) for n in range(51, 55)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spend_101_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[1],
                                               node1_address,
                                               amount=INITIAL_BLOCK_REWARD -
                                               0.01)
        spend_102_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[2],
                                               node0_address,
                                               amount=INITIAL_BLOCK_REWARD -
                                               0.01)
        spend_103_raw = create_raw_transaction(self.nodes[0],
                                               coinbase_txids[3],
                                               node0_address,
                                               amount=INITIAL_BLOCK_REWARD -
                                               0.01)

        # Create a block-height-locked transaction which will be invalid after reorg
        timelock_tx = self.nodes[0].createrawtransaction(
            [{
                "txid": coinbase_txids[0],
                "vout": 0
            }], {node0_address: INITIAL_BLOCK_REWARD - 0.01})
        # Set the time lock
        timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
        timelock_tx = timelock_tx[:-8] + hex(
            self.nodes[0].getblockcount() +
            2)[3:] + "0" + hex(self.nodes[0].getblockcount() + 2)[2:3] + "0000"
        timelock_tx = self.nodes[0].signrawtransactionwithwallet(
            timelock_tx)["hex"]
        # This will raise an exception because the timelock transaction is too immature to spend
        assert_raises_rpc_error(-26, "non-final",
                                self.nodes[0].sendrawtransaction, timelock_tx)

        # Broadcast and mine spend_102 and 103:
        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
        self.nodes[0].generate(1)
        # Time-locked transaction is still too immature to spend
        assert_raises_rpc_error(-26, 'non-final',
                                self.nodes[0].sendrawtransaction, timelock_tx)

        # Create 102_1 and 103_1:
        spend_102_1_raw = create_raw_transaction(self.nodes[0],
                                                 spend_102_id,
                                                 node1_address,
                                                 amount=INITIAL_BLOCK_REWARD -
                                                 Decimal('0.02'))
        spend_103_1_raw = create_raw_transaction(self.nodes[0],
                                                 spend_103_id,
                                                 node1_address,
                                                 amount=INITIAL_BLOCK_REWARD -
                                                 Decimal('0.02'))

        # Broadcast and mine 103_1:
        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
        last_block = self.nodes[0].generate(1)
        # Time-locked transaction can now be spent
        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)

        # ... now put spend_101 and spend_102_1 in memory pools:
        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)

        self.sync_all()

        assert_equal(set(self.nodes[0].getrawmempool()),
                     {spend_101_id, spend_102_1_id, timelock_tx_id})

        for node in self.nodes:
            node.invalidateblock(last_block[0])
        # Time-locked transaction is now too immature and has been removed from the mempool
        # spend_103_1 has been re-orged out of the chain and is back in the mempool
        assert_equal(set(self.nodes[0].getrawmempool()),
                     {spend_101_id, spend_102_1_id, spend_103_1_id})

        # Use invalidateblock to re-org back and make all those coinbase spends
        # immature/invalid:
        for node in self.nodes:
            node.invalidateblock(new_blocks[0])

        self.sync_all()

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())
    def basic_check(self):
        """Tests basic getdsproof/getdsprooflist functionality"""

        self.generate(self.nodes[0], 1)
        self.sync_all()

        # Create and mine a regular non-coinbase transaction for spending
        funding_txid = self.nodes[0].getblock(
            self.nodes[0].getblockhash(1))['tx'][0]

        # Create three conflicting transactions. They are only signed, but not yet submitted to the mempool
        first_ds_tx = create_raw_transaction(self.nodes[0], funding_txid,
                                             self.nodes[0].getnewaddress(),
                                             49.95)
        second_ds_tx = create_raw_transaction(self.nodes[0], funding_txid,
                                              self.nodes[0].getnewaddress(),
                                              49.95)

        first_ds_tx_id = self.nodes[0].sendrawtransaction(first_ds_tx)
        assert_equal(self.nodes[0].getdsproofscore(first_ds_tx_id),
                     1.0)  # score is 1.0 until we see a dsproof
        second_ds_tx_id = self.nodes[1].call_rpc(
            'sendrawtransaction',
            second_ds_tx,
            ignore_error='txn-mempool-conflict')

        vout = find_output(self.nodes[0], first_ds_tx_id, Decimal('49.95'))
        child = create_raw_transaction(self.nodes[0], first_ds_tx_id,
                                       self.nodes[0].getnewaddress(), 49.90,
                                       vout)
        child_id = self.nodes[0].sendrawtransaction(child)

        vout = find_output(self.nodes[0], child_id, Decimal('49.90'))
        grandchild = create_raw_transaction(self.nodes[0], child_id,
                                            self.nodes[0].getnewaddress(),
                                            49.85, vout)
        grandchild_id = self.nodes[0].sendrawtransaction(grandchild)
        # Wait until both nodes see the same dsproof
        wait_until(lambda: len(self.nodes[0].getdsprooflist()) == 1 and len(
            self.nodes[1].getdsprooflist()) == 1,
                   timeout=10)

        assert_equal(self.nodes[0].getdsproofscore(first_ds_tx_id),
                     0.0)  # score is 0 after we see a dsproof

        dsplist = self.nodes[0].getdsprooflist()
        assert_equal(len(dsplist), 1)
        assert isinstance(dsplist[0], str)
        assert isinstance(self.nodes[0].getdsprooflist(1)[0], dict)

        # Get a DSP by DspId
        dsp = self.nodes[0].getdsproof(dsplist[0])
        dsp_node1 = self.nodes[1].getdsproof(dsplist[0])
        # each node has the same dsproof, but associated with the txid it sees in mempool
        assert_equal(dsp["txid"], first_ds_tx_id)
        if second_ds_tx_id is not None:
            # common case where node1 saw the RPC tx2 before the p2p tx1
            assert_equal(dsp_node1["txid"], second_ds_tx_id)
        else:
            # node1 happened to see the first tx via p2p first
            assert_equal(dsp_node1["txid"], first_ds_tx_id)
        # we expect this dsp tx to invalidate 3 tx's total (parent, child, and grandchild)
        assert_equal(len(dsp["descendants"]), 3)
        # Check that the dsp has the "outpoint" key and it is what we expect
        ds_outpoint = {"txid": funding_txid, "vout": 0}
        assert_equal(dsp["outpoint"], ds_outpoint)

        # Get a DSP by double spending txid
        assert "txid" in self.nodes[0].getdsproof(first_ds_tx_id)

        # Get a DSP by txid of a transaction in a double spent chain
        assert_equal(len(self.nodes[0].getdsproof(child_id)["path"]), 2)
        assert_equal(len(self.nodes[0].getdsproof(grandchild_id)["path"]), 3)

        # A non-recursive call for the double spent transaction will result in a DSP
        assert self.nodes[0].getdsproof(first_ds_tx_id, 0, False) is not None
        # A non-recursive call for a child transaction in the double spent chain
        # will not result in a DSP
        assert self.nodes[0].getdsproof(child_id, 0, False) is None

        # Check that the list and the get calls outputs match for the same verbosity level,
        # and that they contain the keys we expect for each verbosity level
        verb_keys = {
            1: {"txid", "hex"},
            2: {"dspid", "txid", "outpoint"},
            3: {"dspid", "txid", "outpoint", "spenders"},
        }
        spenders_keys = {
            "txversion", "sequence", "locktime", "hashprevoutputs",
            "hashsequence", "hashoutputs", "pushdata"
        }
        for verbosity in (1, 2, 3):
            dspid = dsplist[0]
            dsp = self.nodes[0].getdsproof(dspid, verbosity)
            dsp.pop("descendants",
                    None)  # Remove key that is missing from the list mode
            dlist = self.nodes[0].getdsprooflist(verbosity)
            for dsp2 in dlist:
                if dsp == dsp2:
                    break
            else:
                assert False, "Could not find the dsp we expected in the dsplist"
            assert_equal(dsp["txid"],
                         first_ds_tx_id)  # ensure txid always what we expect
            expected_keys = verb_keys[verbosity]
            assert_equal(expected_keys & set(dsp.keys()), expected_keys)
            if "dspid" in expected_keys:
                assert_equal(dsp["dspid"], dspid)
            if "outpoint" in expected_keys:
                assert_equal(dsp["outpoint"], ds_outpoint)
            if "spenders" in expected_keys:
                for spender in dsp["spenders"]:
                    assert_equal(spenders_keys & set(spender.keys()),
                                 spenders_keys)
            if "hex" in expected_keys:
                # ensure that the dsproof hex data decodes ok
                data = bytes.fromhex(dsp["hex"])
                # dsproof serialized data cannot be smaller than 216 bytes
                assert_greater_than(len(data), 216)

        # If any of the competing transactions is mined, the DPSs are put in the orphan list
        self.generate(self.nodes[0], 1)
        self.sync_all()
        assert_equal(len(self.nodes[0].getdsprooflist()),
                     0)  # no non-orphan results
        dsps_all_orphans = self.nodes[0].getdsprooflist(0, True)
        assert_equal(dsps_all_orphans,
                     dsplist)  # all of the previous proofs are orphans
        for dspid in dsps_all_orphans:
            # make sure they are all orphans by checking they have no 'txid' key
            assert self.nodes[0].getdsproof(dspid).get('txid') is None
    def paths_check(self):
        """Check that:
         - the 'paths' key in a lookup by child txid works as expected,
         - the 'descendants' key in the lookup of a dsp works as expected. """

        self.generate(self.nodes[0], 1)
        self.sync_all()

        # Create a transaction on a double spent chain with multiple paths back to the DSP
        # The following scenario of txos will occur:
        # A -> B -> C -> D -> E
        #  \           /
        #   -> Z ---->/
        # Where there is a known DSP for A
        # and D contains inputs from C and Z
        # exactly one path from D to A will be found
        # (either [Z->D, A->Z] or [C->D, B->C, A->B])

        paths = [[], []]

        # Here we spend from A to B and Z
        funding_txid = self.nodes[0].getblock(
            self.nodes[0].getblockhash(2))['tx'][0]
        inputs = [{"txid": funding_txid, "vout": 0}]
        b_address = self.nodes[0].getnewaddress()
        z_address = self.nodes[0].getnewaddress()
        outputs = {b_address: 24.99, z_address: 24.99}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signresult = self.nodes[0].signrawtransactionwithwallet(rawtx)
        assert_equal(signresult["complete"], True)
        transaction_2_outputs = signresult['hex']

        doublespendingtransaction = create_raw_transaction(
            self.nodes[0], funding_txid, self.nodes[0].getnewaddress(), 49.97,
            0)

        transaction_2outputs_id = self.nodes[0].sendrawtransaction(
            transaction_2_outputs)
        self.nodes[1].call_rpc('sendrawtransaction',
                               doublespendingtransaction,
                               ignore_error='txn-mempool-conflict')
        paths[0].insert(0,
                        transaction_2outputs_id)  # root of both possible paths
        paths[1].insert(0, transaction_2outputs_id)

        # Here we spend from B to C
        child = create_raw_transaction(self.nodes[0], transaction_2outputs_id,
                                       self.nodes[0].getnewaddress(), 24.96, 0)
        child_id = self.nodes[0].sendrawtransaction(child)
        paths[1].insert(0, child_id)  # exists only on longer path

        d_address = self.nodes[0].getnewaddress()
        vout = find_output(self.nodes[0], child_id, Decimal('24.96'))
        # Here we spend from Z and C to D
        inputs = [{
            "txid": transaction_2outputs_id,
            "vout": 1
        }, {
            "txid": child_id,
            "vout": vout
        }]
        outputs = {d_address: 49.94}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signresult = self.nodes[0].signrawtransactionwithwallet(rawtx)
        assert_equal(signresult["complete"], True)
        transaction_2inputs = signresult['hex']
        transaction_2inputs_id = self.nodes[0].sendrawtransaction(
            transaction_2inputs)
        paths[0].insert(
            0, transaction_2inputs_id)  # exists of both possible paths
        paths[1].insert(0, transaction_2inputs_id)

        # add 1 more grandchild tx for good measure
        e_tx = create_raw_transaction(self.nodes[0], transaction_2inputs_id,
                                      self.nodes[0].getnewaddress(), 24.95 * 2,
                                      0)
        e_txid = self.nodes[0].sendrawtransaction(e_tx)
        paths_shorter = deepcopy(paths)
        paths[0].insert(0, e_txid)  # leaf tx of both possible paths
        paths[1].insert(0, e_txid)

        wait_until(lambda: len(self.nodes[0].getdsprooflist()) == 1,
                   timeout=10)
        dsplist = self.nodes[0].getdsprooflist()
        self.log.info(f"dsplist: {dsplist}")
        dsp = self.nodes[0].getdsproof(dsplist[0])
        descendants_expected = {txid for txid in paths[0] + paths[1]}
        self.log.info(
            f"dsp: {dsp} descendants_expected: {descendants_expected}")
        assert_equal(set(dsp["descendants"]), descendants_expected)

        dsp = self.nodes[0].getdsproof(e_txid)
        self.log.info(f"dsp: {dsp}, paths: {paths}")
        assert dsp is not None
        assert "path" in dsp
        # make sure the path from query txid to double-spend txid is one of the two possible paths
        assert dsp["path"] in paths
        self.log.info(f"dsp: {dsp}")
        self.log.info(f"dsp path len: {len(dsp['path'])}")
        assert_equal(dsp["txid"], transaction_2outputs_id)

        # now go up one, query by previous txid, we should get a shorter path
        dsp2 = self.nodes[0].getdsproof(transaction_2inputs_id)
        assert dsp2 != dsp
        assert dsp2["path"] in paths_shorter
        assert_equal(dsp2["descendants"], dsp["descendants"])
        assert_equal(dsp2["dspid"], dsp["dspid"])
        assert_equal(dsp2["txid"], dsp["txid"])
Ejemplo n.º 9
0
    def run_test(self):

        node = self.nodes[0]
        self.setup_stake_coins(node)

        first_3_blocks = node.generate(3)

        # Let's lock the first 3 coinbase txs so we can used them later
        for block_id in first_3_blocks:
            node.lockunspent(False, [{"txid": node.getblock(block_id)['tx'][0], "vout": 0}])

        # Make the first 3 coinbase mature now
        node.generate(102)
        assert_equal(node.getblockcount(), 105)
        assert_finalizationstate(node, {'currentDynasty': 18,
                                        'currentEpoch': 21,
                                        'lastJustifiedEpoch': 20,
                                        'lastFinalizedEpoch': 19})

        node0_address = node.getnewaddress("", "bech32")
        # Spend block 1/2/3's coinbase transactions
        # Mine a block.
        # Create three more transactions, spending the spends
        # Mine another block.
        # ... make sure all the transactions are confirmed
        # Invalidate both blocks
        # ... make sure all the transactions are put back in the mempool
        # Mine a new block
        # ... make sure all the transactions are confirmed again.

        b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=PROPOSER_REWARD - Decimal('0.01')) for txid in coinbase_txids]
        spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]

        blocks = []
        blocks.extend(node.generate(1))

        spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=PROPOSER_REWARD - Decimal('0.02')) for txid in spends1_id]
        spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]

        blocks.extend(node.generate(1))

        # mempool should be empty, all txns confirmed
        assert_equal(set(node.getrawmempool()), set())
        for txid in spends1_id+spends2_id:
            tx = node.gettransaction(txid)
            assert tx["confirmations"] > 0

        # Use invalidateblock to re-org back
        for node in self.nodes:
            node.invalidateblock(blocks[0])

        # All txns should be back in mempool with 0 confirmations
        assert_equal(set(node.getrawmempool()), set(spends1_id+spends2_id))
        for txid in spends1_id+spends2_id:
            tx = node.gettransaction(txid)
            assert tx["confirmations"] == 0

        # Generate another block, they should all get mined
        node.generate(1)
        # mempool should be empty, all txns confirmed
        assert_equal(set(node.getrawmempool()), set())
        for txid in spends1_id+spends2_id:
            tx = node.gettransaction(txid)
            assert tx["confirmations"] > 0