def test_shard_genesis_fork_fork(self):
        """ Test shard forks at genesis blocks due to root chain fork at GENESIS.ROOT_HEIGHT"""
        acc1 = Address.create_random_account(0)
        acc2 = Address.create_random_account(1)

        with ClusterContext(2, acc1, genesis_root_heights=[0, 1]) as clusters:
            # shutdown cluster connection
            clusters[1].peer.close()

            master0 = clusters[0].master
            is_root, root0 = call_async(master0.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            call_async(master0.add_root_block(root0))
            genesis0 = clusters[0].get_shard_state(1).db.get_minor_block_by_height(0)
            self.assertEqual(
                genesis0.header.hash_prev_root_block, root0.header.get_hash()
            )

            master1 = clusters[1].master
            is_root, root1 = call_async(master1.get_next_block_to_mine(acc2))
            self.assertTrue(is_root)
            self.assertNotEqual(root0.header.get_hash(), root1.header.get_hash())
            call_async(master1.add_root_block(root1))
            genesis1 = clusters[1].get_shard_state(1).db.get_minor_block_by_height(0)
            self.assertEqual(
                genesis1.header.hash_prev_root_block, root1.header.get_hash()
            )

            # let's make cluster1's root chain longer than cluster0's
            # expect to mine shard 0 due to proof-of-progress
            is_root, block1 = call_async(master1.get_next_block_to_mine(acc2))
            self.assertFalse(is_root)
            self.assertEqual(block1.header.branch.get_shard_id(), 0)
            result = call_async(
                master1.add_raw_minor_block(block1.header.branch, block1.serialize())
            )
            self.assertTrue(result)

            is_root, root2 = call_async(master1.get_next_block_to_mine(acc2))
            self.assertTrue(is_root)
            call_async(master1.add_root_block(root2))
            self.assertEqual(master1.root_state.tip.height, 2)

            # reestablish cluster connection
            call_async(
                clusters[1].network.connect(
                    "127.0.0.1",
                    clusters[0].master.env.cluster_config.SIMPLE_NETWORK.BOOTSTRAP_PORT,
                )
            )
            # Expect cluster0's genesis change to genesis1
            assert_true_with_timeout(
                lambda: clusters[0]
                .get_shard_state(1)
                .db.get_minor_block_by_height(0)
                .header.get_hash()
                == genesis1.header.get_hash()
            )
            self.assertTrue(clusters[0].get_shard_state(1).root_tip == root2.header)
Exemple #2
0
    def test_shard_genesis_fork_fork(self):
        """ Test shard forks at genesis blocks due to root chain fork at GENESIS.ROOT_HEIGHT"""
        acc1 = Address.create_random_account(0)
        acc2 = Address.create_random_account(1)

        genesis_root_heights = {2: 0, 3: 1}
        with ClusterContext(
                2,
                acc1,
                chain_size=1,
                shard_size=2,
                genesis_root_heights=genesis_root_heights,
        ) as clusters:
            # shutdown cluster connection
            clusters[1].peer.close()

            master0 = clusters[0].master
            root0 = call_async(
                master0.get_next_block_to_mine(acc1, branch_value=None))
            call_async(master0.add_root_block(root0))
            genesis0 = (clusters[0].get_shard_state(
                2 | 1).db.get_minor_block_by_height(0))
            self.assertEqual(genesis0.header.hash_prev_root_block,
                             root0.header.get_hash())

            master1 = clusters[1].master
            root1 = call_async(
                master1.get_next_block_to_mine(acc2, branch_value=None))
            self.assertNotEqual(root0.header.get_hash(),
                                root1.header.get_hash())
            call_async(master1.add_root_block(root1))
            genesis1 = (clusters[1].get_shard_state(
                2 | 1).db.get_minor_block_by_height(0))
            self.assertEqual(genesis1.header.hash_prev_root_block,
                             root1.header.get_hash())

            self.assertNotEqual(genesis0.header.get_hash(),
                                genesis1.header.get_hash())

            # let's make cluster1's root chain longer than cluster0's
            root2 = call_async(
                master1.get_next_block_to_mine(acc2, branch_value=None))
            call_async(master1.add_root_block(root2))
            self.assertEqual(master1.root_state.tip.height, 2)

            # reestablish cluster connection
            call_async(clusters[1].network.connect(
                "127.0.0.1",
                clusters[0].master.env.cluster_config.SIMPLE_NETWORK.
                BOOTSTRAP_PORT,
            ))
            # Expect cluster0's genesis change to genesis1
            assert_true_with_timeout(lambda: clusters[0].get_shard_state(
                2 | 1).db.get_minor_block_by_height(0).header.get_hash() ==
                                     genesis1.header.get_hash())
            self.assertTrue(
                clusters[0].get_shard_state(2 | 1).root_tip == root2.header)
Exemple #3
0
    def test_add_minor_block_request_list(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(2, acc1) as clusters:
            shard_state = clusters[0].slave_list[0].shards[Branch(0b10)].state
            coinbase_amount = (
                shard_state.env.quark_chain_config.SHARD_LIST[
                    shard_state.shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            b1 = shard_state.get_tip().create_block_to_append()
            evm_state = shard_state.run_block(b1)
            b1.finalize(
                evm_state=evm_state,
                coinbase_amount=evm_state.block_fee + coinbase_amount,
            )
            add_result = call_async(
                clusters[0].master.add_raw_minor_block(b1.header.branch, b1.serialize())
            )
            self.assertTrue(add_result)

            # Make sure the xshard list is not broadcasted to the other shard
            self.assertFalse(
                clusters[0]
                .slave_list[1]
                .shards[Branch(0b11)]
                .state.contain_remote_minor_block_hash(b1.header.get_hash())
            )
            self.assertTrue(
                clusters[0].master.root_state.is_minor_block_validated(
                    b1.header.get_hash()
                )
            )

            # Make sure another cluster received the new block
            assert_true_with_timeout(
                lambda: clusters[1]
                .slave_list[0]
                .shards[Branch(0b10)]
                .state.contain_block_by_hash(b1.header.get_hash())
            )
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.is_minor_block_validated(
                    b1.header.get_hash()
                )
            )
    def test_add_transaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=1)

        with ClusterContext(2, acc1) as clusters:
            master = clusters[0].master

            root = call_async(
                master.get_next_block_to_mine(acc1, branch_value=None))
            call_async(master.add_root_block(root))

            tx1 = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(0b10),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(call_async(master.add_transaction(tx1)))
            self.assertEqual(len(clusters[0].get_shard_state(0b10).tx_queue),
                             1)

            branch1 = Branch(2 | 1)
            tx2 = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(0b11),
                key=id1.get_key(),
                from_address=acc2,
                to_address=acc1,
                value=12345,
                gas=30000,
            )
            self.assertTrue(call_async(master.add_transaction(tx2)))
            self.assertEqual(len(clusters[0].get_shard_state(0b11).tx_queue),
                             1)

            # check the tx is received by the other cluster
            tx_queue = clusters[1].get_shard_state(0b10).tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(), tx1.tx.to_evm_tx())

            tx_queue = clusters[1].get_shard_state(0b11).tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(), tx2.tx.to_evm_tx())
