示例#1
0
 def test_single_node_session_timeout(self, do_cycle_llmqs):
     set_node_times(self.nodes, self.mocktime)
     isolate_node(self.nodes[3])
     rawtx = self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})
     rawtx = self.nodes[0].fundrawtransaction(rawtx)['hex']
     rawtx = self.nodes[0].signrawtransaction(rawtx)['hex']
     txid = self.nodes[3].sendrawtransaction(rawtx)
     time.sleep(2) # make sure signing is done on node 2 (it's async)
     # Make the signing session for the IS lock timeout on node 3
     self.bump_mocktime(61)
     set_node_times(self.nodes, self.mocktime)
     time.sleep(2) # make sure Cleanup() is called
     reconnect_isolated_node(self.nodes[3], 0)
     self.wait_for_mnauth(self.nodes[3], 2)
     self.nodes[0].sendrawtransaction(rawtx)
     # Make sure nodes 1 and 2 received the TX
     self.wait_for_tx(txid, self.nodes[1])
     self.wait_for_tx(txid, self.nodes[2])
     # Make sure signing is done on nodes 1 and 2 (it's async)
     time.sleep(5)
     # node 3 fully reconnected but the signing session is already timed out on it, so no IS lock
     self.wait_for_instantlock(txid, self.nodes[0], False, 1)
     if do_cycle_llmqs:
         self.cycle_llmqs()
         self.wait_for_instantlock(txid, self.nodes[0], False, 5)
     # Make node 0 consider the TX as safe
     self.bump_mocktime(10 * 60 + 1)
     self.nodes[0].setmocktime(self.mocktime)
     block = self.nodes[0].generate(1)[0]
     self.wait_for_chainlocked_block_all_nodes(block)
示例#2
0
    def test_block_doublespend(self):
        sender = self.nodes[self.sender_idx]
        receiver = self.nodes[self.receiver_idx]
        isolated = self.nodes[self.isolated_idx]

        # feed the sender with some balance
        sender_addr = sender.getnewaddress()
        self.nodes[0].sendtoaddress(sender_addr, 1)
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        self.nodes[0].generate(2)
        self.sync_all()

        # create doublespending transaction, but don't relay it
        dblspnd_tx = self.create_raw_tx(sender, isolated, 0.5, 1, 100)
        # isolate one node from network
        isolate_node(isolated)
        # instantsend to receiver
        receiver_addr = receiver.getnewaddress()
        is_id = sender.sendtoaddress(receiver_addr, 0.9)
        # wait for the transaction to propagate
        connected_nodes = self.nodes.copy()
        del connected_nodes[self.isolated_idx]
        sync_mempools(connected_nodes)
        for node in connected_nodes:
            self.wait_for_instantlock(is_id, node)
        # send doublespend transaction to isolated node
        isolated.sendrawtransaction(dblspnd_tx['hex'])
        # generate block on isolated node with doublespend transaction
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        isolated.generate(1)
        wrong_block = isolated.getbestblockhash()
        # connect isolated block to network
        reconnect_isolated_node(isolated, 0)
        # check doublespend block is rejected by other nodes
        timeout = 10
        for i in range(0, self.num_nodes):
            if i == self.isolated_idx:
                continue
            res = self.nodes[i].waitforblock(wrong_block, timeout)
            assert (res['hash'] != wrong_block)
            # wait for long time only for first node
            timeout = 1
        # send coins back to the controller node without waiting for confirmations
        receiver.sendtoaddress(self.nodes[0].getnewaddress(), 0.9, "", "",
                               True)
        assert_equal(receiver.getwalletinfo()["balance"], 0)
        # mine more blocks
        # TODO: mine these blocks on an isolated node
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        self.nodes[0].generate(2)
        self.sync_all()
示例#3
0
    def test_mempool_doublespend(self):
        sender = self.nodes[self.sender_idx]
        receiver = self.nodes[self.receiver_idx]
        isolated = self.nodes[self.isolated_idx]

        # feed the sender with some balance
        sender_addr = sender.getnewaddress()
        self.nodes[0].sendtoaddress(sender_addr, 1)
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        self.nodes[0].generate(2)
        self.sync_all()

        # create doublespending transaction, but don't relay it
        dblspnd_tx = self.create_raw_tx(sender, isolated, 0.5, 1, 100)
        dblspnd_txid = bytes_to_hex_str(
            hash256(hex_str_to_bytes(dblspnd_tx['hex']))[::-1])
        # isolate one node from network
        isolate_node(isolated)
        # send doublespend transaction to isolated node
        isolated.sendrawtransaction(dblspnd_tx['hex'])
        # let isolated node rejoin the network
        # The previously isolated node should NOT relay the doublespending TX
        reconnect_isolated_node(isolated, 0)
        for node in self.nodes:
            if node is not isolated:
                assert_raises_rpc_error(
                    -5, "No such mempool or blockchain transaction",
                    node.getrawtransaction, dblspnd_txid)
        # instantsend to receiver. The previously isolated node should prune the doublespend TX and request the correct
        # TX from other nodes.
        receiver_addr = receiver.getnewaddress()
        is_id = sender.sendtoaddress(receiver_addr, 0.9)
        # wait for the transaction to propagate
        sync_mempools(self.nodes)
        for node in self.nodes:
            self.wait_for_instantlock(is_id, node)
        assert_raises_rpc_error(-5,
                                "No such mempool or blockchain transaction",
                                isolated.getrawtransaction, dblspnd_txid)
        # send coins back to the controller node without waiting for confirmations
        receiver.sendtoaddress(self.nodes[0].getnewaddress(), 0.9, "", "",
                               True)
        assert_equal(receiver.getwalletinfo()["balance"], 0)
        # mine more blocks
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        self.nodes[0].generate(2)
        self.sync_all()
