Exemple #1
0
    def test_xshard_tx_sent(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_from_identity(id1, full_shard_id=1)
        acc3 = Address.create_random_account(full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env, shard_id=0)
        env1 = get_test_env(genesis_account=acc1,
                            genesis_minor_quarkash=10000000)
        state1 = create_default_shard_state(env=env1, shard_id=1)

        # Add a root block to update block gas limit so that xshard tx can be included
        root_block = (
            state.root_tip.create_block_to_append().add_minor_block_header(
                state.header_tip).add_minor_block_header(
                    state1.header_tip).finalize())
        state.add_root_block(root_block)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=888888,
            gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST,
        )
        state.add_tx(tx)

        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)

        self.assertEqual(state.evm_state.gas_used, 0)
        # Should succeed
        state.finalize_and_add_block(b1)
        self.assertEqual(len(state.evm_state.xshard_list), 1)
        self.assertEqual(
            state.evm_state.xshard_list[0],
            CrossShardTransactionDeposit(
                tx_hash=tx.get_hash(),
                from_address=acc1,
                to_address=acc2,
                value=888888,
                gas_price=1,
            ),
        )
        self.assertEqual(
            state.get_balance(id1.recipient),
            10000000 - 888888 - opcodes.GTXCOST - opcodes.GTXXSHARDCOST,
        )
        # Make sure the xshard gas is not used by local block
        self.assertEqual(state.evm_state.gas_used,
                         opcodes.GTXCOST + opcodes.GTXXSHARDCOST)
        # GTXXSHARDCOST is consumed by remote shard
        self.assertEqual(state.get_balance(acc3.recipient),
                         opcodes.GTXCOST // 2)
Exemple #2
0
 def test_blocks_with_incorrect_height(self):
     env = get_test_env()
     r_state, s_states = create_default_state(env)
     root_block = r_state.create_block_to_mine([])
     root_block.header.height += 1
     with self.assertRaisesRegexp(ValueError, "incorrect block height"):
         r_state.add_block(root_block)
Exemple #3
0
    def test_shard_state_add_root_block_too_many_minor_blocks(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000,
                           shard_size=1)
        state = create_default_shard_state(env=env, shard_id=0)

        headers = [state.header_tip]
        for i in range(13):
            b = state.get_tip().create_block_to_append(address=acc1)
            state.finalize_and_add_block(b)
            headers.append(b.header)

        root_block = (state.root_tip.create_block_to_append().
                      extend_minor_block_header_list(headers).finalize())

        # Too many blocks
        self.assertRaises(ValueError, state.add_root_block, root_block)

        self.assertEqual(state.get_unconfirmed_header_list(), headers[:13])

        # 10 blocks is okay
        root_block.minor_block_header_list = headers[:13]
        root_block.finalize()
        state.add_root_block(root_block)
Exemple #4
0
    def test_shard_state_fork_resolve_with_higher_root_chain(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env, shard_id=0)

        b0 = state.get_tip().create_block_to_append()
        state.finalize_and_add_block(b0)
        root_block = (
            state.root_tip.create_block_to_append().add_minor_block_header(
                b0.header).finalize())

        self.assertEqual(state.header_tip, b0.header)
        self.assertTrue(state.add_root_block(root_block))

        b1 = state.get_tip().create_block_to_append()
        b2 = state.get_tip().create_block_to_append(nonce=1)
        b2.header.hash_prev_root_block = root_block.header.get_hash()
        b3 = state.get_tip().create_block_to_append(nonce=2)
        b3.header.hash_prev_root_block = root_block.header.get_hash()

        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)

        # Fork happens, although they have the same height, b2 survives since it confirms root block
        state.finalize_and_add_block(b2)
        self.assertEqual(state.header_tip, b2.header)

        # b3 confirms the same root block as b2, so it will not override b2
        state.finalize_and_add_block(b3)
        self.assertEqual(state.header_tip, b2.header)
Exemple #5
0
    def test_native_token_transfer_0_value_success(self):
        """to prevent storage spamming, do not delta_token_balance does not take action if value is 0
        """
        MALICIOUS0 = token_id_encode("MALICIOUS0")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 10000000,
                "MALICIOUS0": 0,
            },
        )
        state = create_default_shard_state(env=env)
        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=self.genesis_token,
            transfer_token_id=MALICIOUS0,
        )
        self.assertFalse(state.add_tx(tx))
