예제 #1
0
    def test_create_shard_at_different_height(self):
        acc1 = Address.create_random_account()
        id1 = 0 << 16 | 1 | 0
        id2 = 1 << 16 | 1 | 0
        genesis_root_heights = {id1: 1, id2: 2}
        with ClusterContext(
                1,
                acc1,
                chain_size=2,
                shard_size=1,
                genesis_root_heights=genesis_root_heights,
        ) as clusters:
            master = clusters[0].master

            self.assertIsNone(clusters[0].get_shard(id1))
            self.assertIsNone(clusters[0].get_shard(id2))

            root = call_async(
                master.get_next_block_to_mine(acc1, branch_value=None))
            self.assertEqual(len(root.minor_block_header_list), 0)
            call_async(master.add_root_block(root))

            # shard 0 created at root height 1
            self.assertIsNotNone(clusters[0].get_shard(id1))
            self.assertIsNone(clusters[0].get_shard(id2))

            root = call_async(
                master.get_next_block_to_mine(acc1, branch_value=None))
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))

            self.assertIsNotNone(clusters[0].get_shard(id1))
            # shard 1 created at root height 2
            self.assertIsNotNone(clusters[0].get_shard(id2))

            block = call_async(
                master.get_next_block_to_mine(acc1, branch_value=None))
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))
예제 #2
0
    def update(
        self,
        chain_size,
        shard_size_per_chain,
        root_block_time,
        minor_block_time,
        default_token,
    ):
        self.CHAIN_SIZE = chain_size

        self.ROOT = RootConfig()
        self.ROOT.CONSENSUS_TYPE = ConsensusType.POW_SIMULATE
        self.ROOT.CONSENSUS_CONFIG = POWConfig()
        self.ROOT.CONSENSUS_CONFIG.TARGET_BLOCK_TIME = root_block_time
        self.GENESIS_TOKEN = default_token

        self.CHAINS = []
        self.shards = dict()
        for chain_id in range(chain_size):
            chain_config = ChainConfig()
            chain_config.CHAIN_ID = chain_id
            chain_config.SHARD_SIZE = shard_size_per_chain
            chain_config.CONSENSUS_TYPE = ConsensusType.POW_SIMULATE
            chain_config.CONSENSUS_CONFIG = POWConfig()
            chain_config.CONSENSUS_CONFIG.TARGET_BLOCK_TIME = minor_block_time
            chain_config.DEFAULT_CHAIN_TOKEN = default_token
            self.CHAINS.append(chain_config)
            for shard_id in range(shard_size_per_chain):
                shard_config = ShardConfig(chain_config)
                shard_config.root_config = self.ROOT
                shard_config.SHARD_ID = shard_id
                shard_config.COINBASE_ADDRESS = (
                    Address.create_from(shard_config.COINBASE_ADDRESS)
                    .address_in_shard(shard_config.get_full_shard_id())
                    .serialize()
                    .hex()
                )
                self.shards[shard_config.get_full_shard_id()] = shard_config
        self.init_and_validate()
예제 #3
0
    def test_getTransactionReceipt_on_contract_creation(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            to_full_shard_key = acc1.full_shard_key + 2
            tx = create_contract_creation_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=to_full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(endpoint,
                                    "0x" + tx.get_hash().hex() + "00000002")
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], "0x213eb")

                contract_address = mk_contract_address(acc1.recipient,
                                                       to_full_shard_key, 0)
                self.assertEqual(
                    resp["contractAddress"],
                    "0x" + contract_address.hex() +
                    to_full_shard_key.to_bytes(4, "big").hex(),
                )
예제 #4
0
    def test_fork_resolve(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()
        b1 = state.get_tip().create_block_to_append()

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

        # Fork happens, first come first serve
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b0.header)

        # Longer fork happens, override existing one
        b2 = b1.create_block_to_append()
        state.finalize_and_add_block(b2)
        self.assertEqual(state.header_tip, b2.header)
예제 #5
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
            b1 = shard_state.get_tip().create_block_to_append()
            b1.finalize(evm_state=shard_state.run_block(b1))
            addResult = call_async(
                clusters[0].master.add_raw_minor_block(b1.header.branch, b1.serialize())
            )
            self.assertTrue(addResult)

            # 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()
                )
            )
