Beispiel #1
0
 def setColdStakingEnforcement(self, fEnable=True):
     new_val = 1563253447 if fEnable else 4070908800
     # update spork 17 and mine 1 more block
     mess = "Enabling" if fEnable else "Disabling"
     mess += " cold staking with SPORK 17..."
     self.log.info(mess)
     res = self.nodes[0].spork("SPORK_17_COLDSTAKING_ENFORCEMENT", new_val)
     self.log.info(res)
     assert (res == "success")
     time.sleep(1)
     sync_chain(self.nodes)
Beispiel #2
0
    def run_test(self):
        self.log.info(
            "Ensure submitblock can in principle reorg to a competing chain")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 1)
        (hashY, hashZ) = self.nodes[1].generate(2)
        assert_equal(self.nodes[1].getblockcount(), 2)
        node_sync_via_rpc(self.nodes[0:3])
        assert_equal(self.nodes[0].getbestblockhash(), hashZ)

        self.log.info("Mine blocks A-B-C on Node 0")
        (hashA, hashB, hashC) = self.nodes[0].generate(3)
        assert_equal(self.nodes[0].getblockcount(), 5)
        self.log.info("Mine competing blocks E-F-G on Node 1")
        (hashE, hashF, hashG) = self.nodes[1].generate(3)
        assert_equal(self.nodes[1].getblockcount(), 5)
        assert (hashC != hashG)
        self.log.info("Connect nodes and check no reorg occurs")
        # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
        node_sync_via_rpc(self.nodes[0:2])
        connect_nodes_bi(self.nodes, 0, 1)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block C again")
        self.nodes[0].preciousblock(hashC)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block C")
        self.nodes[1].preciousblock(hashC)
        sync_chain(self.nodes[0:2]
                   )  # wait because node 1 may not have downloaded hashC
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block G again")
        self.nodes[1].preciousblock(hashG)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G again")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node1 prefer block C again")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info(
            "Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 6)
        sync_blocks(self.nodes[0:2])
        hashH = self.nodes[0].getbestblockhash()
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Node1 should not be able to prefer block C anymore")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Mine competing blocks I-J-K-L on Node 2")
        self.nodes[2].generate(4)
        assert_equal(self.nodes[2].getblockcount(), 6)
        hashL = self.nodes[2].getbestblockhash()
        self.log.info("Connect nodes and check no reorg occurs")
        node_sync_via_rpc(self.nodes[1:3])
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        assert_equal(self.nodes[0].getbestblockhash(), hashH)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashL)
        self.log.info("Make Node1 prefer block L")
        self.nodes[1].preciousblock(hashL)
        assert_equal(self.nodes[1].getbestblockhash(), hashL)
        self.log.info("Make Node2 prefer block H")
        self.nodes[2].preciousblock(hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashH)
