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