예제 #6
0
    def test_gasPrice(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            # run for multiple times
            for _ in range(3):
                tx = create_transfer_transaction(
                    shard_state=clusters[0].get_shard_state(2 | 0),
                    key=id1.get_key(),
                    from_address=acc1,
                    to_address=acc1,
                    value=0,
                    gas_price=12,
                )
                self.assertTrue(slaves[0].add_tx(tx))

                block = call_async(
                    master.get_next_block_to_mine(address=acc1,
                                                  branch_value=0b10))
                self.assertTrue(
                    call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    resp = send_request("eth_gasPrice", ["0x0"])
                else:
                    resp = send_request(
                        "gasPrice",
                        ["0x0",
                         quantity_encoder(token_id_encode("QKC"))])

                self.assertEqual(resp, "0xc")
예제 #7
0
    def __init_miner(self):
        miner_address = Address.create_from(
            self.env.quark_chain_config.SHARD_LIST[
                self.shard_id].COINBASE_ADDRESS)

        async def __create_block(retry=True):
            # hold off mining if the shard is syncing
            while self.synchronizer.running or not self.state.initialized:
                if not retry:
                    break
                await asyncio.sleep(0.1)

            return self.state.create_block_to_mine(address=miner_address)

        async def __add_block(block):
            # Do not add block if there is a sync in progress
            if self.synchronizer.running:
                return
            # Do not add stale block
            if self.state.header_tip.height >= block.header.height:
                return
            await self.handle_new_block(block)

        def __get_mining_param():
            return {
                "target_block_time":
                self.slave.artificial_tx_config.target_minor_block_time
            }

        shard_config = self.env.quark_chain_config.SHARD_LIST[
            self.shard_id]  # type: ShardConfig
        self.miner = Miner(
            shard_config.CONSENSUS_TYPE,
            __create_block,
            __add_block,
            __get_mining_param,
            remote=shard_config.CONSENSUS_CONFIG.REMOTE_MINE,
        )
예제 #8
0
    def test_getTransactionReceipt_on_transfer(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    [
                        "0x" + tx.get_hash().hex() +
                        acc1.full_shard_key.to_bytes(4, "big").hex()
                    ],
                )
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], "0x5208")
                self.assertIsNone(resp["contractAddress"])
예제 #9
0
 def from_dict(cls, d):
     config = super().from_dict(d)
     config.ROOT = RootConfig.from_dict(config.ROOT)
     chains = []
     shards = dict()
     for s in config.CHAINS:
         chain_config = ChainConfig.from_dict(s)
         chains.append(chain_config)
         for shard_id in range(chain_config.SHARD_SIZE):
             shard_config = ShardConfig(chain_config)
             shard_config.root_config = config.ROOT
             shard_config.SHARD_ID = shard_id
             shard_config.COINBASE_ADDRESS = (
                 Address.create_from(shard_config.COINBASE_ADDRESS)
                 .address_in_shard(shard_config.get_full_shard_id())
                 .serialize()
                 .hex()
             )
             shards[shard_config.get_full_shard_id()] = shard_config
     config.CHAINS = chains
     config.shards = shards
     config.init_and_validate()
     return config
예제 #10
0
    def create_block_to_mine(self, m_header_list, address=None, create_time=None):
        if not address:
            address = Address.create_empty_account()
        if create_time is None:
            create_time = max(self.tip.create_time + 1, int(time.time()))
        tracking_data = {
            "inception": time_ms(),
            "cluster": self.env.cluster_config.MONITORING.CLUSTER_ID,
        }

        difficulty = self.diff_calc.calculate_diff_with_parent(self.tip, create_time)
        block = self.tip.create_block_to_append(
            create_time=create_time, address=address, difficulty=difficulty
        )
        block.minor_block_header_list = m_header_list

        coinbase_tokens = self._calculate_root_block_coinbase(
            [header.get_hash() for header in m_header_list], block.header.height
        )

        tracking_data["creation_ms"] = time_ms() - tracking_data["inception"]
        block.tracking_data = json.dumps(tracking_data).encode("utf-8")
        return block.finalize(coinbase_tokens=coinbase_tokens, coinbase_address=address)