Beispiel #3
0
    def run_test(self):
        self.description = "Performs tests on the Cold Staking P2CS implementation"
        self.init_test()
        LAST_POW_BLOCK = 250
        NUM_OF_INPUTS = 20
        INPUT_VALUE = 50
        INITAL_MINED_BLOCKS = LAST_POW_BLOCK + 1

        # nodes[0] - coin-owner
        # nodes[1] - cold-staker

        # 1) nodes[0] mines 20 blocks. nodes[2] mines 231 blocks.
        # -----------------------------------------------------------
        # Check that SPORK 17 is disabled
        assert (not self.isColdStakingEnforced())
        print("*** 1 ***")
        self.log.info("Mining %d blocks..." % INITAL_MINED_BLOCKS)
        self.generateBlock(20, 0)
        sync_chain(self.nodes)
        self.log.info("20 Blocks mined.")
        self.generateBlock(INITAL_MINED_BLOCKS - 20)
        sync_chain(self.nodes)
        self.log.info("251 Blocks mined.")

        # 2) nodes[0] generates a owner address
        #    nodes[1] generates a cold-staking address.
        # ---------------------------------------------
        print("*** 2 ***")
        owner_address = self.nodes[0].getnewaddress()
        self.log.info("Owner Address: %s" % owner_address)
        staker_address = self.nodes[1].getnewstakingaddress()
        self.log.info("Staking Address: %s" % staker_address)

        # 3) Check enforcement.
        # ---------------------
        print("*** 3 ***")
        self.log.info(
            "Creating a stake-delegation tx before cold staking enforcement..."
        )
        assert_raises_rpc_error(-4, "The transaction was rejected!",
                                self.nodes[0].delegatestake, staker_address,
                                INPUT_VALUE, owner_address, False, False, True)
        self.log.info("Good. Cold Staking NOT ACTIVE yet.")

        # Enable SPORK
        self.setColdStakingEnforcement()
        # double check
        assert (self.isColdStakingEnforced())

        # 4) nodes[0] delegates a number of inputs for nodes[1] to stake em.
        # ------------------------------------------------------------------
        print("*** 4 ***")
        self.log.info("First check warning when using external addresses...")
        assert_raises_rpc_error(
            -5,
            "Only the owner of the key to owneraddress will be allowed to spend these coins",
            self.nodes[0].delegatestake, staker_address, INPUT_VALUE,
            "yCgCXC8N5VThhfiaVuKaNLkNnrWduzVnoT")
        self.log.info("Good. Warning triggered.")

        self.log.info(
            "Now force the use of external address creating (but not sending) the delegation..."
        )
        res = self.nodes[0].rawdelegatestake(
            staker_address, INPUT_VALUE, "yCgCXC8N5VThhfiaVuKaNLkNnrWduzVnoT",
            True)
        assert (res is not None and res != "")
        self.log.info("Good. Warning NOT triggered.")

        self.log.info("Now delegate with internal owner address..")
        self.log.info("Try first with a value (0.99) below the threshold")
        assert_raises_rpc_error(-8, "Invalid amount",
                                self.nodes[0].delegatestake, staker_address,
                                0.99, owner_address)
        self.log.info("Nice. it was not possible.")
        self.log.info(
            "Then try (creating but not sending) with the threshold value (1.00)"
        )
        res = self.nodes[0].rawdelegatestake(staker_address, 1.00,
                                             owner_address)
        assert (res is not None and res != "")
        self.log.info("Good. Warning NOT triggered.")

        self.log.info("Now creating %d real stake-delegation txes..." %
                      NUM_OF_INPUTS)
        for i in range(NUM_OF_INPUTS):
            res = self.nodes[0].delegatestake(staker_address, INPUT_VALUE,
                                              owner_address)
            assert (res != None and res["txid"] != None and res["txid"] != "")
            assert_equal(res["owner_address"], owner_address)
            assert_equal(res["staker_address"], staker_address)
        self.generateBlock()
        sync_chain(self.nodes)
        self.log.info("%d Txes created." % NUM_OF_INPUTS)
        # check balances:
        self.expected_balance = NUM_OF_INPUTS * INPUT_VALUE
        self.expected_immature_balance = 0
        self.checkBalances()

        # 5) check that the owner (nodes[0]) can spend the coins.
        # -------------------------------------------------------
        print("*** 5 ***")
        self.log.info("Spending back one of the delegated UTXOs...")
        delegated_utxos = getDelegatedUtxos(self.nodes[0].listunspent())
        assert_equal(20, len(delegated_utxos))
        assert_equal(len(delegated_utxos), len(self.nodes[0].listcoldutxos()))
        u = delegated_utxos[0]
        txhash = self.spendUTXOwithNode(u, 0)
        assert (txhash != None)
        self.log.info("Good. Owner was able to spend - tx: %s" % str(txhash))

        self.generateBlock()
        sync_chain(self.nodes)
        # check balances after spend.
        self.expected_balance -= float(u["amount"])
        self.checkBalances()
        self.log.info("Balances check out after spend")
        assert_equal(19, len(self.nodes[0].listcoldutxos()))

        # 6) check that the staker CANNOT use the coins to stake yet.
        # He needs to whitelist the owner first.
        # -----------------------------------------------------------
        print("*** 6 ***")
        self.log.info(
            "Trying to generate a cold-stake block before whitelisting the owner..."
        )
        assert_equal(self.nodes[1].getstakingstatus()["mintablecoins"], False)
        self.log.info(
            "Nice. Cold staker was NOT able to create the block yet.")

        self.log.info("Whitelisting the owner...")
        ret = self.nodes[1].delegatoradd(owner_address)
        assert (ret)
        self.log.info("Delegator address %s whitelisted" % owner_address)

        # 7) check that the staker CANNOT spend the coins.
        # ------------------------------------------------
        print("*** 7 ***")
        self.log.info(
            "Trying to spend one of the delegated UTXOs with the cold-staking key..."
        )
        delegated_utxos = getDelegatedUtxos(self.nodes[0].listunspent())
        assert_greater_than(len(delegated_utxos), 0)
        u = delegated_utxos[0]
        assert_raises_rpc_error(
            -26,
            "mandatory-script-verify-flag-failed (Script failed an OP_CHECKCOLDSTAKEVERIFY operation",
            self.spendUTXOwithNode, u, 1)
        self.log.info(
            "Good. Cold staker was NOT able to spend (failed OP_CHECKCOLDSTAKEVERIFY)"
        )
        self.generateBlock()
        sync_chain(self.nodes)

        # 8) check that the staker can use the coins to stake a block with internal miner.
        # --------------------------------------------------------------------------------
        print("*** 8 ***")
        assert_equal(self.nodes[1].getstakingstatus()["mintablecoins"], True)
        self.log.info("Generating one valid cold-stake block...")
        self.generateBlock(1, 1)
        self.log.info("New block created by cold-staking. Trying to submit...")
        newblockhash = self.nodes[1].getbestblockhash()
        self.log.info("Block %s submitted" % newblockhash)

        # Verify that nodes[0] accepts it
        sync_chain(self.nodes)
        assert_equal(self.nodes[0].getblockcount(),
                     self.nodes[1].getblockcount())
        assert_equal(newblockhash, self.nodes[0].getbestblockhash())
        self.log.info("Great. Cold-staked block was accepted!")

        # check balances after staked block.
        self.expected_balance -= 50
        self.expected_immature_balance += 300
        self.checkBalances()
        self.log.info("Balances check out after staked block")

        # 9) check that the staker can use the coins to stake a block with a rawtransaction.
        # ----------------------------------------------------------------------------------
        print("*** 9 ***")
        self.log.info("Generating another valid cold-stake block...")
        stakeable_coins = getDelegatedUtxos(self.nodes[0].listunspent())
        block_n = self.nodes[1].getblockcount()
        block_hash = self.nodes[1].getblockhash(block_n)
        prevouts = self.get_prevouts(stakeable_coins, 1)
        assert_greater_than(len(prevouts), 0)
        # Create the block
        new_block = self.create_block(block_hash, prevouts, block_n + 1, 1,
                                      staker_address)
        self.log.info(
            "New block created (rawtx) by cold-staking. Trying to submit...")
        # Try to submit the block
        ret = self.nodes[1].submitblock(bytes_to_hex_str(
            new_block.serialize()))
        self.log.info("Block %s submitted." % new_block.hash)
        assert (ret is None)

        # Verify that nodes[0] accepts it
        sync_chain(self.nodes)
        assert_equal(self.nodes[0].getblockcount(),
                     self.nodes[1].getblockcount())
        assert_equal(new_block.hash, self.nodes[0].getbestblockhash())
        self.log.info("Great. Cold-staked block was accepted!")

        # check balances after staked block.
        self.expected_balance -= 50
        self.expected_immature_balance += 300
        self.checkBalances()
        self.log.info("Balances check out after staked block")

        # 10) check that the staker cannot stake a block changing the coinstake scriptPubkey.
        # ----------------------------------------------------------------------------------
        print("*** 10 ***")
        self.log.info(
            "Generating one invalid cold-stake block (changing first coinstake output)..."
        )
        stakeable_coins = getDelegatedUtxos(self.nodes[0].listunspent())
        block_n = self.nodes[1].getblockcount()
        block_hash = self.nodes[1].getblockhash(block_n)
        prevouts = self.get_prevouts(stakeable_coins, 1)
        assert_greater_than(len(prevouts), 0)
        # Create the block
        new_block = self.create_block(block_hash,
                                      prevouts,
                                      block_n + 1,
                                      1,
                                      staker_address,
                                      fInvalid=1)
        self.log.info(
            "New block created (rawtx) by cold-staking. Trying to submit...")
        # Try to submit the block
        ret = self.nodes[1].submitblock(bytes_to_hex_str(
            new_block.serialize()))
        self.log.info("Block %s submitted." % new_block.hash)
        assert ("rejected" in ret)

        # Verify that nodes[0] rejects it
        sync_chain(self.nodes)
        assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock,
                                new_block.hash)
        self.log.info("Great. Malicious cold-staked block was NOT accepted!")
        self.checkBalances()
        self.log.info("Balances check out after (non) staked block")

        # 11) neither adding different outputs to the coinstake.
        # ------------------------------------------------------
        print("*** 11 ***")
        self.log.info(
            "Generating another invalid cold-stake block (adding coinstake output)..."
        )
        stakeable_coins = getDelegatedUtxos(self.nodes[0].listunspent())
        block_n = self.nodes[1].getblockcount()
        block_hash = self.nodes[1].getblockhash(block_n)
        prevouts = self.get_prevouts(stakeable_coins, 1)
        assert_greater_than(len(prevouts), 0)
        # Create the block
        new_block = self.create_block(block_hash,
                                      prevouts,
                                      block_n + 1,
                                      1,
                                      staker_address,
                                      fInvalid=2)
        self.log.info(
            "New block created (rawtx) by cold-staking. Trying to submit...")
        # Try to submit the block
        ret = self.nodes[1].submitblock(bytes_to_hex_str(
            new_block.serialize()))
        self.log.info("Block %s submitted." % new_block.hash)
        assert_equal(ret, "bad-p2cs-outs")

        # Verify that nodes[0] rejects it
        sync_chain(self.nodes)
        assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock,
                                new_block.hash)
        self.log.info("Great. Malicious cold-staked block was NOT accepted!")
        self.checkBalances()
        self.log.info("Balances check out after (non) staked block")

        # 12) Now node[0] gets mad and spends all the delegated coins, voiding the P2CS contracts.
        # ----------------------------------------------------------------------------------------
        self.log.info("Let's void the contracts.")
        self.generateBlock()
        sync_chain(self.nodes)
        print("*** 12 ***")
        self.log.info(
            "Cancel the stake delegation spending the cold stakes...")
        delegated_utxos = getDelegatedUtxos(self.nodes[0].listunspent())
        # remove one utxo to spend later
        final_spend = delegated_utxos.pop()
        txhash = self.spendUTXOsWithNode(delegated_utxos, 0)
        assert (txhash != None)
        self.log.info(
            "Good. Owner was able to void the stake delegations - tx: %s" %
            str(txhash))
        self.generateBlock()
        sync_chain(self.nodes)

        # deactivate SPORK 17 and check that the owner can still spend the last utxo
        self.setColdStakingEnforcement(False)
        assert (not self.isColdStakingEnforced())
        txhash = self.spendUTXOsWithNode([final_spend], 0)
        assert (txhash != None)
        self.log.info(
            "Good. Owner was able to void the last stake delegation (with SPORK 17 disabled) - tx: %s"
            % str(txhash))
        self.generateBlock()
        sync_chain(self.nodes)

        # check balances after big spend.
        self.expected_balance = 0
        self.checkBalances()
        self.log.info(
            "Balances check out after the delegations have been voided.")
        # re-activate SPORK17
        self.setColdStakingEnforcement()
        assert (self.isColdStakingEnforced())

        # 13) check that coinstaker is empty and can no longer stake.
        # -----------------------------------------------------------
        print("*** 13 ***")
        self.log.info("Trying to generate one cold-stake block again...")
        assert_equal(self.nodes[1].getstakingstatus()["mintablecoins"], False)
        self.log.info(
            "Cigar. Cold staker was NOT able to create any more blocks.")

        # 14) check balances when mature.
        # -----------------------------------------------------------
        print("*** 14 ***")
        self.log.info("Staking 100 blocks to mature last 2...")
        self.generateBlock(100)
        self.expected_balance = self.expected_immature_balance
        self.expected_immature_balance = 0
        self.checkBalances()
        self.log.info("Balances check out after maturation.\n")
    def run_test(self):
        self.log.info(
            "Ensure submitblock can in principle reorg to a competing chain")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 1)
        (hashY, hashZ) = self.nodes[1].generate(2)
        assert_equal(self.nodes[1].getblockcount(), 2)
        node_sync_via_rpc(self.nodes[0:3])
        assert_equal(self.nodes[0].getbestblockhash(), hashZ)

        self.log.info("Mine blocks A-B-C on Node 0")
        (hashA, hashB, hashC) = self.nodes[0].generate(3)
        assert_equal(self.nodes[0].getblockcount(), 5)
        self.log.info("Mine competing blocks E-F-G on Node 1")
        (hashE, hashF, hashG) = self.nodes[1].generate(3)
        assert_equal(self.nodes[1].getblockcount(), 5)
        assert(hashC != hashG)
        self.log.info("Connect nodes and check no reorg occurs")
        # Submit competing blocks via RPC so any reorg should occur before we
        # proceed (no way to wait on inaction for p2p sync)
        node_sync_via_rpc(self.nodes[0:2])
        connect_nodes_bi(self.nodes, 0, 1)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block C again")
        self.nodes[0].preciousblock(hashC)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block C")
        self.nodes[1].preciousblock(hashC)
        sync_chain(self.nodes[0:2])
                   # wait because node 1 may not have downloaded hashC
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block G again")
        self.nodes[1].preciousblock(hashG)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G again")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node1 prefer block C again")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info(
            "Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 6)
        sync_blocks(self.nodes[0:2])
        hashH = self.nodes[0].getbestblockhash()
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Node1 should not be able to prefer block C anymore")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Mine competing blocks I-J-K-L on Node 2")
        self.nodes[2].generate(4)
        assert_equal(self.nodes[2].getblockcount(), 6)
        hashL = self.nodes[2].getbestblockhash()
        self.log.info("Connect nodes and check no reorg occurs")
        node_sync_via_rpc(self.nodes[1:3])
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        assert_equal(self.nodes[0].getbestblockhash(), hashH)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashL)
        self.log.info("Make Node1 prefer block L")
        self.nodes[1].preciousblock(hashL)
        assert_equal(self.nodes[1].getbestblockhash(), hashL)
        self.log.info("Make Node2 prefer block H")
        self.nodes[2].preciousblock(hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashH)