示例#4
0
    def run_test(self):
        while self.nodes[0].getblockchaininfo()["bip9_softforks"]["dip0008"]["status"] != "active":
            self.nodes[0].generate(10)
        sync_blocks(self.nodes, timeout=60*5)

        self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0)
        self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 0)
        self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0)
        self.nodes[0].spork("SPORK_3_INSTANTSEND_BLOCK_FILTERING", 0)
        self.wait_for_sporks_same()

        self.mine_quorum()
        self.mine_quorum()

        # Make sure that all nodes are chainlocked at the same height before starting actual tests
        self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash(), timeout=30)

        self.log.info("trying normal IS lock")
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # 3 nodes should be enough to create an IS lock even if nodes 4 and 5 (which have no tx itself)
        # are the only "neighbours" in intra-quorum connections for one of them.
        self.wait_for_instantlock(txid, self.nodes[0])
        self.bump_mocktime(1)
        set_node_times(self.nodes, self.mocktime)
        block = self.nodes[0].generate(1)[0]
        self.wait_for_chainlocked_block_all_nodes(block)

        self.log.info("testing normal signing with partially known TX")
        isolate_node(self.nodes[3])
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # Make sure nodes 1 and 2 received the TX before we continue,
        # otherwise it might announce the TX to node 3 when reconnecting
        self.wait_for_tx(txid, self.nodes[1])
        self.wait_for_tx(txid, self.nodes[2])
        reconnect_isolated_node(self.nodes[3], 0)
        self.wait_for_mnauth(self.nodes[3], 2)
        # node 3 fully reconnected but the TX wasn't relayed to it, so there should be no IS lock
        self.wait_for_instantlock(txid, self.nodes[0], False, 5)
        # push the tx directly via rpc
        self.nodes[3].sendrawtransaction(self.nodes[0].getrawtransaction(txid))
        # node 3 should vote on a tx now since it became aware of it via sendrawtransaction
        # and this should be enough to complete an IS lock
        self.wait_for_instantlock(txid, self.nodes[0])

        self.log.info("testing retroactive signing with unknown TX")
        isolate_node(self.nodes[3])
        rawtx = self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})
        rawtx = self.nodes[0].fundrawtransaction(rawtx)['hex']
        rawtx = self.nodes[0].signrawtransaction(rawtx)['hex']
        txid = self.nodes[3].sendrawtransaction(rawtx)
        # Make node 3 consider the TX as safe
        self.bump_mocktime(10 * 60 + 1)
        set_node_times(self.nodes, self.mocktime)
        block = self.nodes[3].generatetoaddress(1, self.nodes[0].getnewaddress())[0]
        reconnect_isolated_node(self.nodes[3], 0)
        self.wait_for_chainlocked_block_all_nodes(block)
        self.nodes[0].setmocktime(self.mocktime)

        self.log.info("testing retroactive signing with partially known TX")
        isolate_node(self.nodes[3])
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # Make sure nodes 1 and 2 received the TX before we continue,
        # otherwise it might announce the TX to node 3 when reconnecting
        self.wait_for_tx(txid, self.nodes[1])
        self.wait_for_tx(txid, self.nodes[2])
        reconnect_isolated_node(self.nodes[3], 0)
        self.wait_for_mnauth(self.nodes[3], 2)
        # node 3 fully reconnected but the TX wasn't relayed to it, so there should be no IS lock
        self.wait_for_instantlock(txid, self.nodes[0], False, 5)
        # Make node0 consider the TX as safe
        self.bump_mocktime(10 * 60 + 1)
        set_node_times(self.nodes, self.mocktime)
        block = self.nodes[0].generate(1)[0]
        self.wait_for_chainlocked_block_all_nodes(block)

        self.log.info("testing retroactive signing with partially known TX and all nodes session timeout")
        self.test_all_nodes_session_timeout(False)
        self.log.info("repeating test, but with cycled LLMQs")
        self.test_all_nodes_session_timeout(True)

        self.log.info("testing retroactive signing with partially known TX and single node session timeout")
        self.test_single_node_session_timeout(False)
        self.log.info("repeating test, but with cycled LLMQs")
        self.test_single_node_session_timeout(True)
    def run_test(self):
        self.activate_dip8()

        self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0)
        # Turn mempool IS signing off
        self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 1)
        self.wait_for_sporks_same()

        self.mine_quorum()
        self.mine_quorum()

        # Make sure that all nodes are chainlocked at the same height before starting actual tests
        self.wait_for_chainlocked_block_all_nodes(
            self.nodes[0].getbestblockhash(), timeout=30)

        self.log.info(
            "trying normal IS lock w/ signing spork off. Shouldn't be islocked before block is created."
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # 3 nodes should be enough to create an IS lock even if nodes 4 and 5 (which have no tx itself)
        # are the only "neighbours" in intra-quorum connections for one of them.
        self.wait_for_instantlock(txid, self.nodes[0], False, 5)
        # Have to disable ChainLocks to avoid signing a block with a "safe" tx too early
        self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 4000000000)
        self.wait_for_sporks_same()
        # We have to wait in order to include tx in block
        self.bump_mocktime(10 * 60 + 1)
        block = self.nodes[0].generate(1)[0]
        self.wait_for_instantlock(txid, self.nodes[0])
        self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 0)
        self.wait_for_sporks_same()
        self.wait_for_chainlocked_block_all_nodes(block)

        self.log.info("Enable mempool IS signing")
        self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0)
        self.wait_for_sporks_same()

        self.log.info("trying normal IS lock")
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # 3 nodes should be enough to create an IS lock even if nodes 4 and 5 (which have no tx itself)
        # are the only "neighbours" in intra-quorum connections for one of them.
        self.wait_for_instantlock(txid, self.nodes[0])
        self.bump_mocktime(1)
        block = self.nodes[0].generate(1)[0]
        self.wait_for_chainlocked_block_all_nodes(block)

        self.log.info("testing normal signing with partially known TX")
        isolate_node(self.nodes[3])
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # Make sure nodes 1 and 2 received the TX before we continue,
        # otherwise it might announce the TX to node 3 when reconnecting
        self.wait_for_tx(txid, self.nodes[1])
        self.wait_for_tx(txid, self.nodes[2])
        reconnect_isolated_node(self.nodes[3], 0)
        # Make sure nodes actually try re-connecting quorum connections
        self.bump_mocktime(30)
        self.wait_for_mnauth(self.nodes[3], 2)
        # node 3 fully reconnected but the TX wasn't relayed to it, so there should be no IS lock
        self.wait_for_instantlock(txid, self.nodes[0], False, 5)
        # push the tx directly via rpc
        self.nodes[3].sendrawtransaction(self.nodes[0].getrawtransaction(txid))
        # node 3 should vote on a tx now since it became aware of it via sendrawtransaction
        # and this should be enough to complete an IS lock
        self.wait_for_instantlock(txid, self.nodes[0])

        self.log.info("testing retroactive signing with unknown TX")
        isolate_node(self.nodes[3])
        rawtx = self.nodes[0].createrawtransaction(
            [], {self.nodes[0].getnewaddress(): 1})
        rawtx = self.nodes[0].fundrawtransaction(rawtx)['hex']
        rawtx = self.nodes[0].signrawtransactionwithwallet(rawtx)['hex']
        txid = self.nodes[3].sendrawtransaction(rawtx)
        # Make node 3 consider the TX as safe
        self.bump_mocktime(10 * 60 + 1)
        block = self.nodes[3].generatetoaddress(
            1, self.nodes[0].getnewaddress())[0]
        reconnect_isolated_node(self.nodes[3], 0)
        self.wait_for_chainlocked_block_all_nodes(block)
        self.nodes[0].setmocktime(self.mocktime)

        self.log.info("testing retroactive signing with partially known TX")
        isolate_node(self.nodes[3])
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        # Make sure nodes 1 and 2 received the TX before we continue,
        # otherwise it might announce the TX to node 3 when reconnecting
        self.wait_for_tx(txid, self.nodes[1])
        self.wait_for_tx(txid, self.nodes[2])
        reconnect_isolated_node(self.nodes[3], 0)
        # Make sure nodes actually try re-connecting quorum connections
        self.bump_mocktime(30)
        self.wait_for_mnauth(self.nodes[3], 2)
        # node 3 fully reconnected but the TX wasn't relayed to it, so there should be no IS lock
        self.wait_for_instantlock(txid, self.nodes[0], False, 5)
        # Make node0 consider the TX as safe
        self.bump_mocktime(10 * 60 + 1)
        block = self.nodes[0].generate(1)[0]
        assert (txid in self.nodes[0].getblock(block, 1)['tx'])
        self.wait_for_chainlocked_block_all_nodes(block)

        self.log.info(
            "testing retroactive signing with partially known TX and all nodes session timeout"
        )
        self.test_all_nodes_session_timeout(False)
        self.log.info("repeating test, but with cycled LLMQs")
        self.test_all_nodes_session_timeout(True)

        self.log.info(
            "testing retroactive signing with partially known TX and single node session timeout"
        )
        self.test_single_node_session_timeout(False)
        self.log.info("repeating test, but with cycled LLMQs")
        self.test_single_node_session_timeout(True)