예제 #11
0
    def test_getCode(self):
        key = bytes.fromhex(
            "c987d4506fb6824639f9a9e3b8834584f5165e94680501d1b0044071cd36c3b3")
        id1 = Identity.create_from_key(key)
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        created_addr = "0x8531eb33bba796115f56ffa1b7df1ea3acdd8cdd00000000"

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            tx = create_contract_with_storage_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=acc1.full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    resp = send_request("eth_getCode",
                                        [created_addr[:-8], "0x0"])
                else:
                    resp = send_request("getCode", [created_addr])

                self.assertEqual(
                    resp,
                    "0x6080604052600080fd00a165627a7a72305820a6ef942c101f06333ac35072a8ff40332c71d0e11cd0e6d86de8cae7b42696550029",
                )
예제 #12
0
    def test_tx_size(self):
        id1 = Identity.create_from_key(b"0" * 32)
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        evm_tx = EvmTransaction(
            nonce=0,
            gasprice=1,
            startgas=30000,
            to=acc1.recipient,
            value=0,
            data=b"",
            from_full_shard_key=0xFFFF,
            to_full_shard_key=0xFFFF,
            network_id=1,
            gas_token_id=12345,
            transfer_token_id=1234,
        )
        evm_tx.sign(key=id1.get_key())
        tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
        self.assertEqual(len(tx.serialize()), TX_MIN_SIZE)

        evm_tx = EvmTransaction(
            nonce=TT256 - 1,
            gasprice=TT256 - 1,
            startgas=TT256 - 1,
            to=acc1.recipient,
            value=TT256 - 1,
            data=b"",
            from_full_shard_key=SHARD_KEY_MAX,
            to_full_shard_key=SHARD_KEY_MAX,
            network_id=1,
            gas_token_id=TOKEN_ID_MAX,
            transfer_token_id=TOKEN_ID_MAX,
        )
        evm_tx.sign(key=id1.get_key())
        tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
        self.assertEqual(len(tx.serialize()), TX_MAX_SIZE)
예제 #13
0
 async def handle_mined_block():
     while True:
         res = await self.output_q.coro_get()  # type: MiningResult
         if not res:
             return  # empty result means ending
         # start mining before processing and propagating mined block
         self._mine_new_block_async()
         block = self.work_map[res.header_hash]
         block.header.nonce = res.nonce
         block.header.mixhash = res.mixhash
         del self.work_map[res.header_hash]
         self._track(block)
         try:
             # FIXME: Root block should include latest minor block headers while it's being mined
             # This is a hack to get the latest minor block included since testnet does not check difficulty
             if self.consensus_type == ConsensusType.POW_SIMULATE:
                 block = await self.create_block_async_func(
                     Address.create_empty_account())
                 block.header.nonce = random.randint(0, 2**32 - 1)
                 self._track(block)
                 self._log_status(block)
             await self.add_block_async_func(block)
         except Exception:
             Logger.error_exception()
예제 #14
0
    def test_disallowed_unknown_token(self):
        """do not allow tx with unknown token id
        """
        MALICIOUS0 = token_id_encode("MALICIOUS0")
        MALICIOUS1 = token_id_encode("MALICIOUS1")
        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},
        )
        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))

        tx1 = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=MALICIOUS1,
            transfer_token_id=self.genesis_token,
        )
        self.assertFalse(state.add_tx(tx1))