Beispiel #5
0
    def run_test(self):
        self.setup_stake_coins(self.nodes[0], self.nodes[1], self.nodes[2])

        for i in range(self.num_nodes):
            self.nodes[i].add_p2p_connection(P2PInterface())
        network_thread_start()

        wait_until(lambda: all(self.nodes[i].p2p.got_verack()
                               for i in range(self.num_nodes)),
                   timeout=10)

        self.log.info(
            "Ensure submitblock can in principle reorg to a competing chain")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 1)
        hashZ = self.nodes[1].generate(2)[-1]
        assert_equal(self.nodes[1].getblockcount(), 2)
        node_sync_via_rpc(self.nodes[0:3])
        assert_equal(self.nodes[0].getbestblockhash(), hashZ)

        self.log.info("Mine blocks A-B-C on Node 0")
        hashC = self.nodes[0].generate(3)[-1]
        assert_equal(self.nodes[0].getblockcount(), 5)
        self.log.info("Mine competing blocks E-F-G on Node 1")
        hashG = self.nodes[1].generate(3)[-1]
        assert_equal(self.nodes[1].getblockcount(), 5)
        assert hashC != hashG
        self.log.info("Connect nodes and check no reorg occurs")
        # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
        node_sync_via_rpc(self.nodes[0:2])
        connect_nodes_bi(self.nodes, 0, 1)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block C again")
        self.nodes[0].preciousblock(hashC)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block C")
        self.nodes[1].preciousblock(hashC)
        sync_chain(self.nodes[0:2]
                   )  # wait because node 1 may not have downloaded hashC
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block G again")
        self.nodes[1].preciousblock(hashG)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G again")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node1 prefer block C again")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info(
            "Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
        self.nodes[0].generate(1)
        assert_equal(self.nodes[0].getblockcount(), 6)
        sync_blocks(self.nodes[0:2])
        hashH = self.nodes[0].getbestblockhash()
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Node1 should not be able to prefer block C anymore")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Mine competing blocks I-J-K-L on Node 2")
        self.nodes[2].generate(4)
        assert_equal(self.nodes[2].getblockcount(), 6)
        hashL = self.nodes[2].getbestblockhash()
        self.log.info("Connect nodes and check no reorg occurs")
        node_sync_via_rpc(self.nodes[1:3])
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        assert_equal(self.nodes[0].getbestblockhash(), hashH)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashL)
        self.log.info("Make Node1 prefer block L")
        self.nodes[1].preciousblock(hashL)
        assert_equal(self.nodes[1].getbestblockhash(), hashL)
        self.log.info("Make Node2 prefer block H")
        self.nodes[2].preciousblock(hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashH)