Exemple #5
0
    def test_add_transaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=1)

        with ClusterContext(2, acc1) as clusters:
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch0 = Branch(2)
            tx1 = create_transfer_transaction(
                shard_state=slaves[0].shards[branch0].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(call_async(master.add_transaction(tx1)))
            self.assertEqual(len(slaves[0].shards[branch0].state.tx_queue), 1)

            branch1 = Branch(2 | 1)
            tx2 = create_transfer_transaction(
                shard_state=slaves[1].shards[branch1].state,
                key=id1.get_key(),
                from_address=acc2,
                to_address=acc1,
                value=12345,
                gas=30000,
            )
            self.assertTrue(call_async(master.add_transaction(tx2)))
            self.assertEqual(len(slaves[1].shards[branch1].state.tx_queue), 1)

            # check the tx is received by the other cluster
            tx_queue = clusters[1].slave_list[0].shards[branch0].state.tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(),
                             tx1.code.get_evm_transaction())

            tx_queue = clusters[1].slave_list[1].shards[branch1].state.tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(),
                             tx2.code.get_evm_transaction())
Exemple #6
0
    def test_add_minor_block_request_list(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            shard_state = clusters[0].get_shard_state(0b10)
            b1 = _tip_gen(shard_state)
            add_result = call_async(clusters[0].master.add_raw_minor_block(
                b1.header.branch, b1.serialize()))
            self.assertTrue(add_result)

            # Make sure the xshard list is not broadcasted to the other shard
            self.assertFalse(clusters[0].get_shard_state(
                0b11).contain_remote_minor_block_hash(b1.header.get_hash()))
            self.assertTrue(
                clusters[0].master.root_state.db.contain_minor_block_by_hash(
                    b1.header.get_hash()))

            # Make sure another cluster received the new block
            assert_true_with_timeout(lambda: clusters[0].get_shard_state(
                0b10).contain_block_by_hash(b1.header.get_hash()))
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.db.
                contain_minor_block_by_hash(b1.header.get_hash()))