예제 #15
0
    def test_getTransactionReceipt_on_contract_creation_failure(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            # Add a root block to update block gas limit for xshard tx throttling
            # so that the following tx can be processed
            is_root, root_block = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            call_async(master.add_root_block(root_block))

            to_full_shard_key = (
                acc1.full_shard_key + 1
            )  # x-shard contract creation should fail
            tx = create_contract_creation_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=to_full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"):
                resp = send_request(endpoint, "0x" + tx.get_hash().hex() + "00000002")
                self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x0")
                self.assertEqual(resp["cumulativeGasUsed"], "0x13d6c")
                self.assertIsNone(resp["contractAddress"])
예제 #16
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()))
예제 #17
0
    def test_call_success(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

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

            branch = Branch.create(2, 0)
            response = send_request(
                "call",
                {
                    "to": "0x" + acc1.serialize().hex(),
                    "gas": hex(21000)
                },
                "latest",
            )

            self.assertEqual(response, "0x")
            self.assertEqual(
                len(slaves[0].shards[branch].state.tx_queue),
                0,
                "should not affect tx queue",
            )
예제 #18
0
    def __init__(
        self,
        num_cluster,
        genesis_account=Address.create_empty_account(),
        chain_size=2,
        shard_size=2,
        num_slaves=None,
        genesis_root_heights=None,
        remote_mining=False,
        small_coinbase=False,
        loadtest_accounts=None,
    ):
        self.num_cluster = num_cluster
        self.genesis_account = genesis_account
        self.chain_size = chain_size
        self.shard_size = shard_size
        self.num_slaves = num_slaves if num_slaves else chain_size
        self.genesis_root_heights = genesis_root_heights
        self.remote_mining = remote_mining
        self.small_coinbase = small_coinbase
        self.loadtest_accounts = loadtest_accounts

        check(is_p2(self.num_slaves))
        check(is_p2(self.shard_size))
예제 #19
0
    def test_getTransactionById(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)
            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            resp = send_request(
                "getTransactionById",
                [
                    "0x" + tx.get_hash().hex() +
                    acc1.full_shard_key.to_bytes(4, "big").hex()
                ],
            )
            self.assertEqual(resp["hash"], "0x" + tx.get_hash().hex())
예제 #20
0
 async def getStorageAt(self, address, key, block_height=None):
     res = await self.master.get_storage_at(Address.deserialize(address),
                                            key, block_height)
     return data_encoder(res) if res is not None else None
예제 #21
0
def get_test_env(
    genesis_account=Address.create_empty_account(),
    genesis_minor_quarkash=0,
    chain_size=2,
    shard_size=2,
    genesis_root_heights=None,  # dict(full_shard_id, genesis_root_height)
    remote_mining=False,
    genesis_minor_token_balances=None,
    charge_gas_reserve=False,
):
    check(is_p2(shard_size))
    env = DEFAULT_ENV.copy()

    env.db = InMemoryDb()
    env.set_network_id(1234567890)

    env.cluster_config = ClusterConfig()
    env.quark_chain_config.update(
        chain_size, shard_size, 10, 1, env.quark_chain_config.GENESIS_TOKEN
    )
    env.quark_chain_config.MIN_TX_POOL_GAS_PRICE = 0
    env.quark_chain_config.MIN_MINING_GAS_PRICE = 0

    if remote_mining:
        env.quark_chain_config.ROOT.CONSENSUS_CONFIG.REMOTE_MINE = True
        env.quark_chain_config.ROOT.CONSENSUS_TYPE = ConsensusType.POW_DOUBLESHA256
        env.quark_chain_config.ROOT.GENESIS.DIFFICULTY = 10

    env.quark_chain_config.ROOT.DIFFICULTY_ADJUSTMENT_CUTOFF_TIME = 40
    env.quark_chain_config.ROOT.DIFFICULTY_ADJUSTMENT_FACTOR = 1024

    if genesis_root_heights:
        check(len(genesis_root_heights) == shard_size * chain_size)
        for chain_id in range(chain_size):
            for shard_id in range(shard_size):
                full_shard_id = chain_id << 16 | shard_size | shard_id
                shard = env.quark_chain_config.shards[full_shard_id]
                shard.GENESIS.ROOT_HEIGHT = genesis_root_heights[full_shard_id]

    # fund genesis account in all shards
    for full_shard_id, shard in env.quark_chain_config.shards.items():
        addr = genesis_account.address_in_shard(full_shard_id).serialize().hex()
        if genesis_minor_token_balances is not None:
            shard.GENESIS.ALLOC[addr] = genesis_minor_token_balances
        else:
            shard.GENESIS.ALLOC[addr] = {
                env.quark_chain_config.GENESIS_TOKEN: genesis_minor_quarkash
            }
        if charge_gas_reserve:
            gas_reserve_addr = (
                SystemContract.GENERAL_NATIVE_TOKEN.addr().hex() + addr[-8:]
            )
            shard.GENESIS.ALLOC[gas_reserve_addr] = {
                env.quark_chain_config.GENESIS_TOKEN: int(1e18)
            }
        shard.CONSENSUS_CONFIG.REMOTE_MINE = remote_mining
        shard.DIFFICULTY_ADJUSTMENT_CUTOFF_TIME = 7
        shard.DIFFICULTY_ADJUSTMENT_FACTOR = 512
        if remote_mining:
            shard.CONSENSUS_TYPE = ConsensusType.POW_DOUBLESHA256
            shard.GENESIS.DIFFICULTY = 10
        shard.POSW_CONFIG.WINDOW_SIZE = 2

    env.quark_chain_config.SKIP_MINOR_DIFFICULTY_CHECK = True
    env.quark_chain_config.SKIP_ROOT_DIFFICULTY_CHECK = True
    env.cluster_config.ENABLE_TRANSACTION_HISTORY = True
    env.cluster_config.DB_PATH_ROOT = ""

    check(env.cluster_config.use_mem_db())

    return env
예제 #22
0
    def test_getLogs(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        expected_log_parts = {
            "logIndex": "0x0",
            "transactionIndex": "0x0",
            "blockNumber": "0x1",
            "blockHeight": "0x1",
            "data": "0x",
        }

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            tx = create_contract_creation_with_event_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=acc1.full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                shard_id = hex(acc1.full_shard_key)
                if using_eth_endpoint:
                    req = lambda o: send_request("eth_getLogs", [o, shard_id])
                else:
                    # `None` needed to bypass some request modification
                    req = lambda o: send_request("getLogs", [o, shard_id])

                # no filter object as wild cards
                resp = req({})
                self.assertEqual(1, len(resp))
                self.assertDictContainsSubset(expected_log_parts, resp[0])

                # filter by contract address
                contract_addr = mk_contract_address(acc1.recipient, 0,
                                                    acc1.full_shard_key)
                filter_obj = {
                    "address":
                    "0x" + contract_addr.hex() +
                    ("" if using_eth_endpoint else hex(
                        acc1.full_shard_key)[2:].zfill(8))
                }
                resp = req(filter_obj)
                self.assertEqual(1, len(resp))

                # filter by topics
                filter_obj = {
                    "topics": [
                        "0xa9378d5bd800fae4d5b8d4c6712b2b64e8ecc86fdc831cb51944000fc7c8ecfa"
                    ]
                }
                filter_obj_nested = {
                    "topics": [[
                        "0xa9378d5bd800fae4d5b8d4c6712b2b64e8ecc86fdc831cb51944000fc7c8ecfa"
                    ]]
                }
                for f in (filter_obj, filter_obj_nested):
                    resp = req(f)
                    self.assertEqual(1, len(resp))
                    self.assertDictContainsSubset(expected_log_parts, resp[0])
                    self.assertEqual(
                        "0xa9378d5bd800fae4d5b8d4c6712b2b64e8ecc86fdc831cb51944000fc7c8ecfa",
                        resp[0]["topics"][0],
                    )
예제 #23
0
    def test_getTransactionReceipt_on_x_shard_transfer(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(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            block = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=None))
            call_async(master.add_root_block(block))

            s1, s2 = (
                clusters[0].get_shard_state(2 | 0),
                clusters[0].get_shard_state(2 | 1),
            )
            tx_gen = lambda s, f, t: create_transfer_transaction(
                shard_state=s,
                key=id1.get_key(),
                from_address=f,
                to_address=t,
                gas=21000 if f == t else 30000,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx_gen(s1, acc1, acc2)))
            b1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(b1)))

            root_block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=None))

            call_async(master.add_root_block(root_block))

            tx = tx_gen(s2, acc2, acc2)
            self.assertTrue(slaves[0].add_tx(tx))
            b3 = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=0b11))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 1).add_block(b3)))

            # in-shard tx 21000 + receiving x-shard tx 9000
            self.assertEqual(s2.evm_state.gas_used, 30000)
            self.assertEqual(s2.evm_state.xshard_receive_gas_used, 9000)

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    [
                        "0x" + tx.get_hash().hex() +
                        acc2.full_shard_key.to_bytes(4, "big").hex()
                    ],
                )
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], hex(30000))
                self.assertEqual(resp["gasUsed"], hex(21000))
                self.assertIsNone(resp["contractAddress"])