Exemple #6
0
    def test_root_state_add_block_missing_minor_block_header(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.get_tip().create_block_to_append()
        s_state0.finalize_and_add_block(b0)
        b1 = s_state1.get_tip().create_block_to_append()
        s_state1.finalize_and_add_block(b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())
        root_block = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                b1.header).finalize())

        with self.assertRaises(ValueError):
            r_state.add_block(root_block)

        root_block = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                b0.header).finalize())

        with self.assertRaises(ValueError):
            r_state.add_block(root_block)
Exemple #7
0
    def test_root_state_and_shard_state_add_two_blocks(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b0)
        b1 = s_state1.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())
        root_block0 = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                s_state0.db.get_minor_block_by_height(0).header
            ).add_minor_block_header(b0.header).add_minor_block_header(
                s_state1.db.get_minor_block_by_height(
                    0).header).add_minor_block_header(b1.header).finalize())

        self.assertTrue(r_state.add_block(root_block0))

        b2 = s_state0.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b2)
        b3 = s_state1.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b3)

        r_state.add_validated_minor_block_hash(b2.header.get_hash())
        r_state.add_validated_minor_block_hash(b3.header.get_hash())
        root_block1 = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                b2.header).add_minor_block_header(b3.header).finalize())

        self.assertTrue(r_state.add_block(root_block1))
Exemple #8
0
 def test_blocks_with_incorrect_total_difficulty(self):
     env = get_test_env()
     r_state, s_states = create_default_state(env)
     root_block = r_state.create_block_to_mine([])
     root_block.header.total_difficulty += 1
     with self.assertRaisesRegexp(ValueError, "incorrect total difficulty"):
         r_state.add_block(root_block)
Exemple #9
0
    def test_root_state_add_two_blocks(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b0)
        b1 = s_state1.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(
            b0.header.get_hash(), b0.header.coinbase_amount_map.balance_map)
        r_state.add_validated_minor_block_hash(
            b1.header.get_hash(), b1.header.coinbase_amount_map.balance_map)
        root_block0 = r_state.create_block_to_mine([b0.header, b1.header])

        self.assertTrue(r_state.add_block(root_block0))

        b2 = s_state0.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b2)
        b3 = s_state1.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b3)

        r_state.add_validated_minor_block_hash(
            b2.header.get_hash(), b2.header.coinbase_amount_map.balance_map)
        r_state.add_validated_minor_block_hash(
            b3.header.get_hash(), b3.header.coinbase_amount_map.balance_map)
        root_block1 = r_state.create_block_to_mine([b2.header, b3.header])

        self.assertTrue(r_state.add_block(root_block1))
Exemple #10
0
 def test_root_coinbase_decay(self):
     env = get_test_env()
     r_state, s_states = create_default_state(env)
     coinbase = r_state._calculate_root_block_coinbase(
         [], env.quark_chain_config.ROOT.EPOCH_INTERVAL)
     self.assertEqual(
         coinbase,
         {
             env.quark_chain_config.genesis_token:
             env.quark_chain_config.ROOT.COINBASE_AMOUNT *
             env.quark_chain_config.BLOCK_REWARD_DECAY_FACTOR
         },
     )
     coinbase = r_state._calculate_root_block_coinbase(
         [], env.quark_chain_config.ROOT.EPOCH_INTERVAL + 1)
     self.assertEqual(
         coinbase,
         {
             env.quark_chain_config.genesis_token:
             env.quark_chain_config.ROOT.COINBASE_AMOUNT *
             env.quark_chain_config.BLOCK_REWARD_DECAY_FACTOR
         },
     )
     coinbase = r_state._calculate_root_block_coinbase(
         [], env.quark_chain_config.ROOT.EPOCH_INTERVAL * 2)
     self.assertEqual(
         coinbase,
         {
             env.quark_chain_config.genesis_token:
             env.quark_chain_config.ROOT.COINBASE_AMOUNT *
             env.quark_chain_config.BLOCK_REWARD_DECAY_FACTOR**2
         },
     )