Exemple #7
0
    def test_shard_synchronizer_with_fork(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            # shutdown cluster connection
            clusters[1].peer.close()

            block_list = []
            # cluster 0 has 13 blocks added
            shard_state0 = clusters[0].get_shard_state(0b10)
            coinbase_amount = (
                shard_state0.env.quark_chain_config.shards[
                    shard_state0.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            for i in range(13):
                block = shard_state0.get_tip().create_block_to_append()
                evm_state = shard_state0.run_block(block)
                block.finalize(
                    evm_state=evm_state,
                    coinbase_amount=evm_state.block_fee + coinbase_amount,
                )
                add_result = call_async(
                    clusters[0].master.add_raw_minor_block(
                        block.header.branch, block.serialize()
                    )
                )
                self.assertTrue(add_result)
                block_list.append(block)
            self.assertEqual(clusters[0].get_shard_state(0b10).header_tip.height, 13)

            # cluster 1 has 12 blocks added
            shard_state0 = clusters[1].get_shard_state(0b10)
            coinbase_amount = (
                shard_state0.env.quark_chain_config.shards[
                    shard_state0.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            for i in range(12):
                block = shard_state0.get_tip().create_block_to_append()
                evm_state = shard_state0.run_block(block)
                block.finalize(
                    evm_state=evm_state,
                    coinbase_amount=evm_state.block_fee + coinbase_amount,
                )
                add_result = call_async(
                    clusters[1].master.add_raw_minor_block(
                        block.header.branch, block.serialize()
                    )
                )
                self.assertTrue(add_result)
            self.assertEqual(clusters[1].get_shard_state(0b10).header_tip.height, 12)

            # reestablish cluster connection
            call_async(
                clusters[1].network.connect(
                    "127.0.0.1",
                    clusters[0].master.env.cluster_config.SIMPLE_NETWORK.BOOTSTRAP_PORT,
                )
            )

            # a new block from cluster 0 will trigger sync in cluster 1
            shard_state0 = clusters[0].get_shard_state(0b10)
            coinbase_amount = (
                shard_state0.env.quark_chain_config.shards[
                    shard_state0.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            block = shard_state0.get_tip().create_block_to_append()
            evm_state = shard_state0.run_block(block)
            block.finalize(
                evm_state=evm_state,
                coinbase_amount=evm_state.block_fee + coinbase_amount,
            )
            add_result = call_async(
                clusters[0].master.add_raw_minor_block(
                    block.header.branch, block.serialize()
                )
            )
            self.assertTrue(add_result)
            block_list.append(block)

            # expect cluster 1 has all the blocks from cluter 0 and
            # has the same tip as cluster 0
            for block in block_list:
                assert_true_with_timeout(
                    lambda: clusters[1]
                    .slave_list[0]
                    .shards[Branch(0b10)]
                    .state.contain_block_by_hash(block.header.get_hash())
                )
                assert_true_with_timeout(
                    lambda: clusters[1].master.root_state.is_minor_block_validated(
                        block.header.get_hash()
                    )
                )

            self.assertEqual(
                clusters[1].get_shard_state(0b10).header_tip,
                clusters[0].get_shard_state(0b10).header_tip,
            )
Exemple #8
0
    def test_add_root_block_request_list(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            # shutdown cluster connection
            clusters[1].peer.close()

            # add blocks in cluster 0
            block_header_list = [clusters[0].get_shard_state(2 | 0).header_tip]
            shard_state0 = clusters[0].get_shard_state(0b10)
            coinbase_amount = (
                shard_state0.env.quark_chain_config.shards[
                    shard_state0.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            for i in range(7):
                b1 = shard_state0.get_tip().create_block_to_append()
                evm_state = shard_state0.run_block(b1)
                b1.finalize(
                    evm_state=evm_state,
                    coinbase_amount=evm_state.block_fee + coinbase_amount,
                )
                add_result = call_async(
                    clusters[0].master.add_raw_minor_block(
                        b1.header.branch, b1.serialize()
                    )
                )
                self.assertTrue(add_result)
                block_header_list.append(b1.header)

            block_header_list.append(clusters[0].get_shard_state(2 | 1).header_tip)
            shard_state0 = clusters[0].get_shard_state(0b11)
            coinbase_amount = (
                shard_state0.env.quark_chain_config.shards[
                    shard_state0.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            b2 = shard_state0.get_tip().create_block_to_append()
            evm_state = shard_state0.run_block(b2)
            b2.finalize(
                evm_state=evm_state,
                coinbase_amount=evm_state.block_fee + coinbase_amount,
            )
            add_result = call_async(
                clusters[0].master.add_raw_minor_block(b2.header.branch, b2.serialize())
            )
            self.assertTrue(add_result)
            block_header_list.append(b2.header)

            # add 1 block in cluster 1
            shard_state1 = clusters[1].get_shard_state(0b11)
            coinbase_amount = (
                shard_state1.env.quark_chain_config.shards[
                    shard_state1.full_shard_id
                ].COINBASE_AMOUNT
                // 2
            )
            b3 = shard_state1.get_tip().create_block_to_append()
            evm_state = shard_state1.run_block(b3)
            b3.finalize(
                evm_state=evm_state,
                coinbase_amount=evm_state.block_fee + coinbase_amount,
            )
            add_result = call_async(
                clusters[1].master.add_raw_minor_block(b3.header.branch, b3.serialize())
            )
            self.assertTrue(add_result)

            self.assertEqual(clusters[1].get_shard_state(0b11).header_tip, b3.header)

            # reestablish cluster connection
            call_async(
                clusters[1].network.connect(
                    "127.0.0.1",
                    clusters[0].master.env.cluster_config.SIMPLE_NETWORK.BOOTSTRAP_PORT,
                )
            )

            root_block1 = clusters[0].master.root_state.create_block_to_mine(
                block_header_list, acc1
            )
            call_async(clusters[0].master.add_root_block(root_block1))

            # Make sure the root block tip of local cluster is changed
            self.assertEqual(clusters[0].master.root_state.tip, root_block1.header)

            # Make sure the root block tip of cluster 1 is changed
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.tip == root_block1.header, 2
            )

            # Minor block is downloaded
            self.assertEqual(b1.header.height, 7)
            assert_true_with_timeout(
                lambda: clusters[1].get_shard_state(0b10).header_tip == b1.header
            )

            # The tip is overwritten due to root chain first consensus
            assert_true_with_timeout(
                lambda: clusters[1].get_shard_state(0b11).header_tip == b2.header
            )
Exemple #9
0
    def test_get_root_block_headers_with_skip(self):
        """ Test the broadcast is only done to the neighbors """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            master = clusters[0].master

            # Add a root block first so that later minor blocks referring to this root
            # can be broadcasted to other shards
            root_block_header_list = [master.root_state.tip]
            for i in range(10):
                root_block = call_async(
                    master.get_next_block_to_mine(
                        Address.create_empty_account(), branch_value=None))
                call_async(master.add_root_block(root_block))
                root_block_header_list.append(root_block.header)

            self.assertEqual(root_block_header_list[-1].height, 10)
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.tip.height == 10)

            peer = clusters[1].peer

            # Test Case 1 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=1,
                        skip=1,
                        limit=3,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 3)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[1])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[3])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[5])

            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=root_block_header_list[1].get_hash(),
                        skip=1,
                        limit=3,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 3)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[1])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[3])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[5])

            # Test Case 2 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=2,
                        skip=2,
                        limit=4,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 3)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[2])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[5])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[8])

            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=root_block_header_list[2].get_hash(),
                        skip=2,
                        limit=4,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 3)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[2])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[5])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[8])

            # Test Case 3 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=6,
                        skip=0,
                        limit=100,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 5)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[6])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[7])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[8])
            self.assertEqual(resp.block_header_list[3],
                             root_block_header_list[9])
            self.assertEqual(resp.block_header_list[4],
                             root_block_header_list[10])

            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=root_block_header_list[6].get_hash(),
                        skip=0,
                        limit=100,
                        direction=Direction.TIP,
                    )))
            self.assertEqual(len(resp.block_header_list), 5)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[6])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[7])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[8])
            self.assertEqual(resp.block_header_list[3],
                             root_block_header_list[9])
            self.assertEqual(resp.block_header_list[4],
                             root_block_header_list[10])

            # Test Case 4 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=2,
                        skip=2,
                        limit=4,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 1)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[2])
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=root_block_header_list[2].get_hash(),
                        skip=2,
                        limit=4,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 1)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[2])

            # Test Case 5 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=11,
                        skip=2,
                        limit=4,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 0)

            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=bytes(32),
                        skip=2,
                        limit=4,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 0)

            # Test Case 6 ###################################################
            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.
                    create_for_height(
                        height=8,
                        skip=1,
                        limit=5,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 5)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[8])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[6])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[4])
            self.assertEqual(resp.block_header_list[3],
                             root_block_header_list[2])
            self.assertEqual(resp.block_header_list[4],
                             root_block_header_list[0])

            op, resp, rpc_id = call_async(
                peer.write_rpc_request(
                    op=CommandOp.GET_ROOT_BLOCK_HEADER_LIST_WITH_SKIP_REQUEST,
                    cmd=GetRootBlockHeaderListWithSkipRequest.create_for_hash(
                        hash=root_block_header_list[8].get_hash(),
                        skip=1,
                        limit=5,
                        direction=Direction.GENESIS,
                    )))
            self.assertEqual(len(resp.block_header_list), 5)
            self.assertEqual(resp.block_header_list[0],
                             root_block_header_list[8])
            self.assertEqual(resp.block_header_list[1],
                             root_block_header_list[6])
            self.assertEqual(resp.block_header_list[2],
                             root_block_header_list[4])
            self.assertEqual(resp.block_header_list[3],
                             root_block_header_list[2])
            self.assertEqual(resp.block_header_list[4],
                             root_block_header_list[0])