예제 #24
0
 async def getTransactionCount(self, address, block_height=None):
     account_branch_data = await self.master.get_primary_account_data(
         Address.deserialize(address), block_height)
     return account_branch_data.transaction_count
예제 #25
0
    def test_getRootblockConfirmationIdAndCount(self):
        # TODO test root chain forks
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)

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

            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            tx_id = ("0x" + tx.get_hash().hex() +
                     acc1.full_shard_key.to_bytes(4, "big").hex())
            resp = send_request("getTransactionById", [tx_id])
            self.assertEqual(resp["hash"], "0x" + tx.get_hash().hex())
            self.assertEqual(
                resp["blockId"],
                "0x" + block1.header.get_hash().hex() +
                block1.header.branch.get_full_shard_id().to_bytes(
                    4, byteorder="big").hex(),
            )
            minor_hash = resp["blockId"]

            # zero root block confirmation
            resp_hash = send_request("getRootHashConfirmingMinorBlockById",
                                     [minor_hash])
            self.assertIsNone(
                resp_hash, "should return None for unconfirmed minor blocks")
            resp_count = send_request(
                "getTransactionConfirmedByNumberRootBlocks", [tx_id])
            self.assertEqual(resp_count, "0x0")

            # 1 root block confirmation
            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=None))
            call_async(master.add_root_block(block))
            resp_hash = send_request("getRootHashConfirmingMinorBlockById",
                                     [minor_hash])
            self.assertIsNotNone(resp_hash, "confirmed by root block")
            self.assertEqual(resp_hash, "0x" + block.header.get_hash().hex())
            resp_count = send_request(
                "getTransactionConfirmedByNumberRootBlocks", [tx_id])
            self.assertEqual(resp_count, "0x1")

            # 2 root block confirmation
            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=None))
            call_async(master.add_root_block(block))
            resp_hash = send_request("getRootHashConfirmingMinorBlockById",
                                     [minor_hash])
            self.assertIsNotNone(resp_hash, "confirmed by root block")
            self.assertNotEqual(resp_hash,
                                "0x" + block.header.get_hash().hex())
            resp_count = send_request(
                "getTransactionConfirmedByNumberRootBlocks", [tx_id])
            self.assertEqual(resp_count, "0x2")