Exemple #11
0
    def test_root_state_add_root_block_too_many_minor_blocks(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[2 | 0]
        headers = []
        max_mblock_in_rblock = (
            s_state0.shard_config.max_blocks_per_shard_in_one_root_block)

        for i in range(max_mblock_in_rblock + 1):
            b = s_state0.create_block_to_mine()
            add_minor_block_to_cluster(s_states, b)
            headers.append(b.header)
            r_state.add_validated_minor_block_hash(
                b.header.get_hash(), b.header.coinbase_amount_map.balance_map)

        root_block = r_state.create_block_to_mine(
            m_header_list=headers, create_time=headers[-1].create_time + 1)
        with self.assertRaisesRegexp(
                ValueError,
                "too many minor blocks in the root block for shard"):
            r_state.add_block(root_block)

        headers = headers[:max_mblock_in_rblock]
        root_block = r_state.create_block_to_mine(
            m_header_list=headers, create_time=headers[-1].create_time + 1)
        r_state.add_block(root_block)
Exemple #12
0
    def test_root_state_and_shard_state_add_block(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b0)
        b1 = s_state1.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())
        root_block = r_state.create_block_to_mine([b0.header, b1.header])

        self.assertTrue(r_state.add_block(root_block))
        self.assertIsNone(r_state.get_root_block_by_height(3))
        self.assertEqual(r_state.get_root_block_by_height(2), root_block)
        self.assertEqual(r_state.get_root_block_by_height(None), root_block)
        self.assertEqual(
            r_state.get_root_block_by_height(1),
            r_state.get_root_block_by_hash(root_block.header.hash_prev_block),
        )

        self.assertTrue(s_state0.add_root_block(root_block))
        self.assertEqual(s_state0.root_tip, root_block.header)
        self.assertTrue(s_state1.add_root_block(root_block))
        self.assertEqual(s_state1.root_tip, root_block.header)
Exemple #13
0
    def test_root_state_add_block(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        # chain_id is 0
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.get_tip().create_block_to_append()
        s_state0.finalize_and_add_block(b0)
        b1 = s_state1.get_tip().create_block_to_append()
        s_state1.finalize_and_add_block(b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())
        root_block = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                s_state0.db.get_minor_block_by_height(0).header
            ).add_minor_block_header(b0.header).add_minor_block_header(
                s_state1.db.get_minor_block_by_height(
                    0).header).add_minor_block_header(b1.header).finalize())

        self.assertTrue(r_state.add_block(root_block))

        self.assertIsNone(r_state.get_root_block_by_height(2))
        self.assertEqual(r_state.get_root_block_by_height(1), root_block)
        self.assertEqual(r_state.get_root_block_by_height(None), root_block)
        self.assertEqual(
            r_state.get_root_block_by_height(0),
            r_state.get_root_block_by_hash(root_block.header.hash_prev_block),
        )
Exemple #14
0
    def test_gas_price(self):
        id_list = [Identity.create_random_identity() for _ in range(5)]
        acc_list = [
            Address.create_from_identity(i, full_shard_id=0) for i in id_list
        ]
        env = get_test_env(genesis_account=acc_list[0],
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env)

        # 5 tx per block, make 3 blocks
        for _ in range(3):
            for j in range(5):
                state.add_tx(
                    create_transfer_transaction(
                        shard_state=state,
                        key=id_list[j].get_key(),
                        from_address=acc_list[j],
                        to_address=random.choice(acc_list),
                        value=0,
                        gas_price=42 if j == 0 else 0,
                    ))
            b = state.create_block_to_mine(address=acc_list[1])
            state.finalize_and_add_block(b)

        # for testing purposes, update percentile to take max gas price
        state.gas_price_suggestion_oracle.percentile = 100
        gas_price = state.gas_price()
        self.assertEqual(gas_price, 42)
        # results should be cached (same header). updating oracle shouldn't take effect
        state.gas_price_suggestion_oracle.percentile = 50
        gas_price = state.gas_price()
        self.assertEqual(gas_price, 42)
Exemple #15
0
    def test_add_non_neighbor_tx_fail(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(
            full_shard_id=3)  # not acc1's neighbor
        acc3 = Address.create_random_account(
            full_shard_id=8)  # acc1's neighbor

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000,
                           shard_size=64)
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=0,
            gas=1000000,
        )
        self.assertFalse(state.add_tx(tx))
        self.assertEqual(len(state.tx_queue), 0)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc3,
            value=0,
            gas=1000000,
        )
        self.assertTrue(state.add_tx(tx))
        self.assertEqual(len(state.tx_queue), 1)