Exemple #10
0
    def test_handle_get_minor_block_list_request_with_total_diff(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            cluster0_root_state = clusters[0].master.root_state
            cluster1_root_state = clusters[1].master.root_state
            coinbase = cluster1_root_state._calculate_root_block_coinbase([],
                                                                          0)

            # Cluster 0 generates a root block of height 1 with 1e6 difficulty
            rb0 = cluster0_root_state.get_tip_block()
            rb1 = rb0.create_block_to_append(
                difficulty=int(1e6)).finalize(coinbase)

            # Establish cluster connection
            call_async(clusters[1].network.connect(
                "127.0.0.1",
                clusters[0].master.env.cluster_config.SIMPLE_NETWORK.
                BOOTSTRAP_PORT,
            ))

            # Cluster 0 broadcasts the root block to cluster 1
            call_async(clusters[0].master.add_root_block(rb1))
            self.assertEqual(cluster0_root_state.tip.get_hash(),
                             rb1.header.get_hash())

            # Make sure the root block tip of cluster 1 is changed
            assert_true_with_timeout(
                lambda: cluster1_root_state.tip == rb1.header, 2)

            # Cluster 1 generates a minor block and broadcasts to cluster 0
            shard_state = clusters[1].get_shard_state(0b10)
            b1 = _tip_gen(shard_state)
            add_result = call_async(clusters[1].master.add_raw_minor_block(
                b1.header.branch, b1.serialize()))
            self.assertTrue(add_result)

            # Make sure another cluster received the new minor block
            assert_true_with_timeout(lambda: clusters[1].get_shard_state(
                0b10).contain_block_by_hash(b1.header.get_hash()))
            assert_true_with_timeout(
                lambda: clusters[0].master.root_state.db.
                contain_minor_block_by_hash(b1.header.get_hash()))

            # Cluster 1 generates a new root block with higher total difficulty
            rb2 = rb0.create_block_to_append(
                difficulty=int(3e6)).finalize(coinbase)
            call_async(clusters[1].master.add_root_block(rb2))
            self.assertEqual(cluster1_root_state.tip.get_hash(),
                             rb2.header.get_hash())

            # Generate a minor block b2
            b2 = _tip_gen(shard_state)
            add_result = call_async(clusters[1].master.add_raw_minor_block(
                b2.header.branch, b2.serialize()))
            self.assertTrue(add_result)

            # Make sure another cluster received the new minor block
            assert_true_with_timeout(lambda: clusters[1].get_shard_state(
                0b10).contain_block_by_hash(b2.header.get_hash()))
            assert_true_with_timeout(
                lambda: clusters[0].master.root_state.db.
                contain_minor_block_by_hash(b2.header.get_hash()))