예제 #26
0
    def test_getMinorBlock(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)
            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            # By id
            for need_extra_info in [True, False]:
                resp = send_request(
                    "getMinorBlockById",
                    [
                        "0x" + block1.header.get_hash().hex() + "0" * 8,
                        False,
                        need_extra_info,
                    ],
                )
                self.assertEqual(resp["transactions"][0],
                                 "0x" + tx.get_hash().hex() + "00000002")

            resp = send_request(
                "getMinorBlockById",
                ["0x" + block1.header.get_hash().hex() + "0" * 8, True],
            )
            self.assertEqual(resp["transactions"][0]["hash"],
                             "0x" + tx.get_hash().hex())

            resp = send_request("getMinorBlockById", ["0x" + "ff" * 36, True])
            self.assertIsNone(resp)

            # By height
            for need_extra_info in [True, False]:
                resp = send_request("getMinorBlockByHeight",
                                    ["0x0", "0x1", False, need_extra_info])
                self.assertEqual(resp["transactions"][0],
                                 "0x" + tx.get_hash().hex() + "00000002")

            resp = send_request("getMinorBlockByHeight", ["0x0", "0x1", True])
            self.assertEqual(resp["transactions"][0]["hash"],
                             "0x" + tx.get_hash().hex())

            resp = send_request("getMinorBlockByHeight", ["0x1", "0x2", False])
            self.assertIsNone(resp)
            resp = send_request("getMinorBlockByHeight", ["0x0", "0x4", False])
            self.assertIsNone(resp)
예제 #27
0
 async def eth_getCode(self, address, shard=None):
     addr = Address.deserialize(address)
     if shard is not None:
         addr = Address(addr.recipient, shard)
     res = await self.master.get_code(addr, None)
     return data_encoder(res) if res is not None else None
예제 #28
0
 async def getCode(self, address, block_height=None):
     res = await self.master.get_code(Address.deserialize(address),
                                      block_height)
     return data_encoder(res) if res is not None else None
예제 #29
0
 def testnet_master_address(self):
     return Address.create_from(self.TESTNET_MASTER_ADDRESS)
예제 #30
0
 def miner_address(self):
     return Address.create_from(self.MINER_ADDRESS)