Exemple #16
0
    def test_root_state_and_shard_state_add_block(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        self.assertEqual(r_state.tip.total_difficulty, 2000000)
        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b0)
        b1 = s_state1.create_block_to_mine()
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(
            b0.header.get_hash(), b0.header.coinbase_amount_map.balance_map)
        r_state.add_validated_minor_block_hash(
            b1.header.get_hash(), b1.header.coinbase_amount_map.balance_map)
        root_block = r_state.create_block_to_mine([b0.header, b1.header])

        self.assertEqual(root_block.header.total_difficulty, 3000976)
        self.assertTrue(r_state.add_block(root_block))
        self.assertIsNone(r_state.db.get_root_block_by_height(3))
        self.assertEqual(r_state.db.get_root_block_by_height(2), root_block)
        tip_height = r_state.tip.height
        self.assertEqual(r_state.db.get_root_block_by_height(tip_height),
                         root_block)
        self.assertEqual(
            r_state.db.get_root_block_by_height(1),
            r_state.db.get_root_block_by_hash(
                root_block.header.hash_prev_block),
        )

        self.assertTrue(s_state0.add_root_block(root_block))
        self.assertEqual(s_state0.root_tip, root_block.header)
        self.assertTrue(s_state1.add_root_block(root_block))
        self.assertEqual(s_state1.root_tip, root_block.header)
    def test_native_token_gas(self):
        """in-shard transfer QETH using native token as gas
        TODODLL: support native token as gas
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_token_balances={"QETH": 10000000})
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=QETH,
            transfer_token_id=QETH,
        )
        self.assertFalse(
            state.add_tx(tx)
        )  # warning log: Failed to add transaction: Gas token must be QKC
        return

        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(state.get_token_balance(id1.recipient, QETH),
                         10000000 - opcodes.GTXCOST)
        self.assertEqual(
            state.get_token_balance(acc1.recipient, QETH),
            10000000 - opcodes.GTXCOST - 12345,
        )
        self.assertEqual(state.get_token_balance(acc2.recipient, QETH), 12345)
        # tx fee
        self.assertEqual(
            state.get_token_balance(acc3.recipient, QETH),
            self.getAfterTaxReward(opcodes.GTXCOST),
        )
        # miner coinbase
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.getAfterTaxReward(self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, QETH)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, QETH)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
Exemple #18
0
    def test_root_state_and_shard_state_fork(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)

        s_state0 = s_states[2 | 0]
        s_state1 = s_states[2 | 1]
        b0 = s_state0.get_tip().create_block_to_append()
        b2 = s_state0.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b0)
        b1 = s_state1.get_tip().create_block_to_append(nonce=1)
        b3 = s_state1.get_tip().create_block_to_append(nonce=1)
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())
        root_block0 = (
            r_state.tip.create_block_to_append().add_minor_block_header(
                s_state0.db.get_minor_block_by_height(0).header
            ).add_minor_block_header(b0.header).add_minor_block_header(
                s_state1.db.get_minor_block_by_height(
                    0).header).add_minor_block_header(b1.header).finalize())
        root_block1 = r_state.tip.create_block_to_append()

        self.assertTrue(r_state.add_block(root_block0))
        self.assertTrue(s_state0.add_root_block(root_block0))
        self.assertTrue(s_state1.add_root_block(root_block0))

        add_minor_block_to_cluster(s_states, b2)
        add_minor_block_to_cluster(s_states, b3)

        r_state.add_validated_minor_block_hash(b2.header.get_hash())
        r_state.add_validated_minor_block_hash(b3.header.get_hash())
        root_block1 = (root_block1.add_minor_block_header(
            s_state0.db.get_minor_block_by_height(0).header
        ).add_minor_block_header(b2.header).add_minor_block_header(
            s_state1.db.get_minor_block_by_height(
                0).header).add_minor_block_header(b3.header).finalize())

        self.assertFalse(r_state.add_block(root_block1))
        self.assertFalse(s_state0.add_root_block(root_block1))
        self.assertFalse(s_state1.add_root_block(root_block1))

        b4 = b2.create_block_to_append()
        b5 = b3.create_block_to_append()
        add_minor_block_to_cluster(s_states, b4)
        add_minor_block_to_cluster(s_states, b5)

        r_state.add_validated_minor_block_hash(b4.header.get_hash())
        r_state.add_validated_minor_block_hash(b5.header.get_hash())
        root_block2 = (
            root_block1.create_block_to_append().add_minor_block_header(
                b4.header).add_minor_block_header(b5.header).finalize())

        self.assertTrue(r_state.add_block(root_block2))
        self.assertTrue(s_state0.add_root_block(root_block2))
        self.assertTrue(s_state1.add_root_block(root_block2))
        self.assertEqual(r_state.tip, root_block2.header)
        self.assertEqual(s_state0.root_tip, root_block2.header)
        self.assertEqual(s_state1.root_tip, root_block2.header)
Exemple #19
0
    def test_add_minor_block_with_wrong_root_block_hash(self):
        """ Test for the following case
                 +--+
                 |r1|
                /+--+
               /   |
        +--+  /  +--+    +--+
        |r0|<----|m1|<---|m3|
        +--+  \  +--+    +--+
          ^    \          |
          |     \+--+     |
          |      |r2|<----+
          |      +--+
          |        |
          |      +--+
          +------|m2|
                 +--+
        where m3 is invalid because m3 depends on r2, whose minor chain is not the same chain as m3
        """
        env = get_test_env(shard_size=1)
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[1 | 0]

        root_block0 = r_state.get_tip_block()

        m1 = s_state0.get_tip().create_block_to_append(nonce=0)
        m2 = s_state0.get_tip().create_block_to_append(nonce=1)
        add_minor_block_to_cluster(s_states, m1)
        add_minor_block_to_cluster(s_states, m2)

        r_state.add_validated_minor_block_hash(m1.header.get_hash())
        r_state.add_validated_minor_block_hash(m2.header.get_hash())
        root_block1 = (root_block0.create_block_to_append(
            nonce=0).add_minor_block_header(m1.header).finalize())
        root_block2 = (root_block0.create_block_to_append(
            nonce=1).add_minor_block_header(m2.header).finalize())

        self.assertTrue(r_state.add_block(root_block1))
        self.assertFalse(r_state.add_block(root_block2))
        self.assertTrue(s_state0.add_root_block(root_block1))
        self.assertFalse(s_state0.add_root_block(root_block2))

        m3 = m1.create_block_to_append()
        m3.header.hash_prev_root_block = root_block2.header.get_hash()
        with self.assertRaises(ValueError):
            add_minor_block_to_cluster(s_states, m3)

        m4 = m1.create_block_to_append()
        m4.header.hash_prev_root_block = root_block1.header.get_hash()
        add_minor_block_to_cluster(s_states, m4)

        # Test recovery
        s_state0_recovered = ShardState(env,
                                        full_shard_id=1 | 0,
                                        db=s_state0.raw_db)
        s_state0_recovered.init_from_root_block(root_block1)
        with self.assertRaises(ValueError):
            add_minor_block_to_cluster(s_states, m3)
    def test_root_state_difficulty(self):
        env = get_test_env()
        env.quark_chain_config.SKIP_ROOT_DIFFICULTY_CHECK = False
        env.quark_chain_config.ROOT.GENESIS.DIFFICULTY = 1000
        diff_calc = EthDifficultyCalculator(cutoff=9,
                                            diff_factor=2048,
                                            minimum_diff=1)
        env.quark_chain_config.NETWORK_ID = (
            1)  # other network ids will skip difficulty check

        r_state, s_states = create_default_state(env, diff_calc=diff_calc)
        g0 = s_states[0].header_tip
        b0 = s_states[0].get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b0)
        g1 = s_states[1].header_tip
        b1 = s_states[1].get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, b1)

        r_state.add_validated_minor_block_hash(b0.header.get_hash())
        r_state.add_validated_minor_block_hash(b1.header.get_hash())

        # Check new difficulty
        root_block0 = r_state.create_block_to_mine(
            m_header_list=[b0.header, b1.header],
            address=Address.create_empty_account(),
            create_time=r_state.tip.create_time + 9,
        )
        self.assertEqual(r_state.tip.difficulty, root_block0.header.difficulty)
        root_block0 = r_state.create_block_to_mine(
            m_header_list=[b0.header, b1.header],
            address=Address.create_empty_account(),
            create_time=r_state.tip.create_time + 3,
        )
        self.assertEqual(
            r_state.tip.difficulty + r_state.tip.difficulty // 2048,
            root_block0.header.difficulty,
        )

        root_block0 = r_state.create_block_to_mine(
            m_header_list=[g0, b0.header, g1, b1.header],
            address=Address.create_empty_account(),
            create_time=r_state.tip.create_time + 26,
        ).finalize()
        self.assertEqual(
            r_state.tip.difficulty - r_state.tip.difficulty // 2048,
            root_block0.header.difficulty,
        )

        for i in range(0, 2**32):
            root_block0.header.nonce = i
            if (int.from_bytes(root_block0.header.get_hash(), byteorder="big")
                    * env.quark_chain_config.ROOT.GENESIS.DIFFICULTY < 2**256):
                self.assertTrue(r_state.add_block(root_block0))
                break
            else:
                with self.assertRaises(ValueError):
                    r_state.add_block(root_block0)
Exemple #21
0
    def test_add_root_block_revert_header_tip(self):
        """ block's hash_prev_root_block must be on the same chain with root_tip to update tip.

                 +--+
                 |r1|<-------------+
                /+--+              |
               /   |               |
        +--+  /  +--+    +--+     +--+
        |r0|<----|m1|<---|m2| <---|m3|
        +--+  \  +--+    +--+     +--+
               \   |       \
                \+--+.     +--+
                 |r2|<-----|r3| (r3 includes m2)
                 +--+      +--+

        Initial state: r0 <- m1 <- m2
        Adding r1, r2, m3 makes r1 the root_tip, m3 the header_tip
        Adding r3 should change the root_tip to r3, header_tip to m2
        """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env, shard_id=0)

        m1 = state.get_tip().create_block_to_append(address=acc1)
        state.finalize_and_add_block(m1)

        m2 = state.get_tip().create_block_to_append(address=acc1)
        state.finalize_and_add_block(m2)

        r1 = state.root_tip.create_block_to_append()
        r2 = state.root_tip.create_block_to_append()
        r1.minor_block_header_list.append(m1.header)
        r1.finalize()

        state.add_root_block(r1)

        r2.minor_block_header_list.append(m1.header)
        r2.header.create_time = r1.header.create_time + 1  # make r2, r1 different
        r2.finalize()
        self.assertNotEqual(r1.header.get_hash(), r2.header.get_hash())

        state.add_root_block(r2)

        self.assertEqual(state.root_tip, r1.header)

        m3 = state.create_block_to_mine(address=acc1)
        self.assertEqual(m3.header.hash_prev_root_block, r1.header.get_hash())
        state.finalize_and_add_block(m3)

        r3 = r2.create_block_to_append(address=acc1)
        r3.add_minor_block_header(m2.header)
        r3.finalize()
        state.add_root_block(r3)
        self.assertEqual(state.root_tip, r3.header)
        self.assertEqual(state.header_tip, m2.header)
Exemple #22
0
 def setUp(self):
     super().setUp()
     config = get_test_env().quark_chain_config
     self.root_coinbase = config.ROOT.COINBASE_AMOUNT
     self.shard_coinbase = next(iter(config.shards.values())).COINBASE_AMOUNT
     # to make test verification easier, assume following tax rate
     assert config.REWARD_TAX_RATE == 0.5
     self.tax_rate = config.reward_tax_rate  # type: Fraction
     self.GENESIS_TOKEN = config.GENESIS_TOKEN  # type: str
     self.genesis_token = config.genesis_token  # type: int
    def test_blocks_with_incorrect_version(self):
        env = get_test_env()
        r_state, s_states = create_default_state(env)
        root_block = r_state.create_block_to_mine([])
        root_block.header.version = 1
        with self.assertRaisesRegexp(ValueError, "incorrect root block version"):
            r_state.add_block(root_block)

        root_block.header.version = 0
        r_state.add_block(root_block)
Exemple #24
0
    def test_add_root_block_with_minor_block_with_wrong_root_block_hash(self):
        """ Test for the following case
                 +--+    +--+
                 |r1|<---|r3|
                /+--+    +--+
               /   |      |
        +--+  /  +--+    +--+
        |r0|<----|m1|<---|m2|
        +--+  \  +--+    +--+
               \   |      |
                \+--+     |
                 |r2|<----+
                 +--+

        where r3 is invalid because m2 depends on r2, which is not in the r3 chain.
        """
        env = get_test_env(shard_size=1)
        r_state, s_states = create_default_state(env)
        s_state0 = s_states[1 | 0]
        genesis_header = s_state0.header_tip

        root_block0 = r_state.get_tip_block()

        m1 = s_state0.get_tip().create_block_to_append()
        add_minor_block_to_cluster(s_states, m1)

        r_state.add_validated_minor_block_hash(m1.header.get_hash())
        root_block1 = (root_block0.create_block_to_append(
            nonce=0).add_minor_block_header(
                genesis_header).add_minor_block_header(m1.header).finalize())
        root_block2 = (root_block0.create_block_to_append(
            nonce=1).add_minor_block_header(
                genesis_header).add_minor_block_header(m1.header).finalize())

        self.assertTrue(r_state.add_block(root_block1))
        self.assertFalse(r_state.add_block(root_block2))
        self.assertTrue(s_state0.add_root_block(root_block1))
        self.assertFalse(s_state0.add_root_block(root_block2))

        m2 = m1.create_block_to_append()
        m2.header.hash_prev_root_block = root_block2.header.get_hash()
        add_minor_block_to_cluster(s_states, m2)

        r_state.add_validated_minor_block_hash(m2.header.get_hash())
        root_block3 = (
            root_block1.create_block_to_append().add_minor_block_header(
                m2.header).finalize())

        with self.assertRaises(ValueError):
            r_state.add_block(root_block3)

        root_block4 = (
            root_block2.create_block_to_append().add_minor_block_header(
                m2.header).finalize())
        self.assertTrue(r_state.add_block(root_block4))
Exemple #25
0
    def test_root_chain_first_consensus(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        env0 = get_test_env(genesis_account=acc1,
                            genesis_minor_quarkash=10000000)
        env1 = get_test_env(genesis_account=acc1,
                            genesis_minor_quarkash=10000000)
        state0 = create_default_shard_state(env=env0, shard_id=0)
        state1 = create_default_shard_state(env=env1, shard_id=1)

        # Add one block and prepare a fork
        b0 = state0.get_tip().create_block_to_append(address=acc1)
        b2 = state0.get_tip().create_block_to_append(
            address=Address.create_empty_account())

        state0.finalize_and_add_block(b0)
        state0.finalize_and_add_block(b2)

        b1 = state1.get_tip().create_block_to_append()
        b1.finalize(evm_state=state1.run_block(b1))

        # Create a root block containing the block with the x-shard tx
        state0.add_cross_shard_tx_list_by_minor_block_hash(
            h=b1.header.get_hash(),
            tx_list=CrossShardTransactionList(tx_list=[]))
        root_block = (
            state0.root_tip.create_block_to_append().add_minor_block_header(
                b0.header).add_minor_block_header(b1.header).finalize())
        state0.add_root_block(root_block)

        b00 = b0.create_block_to_append()
        state0.finalize_and_add_block(b00)
        self.assertEqual(state0.header_tip, b00.header)

        # Create another fork that is much longer (however not confirmed by root_block)
        b3 = b2.create_block_to_append()
        state0.finalize_and_add_block(b3)
        b4 = b3.create_block_to_append()
        state0.finalize_and_add_block(b4)
        self.assertGreater(b4.header.height, b00.header.height)
        self.assertEqual(state0.header_tip, b00.header)
Exemple #26
0
    def test_not_update_tip_on_root_fork(self):
        """ block's hash_prev_root_block must be on the same chain with root_tip to update tip.

                 +--+
              a. |r1|
                /+--+
               /   |
        +--+  /  +--+    +--+
        |r0|<----|m1|<---|m2| c.
        +--+  \  +--+    +--+
               \   |      |
                \+--+     |
              b. |r2|<----+
                 +--+

        Initial state: r0 <- m1
        Then adding r1, r2, m2 should not make m2 the tip because r1 is the root tip and r2 and r1
        are not on the same root chain.
        """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env, shard_id=0)

        m1 = state.get_tip().create_block_to_append(address=acc1)
        state.finalize_and_add_block(m1)

        r1 = state.root_tip.create_block_to_append()
        r2 = state.root_tip.create_block_to_append()
        r1.minor_block_header_list.append(m1.header)
        r1.finalize()

        state.add_root_block(r1)

        r2.minor_block_header_list.append(m1.header)
        r2.header.create_time = r1.header.create_time + 1  # make r2, r1 different
        r2.finalize()
        self.assertNotEqual(r1.header.get_hash(), r2.header.get_hash())

        state.add_root_block(r2)

        self.assertEqual(state.root_tip, r1.header)

        m2 = m1.create_block_to_append(address=acc1)
        m2.header.hash_prev_root_block = r2.header.get_hash()

        state.finalize_and_add_block(m2)
        # m2 is added
        self.assertEqual(
            state.db.get_minor_block_by_hash(m2.header.get_hash()), m2)
        # but m1 should still be the tip
        self.assertEqual(state.header_tip, m1.header)
Exemple #27
0
    def test_duplicated_tx(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=0)
        acc3 = Address.create_random_account(full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
        )
        self.assertTrue(state.add_tx(tx))
        self.assertFalse(state.add_tx(tx))  # already in tx_queue

        self.assertEqual(len(state.tx_queue), 1)
        self.assertEqual(len(state.tx_dict), 1)

        block, i = state.get_transaction_by_hash(tx.get_hash())
        self.assertEqual(len(block.tx_list), 1)
        self.assertEqual(block.tx_list[0], tx)
        self.assertEqual(block.header.create_time, 0)
        self.assertEqual(i, 0)

        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)

        # Should succeed
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(state.get_balance(id1.recipient),
                         10000000 - opcodes.GTXCOST - 12345)
        self.assertEqual(state.get_balance(acc2.recipient), 12345)
        self.assertEqual(state.get_balance(acc3.recipient),
                         opcodes.GTXCOST // 2)

        # Check receipts
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, 21000)
        block, i = state.get_transaction_by_hash(tx.get_hash())
        self.assertEqual(block, b1)
        self.assertEqual(i, 0)

        # tx already confirmed
        self.assertTrue(state.db.contain_transaction_hash(tx.get_hash()))
        self.assertFalse(state.add_tx(tx))
    def test_native_token_transfer(self):
        """in-shard transfer QETH using genesis_token as gas
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 10000000,
                "QETH": 99999
            },
        )
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=self.genesis_token,
            transfer_token_id=QETH,
        )
        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            10000000 - opcodes.GTXCOST,
        )
        self.assertEqual(state.get_token_balance(acc1.recipient, QETH),
                         99999 - 12345)
        self.assertEqual(state.get_token_balance(acc2.recipient, QETH), 12345)
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.getAfterTaxReward(opcodes.GTXCOST + self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
Exemple #29
0
    def test_native_token_gas(self):
        """in-shard transfer QETH using native token as gas
        """
        qeth = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        # Miner
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={"QETH": 10000000},
            charge_gas_reserve=True,
        )
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=qeth,
            transfer_token_id=qeth,
        )

        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(
            state.get_token_balance(acc1.recipient, qeth),
            10000000 - opcodes.GTXCOST - 12345,
        )
        self.assertEqual(state.get_token_balance(acc2.recipient, qeth), 12345)
        # after-tax coinbase + tx fee should only be in QKC
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.get_after_tax_reward(self.shard_coinbase + opcodes.GTXCOST),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, qeth)
        self.assertEqual(tx_list[0].transfer_token_id, qeth)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, qeth)
        self.assertEqual(tx_list[0].transfer_token_id, qeth)