Beispiel #6
0
    def run_test(self):
        self.log.info(
            "Ensure submitblock can in principle reorg to a competing chain")
        gen_address = lambda i: self.nodes[i].get_deterministic_priv_key(
        ).address  # A non-wallet address to mine to
        self.nodes[0].generatetoaddress(1, gen_address(0))
        assert_equal(self.nodes[0].getblockcount(), 1)
        hashZ = self.nodes[1].generatetoaddress(2, gen_address(1))[-1]
        assert_equal(self.nodes[1].getblockcount(), 2)
        node_sync_via_rpc(self.nodes[0:3])
        assert_equal(self.nodes[0].getbestblockhash(), hashZ)

        self.log.info("Mine blocks A-B-C on Node 0")
        hashC = self.nodes[0].generatetoaddress(3, gen_address(0))[-1]
        assert_equal(self.nodes[0].getblockcount(), 5)
        self.log.info("Mine competing blocks E-F-G on Node 1")
        hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1]
        assert_equal(self.nodes[1].getblockcount(), 5)
        assert (hashC != hashG)
        self.log.info("Connect nodes and check no reorg occurs")
        # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
        node_sync_via_rpc(self.nodes[0:2])
        connect_nodes_bi(self.nodes, 0, 1)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block C again")
        self.nodes[0].preciousblock(hashC)
        assert_equal(self.nodes[0].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block C")
        self.nodes[1].preciousblock(hashC)
        sync_chain(self.nodes[0:2]
                   )  # wait because node 1 may not have downloaded hashC
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info("Make Node1 prefer block G again")
        self.nodes[1].preciousblock(hashG)
        assert_equal(self.nodes[1].getbestblockhash(), hashG)
        self.log.info("Make Node0 prefer block G again")
        self.nodes[0].preciousblock(hashG)
        assert_equal(self.nodes[0].getbestblockhash(), hashG)
        self.log.info("Make Node1 prefer block C again")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashC)
        self.log.info(
            "Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
        self.nodes[0].generatetoaddress(1, gen_address(0))
        assert_equal(self.nodes[0].getblockcount(), 6)
        sync_blocks(self.nodes[0:2])
        hashH = self.nodes[0].getbestblockhash()
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Node1 should not be able to prefer block C anymore")
        self.nodes[1].preciousblock(hashC)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        self.log.info("Mine competing blocks I-J-K-L on Node 2")
        self.nodes[2].generatetoaddress(4, gen_address(2))
        assert_equal(self.nodes[2].getblockcount(), 6)
        hashL = self.nodes[2].getbestblockhash()
        self.log.info("Connect nodes and check no reorg occurs")
        node_sync_via_rpc(self.nodes[1:3])
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        assert_equal(self.nodes[0].getbestblockhash(), hashH)
        assert_equal(self.nodes[1].getbestblockhash(), hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashL)
        self.log.info("Make Node1 prefer block L")
        self.nodes[1].preciousblock(hashL)
        assert_equal(self.nodes[1].getbestblockhash(), hashL)
        self.log.info("Make Node2 prefer block H")
        self.nodes[2].preciousblock(hashH)
        assert_equal(self.nodes[2].getbestblockhash(), hashH)
    def run_test(self):
        p0, p1, p2, v0 = self.nodes

        self.setup_stake_coins(p0, p1, p2, v0)

        # Leave IBD
        self.generate_sync(p0)

        self.log.info("Setup deposit")
        setup_deposit(self, p0, [v0])
        sync_blocks([p0, p1, p2, v0])

        self.log.info("Setup test prerequisites")
        # get to up to block 49, just one before the new checkpoint
        for _ in range(18):
            generate_block(p0)

        assert_equal(p0.getblockcount(), 49)
        sync_blocks([p0, p1, p2, v0])

        assert_finalizationstate(p0, {'currentEpoch': 5,
                                      'lastJustifiedEpoch': 4,
                                      'lastFinalizedEpoch': 3})

        # disconnect p0
        # v0: p1, p2
        # p0:
        # p1: v0
        # p2: v0
        disconnect_nodes(p0, v0.index)
        disconnect_nodes(p0, p1.index)

        # disconnect p2
        # v0: p1
        # p0:
        # p1: v0
        # p2:
        disconnect_nodes(p2, v0.index)

        # disconnect p1
        # v0:
        # p0:
        # p1:
        # p2:
        disconnect_nodes(p1, v0.index)

        # generate long chain in p0 but don't justify it
        #  F     J
        # 30 .. 40 .. 89    -- p0
        for _ in range(40):
            generate_block(p0)

        assert_equal(p0.getblockcount(), 89)
        assert_finalizationstate(p0, {'currentEpoch': 9,
                                      'lastJustifiedEpoch': 4,
                                      'lastFinalizedEpoch': 3})

        # generate short chain in p1 and justify it
        # on the 6th and 7th epochs sync with validator
        #  F     J
        # 30 .. 40 .. 49 .. .. .. .. .. .. 89    -- p0
        #               \
        #                50 .. 60 .. 69          -- p1
        #                 F     J
        # get to the 6th epoch
        p1.generatetoaddress(2, p1.getnewaddress('', 'bech32'))
        self.wait_for_vote_and_disconnect(finalizer=v0, node=p1)
        # get to the 7th epoch
        p1.generatetoaddress(10, p1.getnewaddress('', 'bech32'))
        self.wait_for_vote_and_disconnect(finalizer=v0, node=p1)
        # generate the rest of the blocks
        p1.generatetoaddress(8, p1.getnewaddress('', 'bech32'))
        connect_nodes(p1, v0.index)
        sync_blocks([p1, v0])

        assert_equal(p1.getblockcount(), 69)
        assert_finalizationstate(p1, {'currentEpoch': 7,
                                      'lastJustifiedEpoch': 6,
                                      'lastFinalizedEpoch': 5})

        # connect p2 with p0 and p1; p2 must switch to the longest justified p1
        # v0: p1
        # p0: p2
        # p1: v0, p2
        # p2: p0, p1
        self.log.info("Test fresh node sync")
        connect_nodes(p2, p0.index)
        connect_nodes(p2, p1.index)

        sync_chain([p1, p2])
        assert_equal(p1.getblockcount(), 69)
        assert_equal(p2.getblockcount(), 69)

        assert_finalizationstate(p1, {'currentEpoch': 7,
                                      'lastJustifiedEpoch': 6,
                                      'lastFinalizedEpoch': 5})
        assert_finalizationstate(p2, {'currentEpoch': 7,
                                      'lastJustifiedEpoch': 6,
                                      'lastFinalizedEpoch': 5})

        # connect p0 with p1, p0 must disconnect its longest but not justified fork and choose p1
        # v0: p1
        # p0: p1, p2
        # p1: v0, p0, p2
        # p2: p0, p1
        self.log.info("Test longest node reverts to justified")
        connect_nodes(p0, p1.index)
        sync_chain([p0, p1])

        # check if p0 accepted shortest in terms of blocks but longest justified chain
        assert_equal(p0.getblockcount(), 69)
        assert_equal(p1.getblockcount(), 69)
        assert_equal(v0.getblockcount(), 69)

        # generate more blocks to make sure they're processed
        self.log.info("Test all nodes continue to work as usual")
        for _ in range(30):
            generate_block(p0)
        sync_chain([p0, p1, p2, v0])
        assert_equal(p0.getblockcount(), 99)
        for _ in range(30):
            generate_block(p1)
        sync_chain([p0, p1, p2, v0])
        assert_equal(p1.getblockcount(), 129)
        for _ in range(30):
            generate_block(p2)
        sync_chain([p0, p1, p2, v0])
        assert_equal(p2.getblockcount(), 159)

        # disconnect all nodes
        # v0:
        # p0:
        # p1:
        # p2:
        self.log.info("Test nodes sync after reconnection")
        disconnect_nodes(v0, p1.index)
        disconnect_nodes(p0, p1.index)
        disconnect_nodes(p0, p2.index)
        disconnect_nodes(p1, p2.index)
        for _ in range(10):
            generate_block(p0)
        for _ in range(20):
            generate_block(p1)
        for _ in range(30):
            generate_block(p2)
        assert_equal(p0.getblockcount(), 169)
        assert_equal(p1.getblockcount(), 179)
        assert_equal(p2.getblockcount(), 189)

        # connect validator back to p1
        # v0: p1
        # p0: p1
        # p1: v0, p0, p2
        # p2: p1
        connect_nodes(p1, v0.index)
        sync_blocks([p1, v0])
        connect_nodes(p1, p0.index)
        connect_nodes(p1, p2.index)
        sync_chain([p0, p1, p2, v0])
Beispiel #8
0
    def test_justification_over_chain_work(self):
        """
        Test that justification has priority over chain work
        """

        def seen_block(node, blockhash):
            try:
                node.getblock(blockhash)
                return True
            except JSONRPCException:
                return False

        def connect_sync_disconnect(node1, node2, blockhash):
            connect_nodes(node1, node2.index)
            wait_until(lambda: seen_block(node1, blockhash), timeout=10)
            wait_until(lambda: node1.getblockcount() == node2.getblockcount(), timeout=5)
            assert_equal(node1.getblockhash(node1.getblockcount()), blockhash)
            disconnect_nodes(node1, node2.index)

        node0 = self.nodes[0]
        node1 = self.nodes[1]
        node2 = self.nodes[2]
        validator = self.nodes[3]

        self.setup_stake_coins(node0, node1, node2, validator)

        connect_nodes(node0, node1.index)
        connect_nodes(node0, node2.index)
        connect_nodes(node0, validator.index)

        # leave IBD
        node0.generatetoaddress(1, node0.getnewaddress('', 'bech32'))
        sync_blocks([node0, node1, node2, validator], timeout=10)

        payto = validator.getnewaddress('', 'legacy')
        txid = validator.deposit(payto, 1500)
        wait_until(lambda: self.have_tx_in_mempool([node0, node1, node2], txid), timeout=10)

        disconnect_nodes(node0, node1.index)
        disconnect_nodes(node0, node2.index)
        disconnect_nodes(node0, validator.index)
        assert_equal(len(node0.getpeerinfo()), 0)

        # F    F    F    F    J
        # e0 - e1 - e2 - e3 - e4 - e5 - e6[26]
        node0.generatetoaddress(25, node0.getnewaddress('', 'bech32'))
        assert_equal(node0.getblockcount(), 26)
        assert_finalizationstate(node0, {'currentDynasty': 3,
                                         'currentEpoch': 6,
                                         'lastJustifiedEpoch': 4,
                                         'lastFinalizedEpoch': 3,
                                         'validators': 1})

        connect_nodes(node0, node1.index)
        connect_nodes(node0, node2.index)
        sync_blocks([node0, node1, node2])
        disconnect_nodes(node0, node1.index)
        disconnect_nodes(node0, node2.index)

        # generate fork with no commits. node0 must switch to it
        # 26 node1
        #   \
        #    - b27 node0, node2
        b27 = node2.generatetoaddress(1, node2.getnewaddress('', 'bech32'))[-1]
        connect_sync_disconnect(node0, node2, b27)
        assert_equal(node0.getblockcount(), 27)

        # generate fork with justified commits. node0 must switch to it
        #    - 27 - b28 node0, node1
        #   /
        # 26
        #   \
        #    - b27 node2
        self.wait_for_vote_and_disconnect(finalizer=validator, node=node1)
        b28 = node1.generatetoaddress(2, node1.getnewaddress('', 'bech32'))[-1]
        connect_sync_disconnect(node0, node1, b28)
        assert_equal(node0.getblockcount(), 28)
        assert_finalizationstate(node0, {'currentDynasty': 3,
                                         'currentEpoch': 6,
                                         'lastJustifiedEpoch': 5,
                                         'lastFinalizedEpoch': 4,
                                         'validators': 1})
        self.log.info('node successfully switched to longest justified fork')

        # generate longer but not justified fork. node0 shouldn't switch
        #    - 27 - b28 node0, node1, node2
        #   /
        # 26
        #   \
        #    - 27 - 28 - 29 - b30
        b30 = node2.generatetoaddress(3, node2.getnewaddress('', 'bech32'))[-1]
        assert_equal(node2.getblockcount(), 30)
        assert_equal(node0.getblockcount(), 28)

        connect_nodes(node0, node2.index)
        sync_chain([node0, node2], timeout=10)
        sync_blocks([node0, node2], timeout=10)

        assert_equal(node0.getblockcount(), 28)
        assert_equal(node0.getblockhash(28), b28)
        assert_equal(node0.getfinalizationstate()['lastJustifiedEpoch'], 5)
        self.log.info('node did not switch to heaviest but less justified fork')

        assert_equal(node2.getblockcount(), 28)
        assert_equal(node2.getblockhash(28), b28)
        assert_equal(node2.getfinalizationstate()['lastJustifiedEpoch'], 5)
        self.log.info('node switched to longest justified fork with less work')

        self.stop_node(node0.index)
        self.stop_node(node1.index)
        self.stop_node(node2.index)
        self.stop_node(validator.index)