Exemple #30
0
    def setUp(self):
        super().setUp()
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=10000000)
        state = create_default_shard_state(env=env)
        tx = create_contract_creation_with_event_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_full_shard_id=acc1.full_shard_id,
        )
        self.assertTrue(state.add_tx(tx))
        b = state.create_block_to_mine(address=acc1, gas_limit=1000000)
        hit_block = b  # will be used later
        state.finalize_and_add_block(b)
        start_height = b.header.height
        # https://hastebin.com/debezaqocu.cs
        # 1 log with 2 topics - sha3(b'Hi(address)') and msg.sender
        log = Log.create_from_eth_log(state.evm_state.receipts[0].logs[0], b,
                                      0, 0)

        # add other random blocks with normal tx
        for _ in range(10):
            tx = create_transfer_transaction(
                shard_state=state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=Address.create_from_identity(
                    Identity.create_random_identity(), full_shard_id=0),
                value=1,
                gas=40000,
            )
            self.assertTrue(state.add_tx(tx))
            b = state.create_block_to_mine(address=acc1, gas_limit=100000)
            state.finalize_and_add_block(b)
        self.assertEqual(b.header.height, start_height + 10)

        self.hit_block = hit_block
        self.log = log
        self.state = state
        self.start_height = start_height

        def filter_gen_with_criteria(criteria, addresses=None):
            return Filter(state.db, addresses or [], criteria, start_height,
                          start_height + 10)

        self.filter_gen_with_criteria = filter_gen_with_criteria