示例#1
0
    def __get_branch_to_add_xshard_tx_list_request(self, block_hash,
                                                   xshard_tx_list,
                                                   prev_root_height):
        xshard_map = dict(
        )  # type: Dict[Branch, List[CrossShardTransactionDeposit]]

        # only broadcast to the shards that have been initialized
        initialized_shard_ids = self.env.quark_chain_config.get_initialized_shard_ids_before_root_height(
            prev_root_height)
        for shard_id in initialized_shard_ids:
            branch = Branch.create(self.__get_shard_size(), shard_id)
            xshard_map[branch] = []

        for xshard_tx in xshard_tx_list:
            shard_id = xshard_tx.to_address.get_shard_id(
                self.__get_shard_size())
            branch = Branch.create(self.__get_shard_size(), shard_id)
            check(branch in xshard_map)
            xshard_map[branch].append(xshard_tx)

        branch_to_add_xshard_tx_list_request = (
            dict())  # type: Dict[Branch, AddXshardTxListRequest]
        for branch, tx_list in xshard_map.items():
            cross_shard_tx_list = CrossShardTransactionList(tx_list)

            request = AddXshardTxListRequest(branch, block_hash,
                                             cross_shard_tx_list)
            branch_to_add_xshard_tx_list_request[branch] = request

        return branch_to_add_xshard_tx_list_request
示例#2
0
    def test_getTransactionReceipt_on_transfer(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):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                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))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    "0x" + tx.get_hash().hex() +
                    acc1.full_shard_id.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"])
示例#3
0
    def test_get_primary_account_data(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=1)

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

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 0
            )
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            is_root, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(
                    master.add_raw_minor_block(block1.header.branch, block1.serialize())
                )
            )

            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 1
            )
            self.assertEqual(
                call_async(master.get_primary_account_data(acc2)).transaction_count, 0
            )
示例#4
0
    def test_getTransactionById(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):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                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))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            resp = send_request(
                "getTransactionById",
                "0x" + tx.get_hash().hex() +
                acc1.full_shard_id.to_bytes(4, "big").hex(),
            )
            self.assertEqual(resp["hash"], "0x" + tx.get_hash().hex())
示例#5
0
    async def eth_getBlockByNumber(self, block_height, include_transactions):
        """
        NOTE: only support block_id "latest" or hex
        """

        def block_transcoder(block):
            """
            QuarkChain Block => ETH Block
            """
            return {
                **block,
                "number": block["height"],
                "parentHash": block["hashPrevMinorBlock"],
                "sha3Uncles": "",
                "logsBloom": "",
                "transactionsRoot": block["hashMerkleRoot"],  # ?
                "stateRoot": block["hashEvmStateRoot"],  # ?
            }

        block = await self.master.get_minor_block_by_height(
            block_height, Branch.create(self.master.get_shard_size(), 0)
        )
        if block is None:
            return None
        return block_transcoder(minor_block_encoder(block))
示例#6
0
 def get_shard(self, shard_id) -> Shard:
     branch = Branch.create(self.master.env.quark_chain_config.SHARD_SIZE,
                            shard_id)
     for slave in self.slave_list:
         if branch in slave.shards:
             return slave.shards[branch]
     return None
示例#7
0
    def __init_miner(self):
        miner_address = self.env.quark_chain_config.testnet_master_address.address_in_branch(
            Branch.create(self.__get_shard_size(), self.shard_id))

        async def __create_block():
            # hold off mining if the shard is syncing
            while self.synchronizer.running or not self.state.initialized:
                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
 async def _get_logs(self, data, shard, decoder: Callable[[str], bytes]):
     start_block = data.get("fromBlock", "latest")
     end_block = data.get("toBlock", "latest")
     # TODO: not supported yet for "earliest" or "pending" block
     if (isinstance(start_block, str)
             and start_block != "latest") or (isinstance(end_block, str)
                                              and end_block != "latest"):
         return None
     # parse addresses / topics
     addresses, topics = [], []
     if "address" in data:
         if isinstance(data["address"], str):
             addresses = [Address.deserialize(decoder(data["address"]))]
         elif isinstance(data["address"], list):
             addresses = [
                 Address.deserialize(decoder(a)) for a in data["address"]
             ]
     if shard is not None:
         addresses = [Address(a.recipient, shard) for a in addresses]
     if "topics" in data:
         for topic_item in data["topics"]:
             if isinstance(topic_item, str):
                 topics.append([data_decoder(topic_item)])
             elif isinstance(topic_item, list):
                 topics.append([data_decoder(tp) for tp in topic_item])
     branch = Branch.create(self.master.get_shard_size(), shard)
     logs = await self.master.get_logs(addresses, topics, start_block,
                                       end_block, branch)
     if logs is None:
         return None
     return loglist_encoder(logs)
示例#9
0
 def get_balance(self, address):
     branch = Branch.create(self.__get_shard_size(),
                            address.get_shard_id(self.__get_shard_size()))
     shard = self.shards.get(branch, None)
     if not shard:
         return None
     return shard.state.get_balance(address.recipient)
示例#10
0
    def test_sendTransaction_with_bad_signature(self):
        """ sendTransaction validates signature """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=1)

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

            branch = Branch.create(2, 0)
            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",
                v="0x1",
                r="0x2",
                s="0x3",
                nonce="0x0",
                fromFullShardId="0x00000000",
                toFullShardId="0x00000001",
            )
            self.assertIsNone(send_request("sendTransaction", request))
            self.assertEqual(len(slaves[0].shards[branch].state.tx_queue), 0)
示例#11
0
    def test_gasPrice(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):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            # run for multiple times
            for _ in range(3):
                tx = create_transfer_transaction(
                    shard_state=slaves[0].shards[branch].state,
                    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))
                self.assertTrue(
                    call_async(clusters[0].get_shard(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")

                self.assertEqual(resp, "0xc")
示例#12
0
    def test_getMinorBlock(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=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

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                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))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            # By id
            resp = send_request(
                "getMinorBlockById",
                "0x" + block1.header.get_hash().hex() + "0" * 8,
                False,
            )
            self.assertEqual(resp["transactions"][0],
                             "0x" + tx.get_hash().hex() + "0" * 8)
            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
            resp = send_request("getMinorBlockByHeight", "0x0", "0x1", False)
            self.assertEqual(resp["transactions"][0],
                             "0x" + tx.get_hash().hex() + "0" * 8)
            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)
示例#13
0
 def add_tx(self, tx: Transaction) -> bool:
     evm_tx = tx.code.get_evm_transaction()
     evm_tx.set_shard_size(self.__get_shard_size())
     branch = Branch.create(self.__get_shard_size(), evm_tx.from_shard_id())
     shard = self.shards.get(branch, None)
     if not shard:
         return False
     return shard.add_tx(tx)
示例#14
0
 async def getMinorBlockById(self, block_id, include_transactions=False):
     block_hash, full_shard_id = block_id
     shard_size = self.master.get_shard_size()
     branch = Branch.create(shard_size, (shard_size - 1) & full_shard_id)
     block = await self.master.get_minor_block_by_hash(block_hash, branch)
     if not block:
         return None
     return minor_block_encoder(block, include_transactions)
示例#15
0
 def estimate_gas(self, tx, from_address) -> Optional[int]:
     evm_tx = tx.code.get_evm_transaction()
     evm_tx.set_shard_size(self.__get_shard_size())
     branch = Branch.create(self.__get_shard_size(), evm_tx.from_shard_id())
     shard = self.shards.get(branch, None)
     if not shard:
         return None
     return shard.state.estimate_gas(tx, from_address)
示例#16
0
 def get_transaction_list_by_address(self, address, start, limit):
     branch = Branch.create(self.__get_shard_size(),
                            address.get_shard_id(self.__get_shard_size()))
     shard = self.shards.get(branch, None)
     if not shard:
         return None
     return shard.state.get_transaction_list_by_address(
         address, start, limit)
示例#17
0
    def test_getStorageAt(self):
        key = bytes.fromhex(
            "c987d4506fb6824639f9a9e3b8834584f5165e94680501d1b0044071cd36c3b3")
        id1 = Identity.create_from_key(key)
        acc1 = Address.create_from_identity(id1, full_shard_id=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

            branch = Branch.create(2, 0)
            tx = create_contract_with_storage_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_id=acc1.full_shard_id,
            )
            self.assertTrue(slaves[0].add_tx(tx))

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

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    req = lambda k: send_request("eth_getStorageAt",
                                                 created_addr[:-8], k, "0x0")
                else:
                    req = lambda k: send_request("getStorageAt", created_addr,
                                                 k)

                # first storage
                response = req("0x0")
                # equals 1234
                self.assertEqual(
                    response,
                    "0x00000000000000000000000000000000000000000000000000000000000004d2",
                )

                # mapping storage
                k = sha3_256(
                    bytes.fromhex(acc1.recipient.hex().zfill(64) +
                                  "1".zfill(64)))
                response = req("0x" + k.hex())
                self.assertEqual(
                    response,
                    "0x000000000000000000000000000000000000000000000000000000000000162e",
                )

                # doesn't exist
                response = req("0x3")
                self.assertEqual(
                    response,
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                )
示例#18
0
 def get_code(self, address: Address,
              block_height: Optional[int]) -> Optional[bytes]:
     shard_size = self.__get_shard_size()
     shard_id = address.get_shard_id(shard_size)
     branch = Branch.create(shard_size, shard_id)
     shard = self.shards.get(branch, None)
     if not shard:
         return None
     return shard.state.get_code(address.recipient, block_height)
示例#19
0
 async def gasPrice(self, shard):
     shard = shard_id_decoder(shard)
     if shard is None:
         return None
     branch = Branch.create(self.master.get_shard_size(), shard)
     ret = await self.master.gas_price(branch)
     if ret is None:
         return None
     return quantity_encoder(ret)
示例#20
0
    def test_getWork_and_submitWork(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

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

            branch = Branch.create(1, 0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=0,
                gas_price=12,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            for shard_id in ["0x0", None]:  # shard, then root
                resp = send_request("getWork", shard_id)
                self.assertEqual(resp[1:], ["0x1", "0xa"])  # height and diff

                header_hash_hex = resp[0]
                if shard_id is not None:  # shard 0
                    miner_address = Address.create_from(
                        master.env.quark_chain_config.shards[1].COINBASE_ADDRESS
                    )
                else:  # root
                    miner_address = Address.create_from(
                        master.env.quark_chain_config.ROOT.COINBASE_ADDRESS
                    )
                _, block = call_async(
                    master.get_next_block_to_mine(
                        address=miner_address, prefer_root=shard_id is None
                    )
                )
                self.assertEqual(
                    header_hash_hex[2:], block.header.get_hash_for_mining().hex()
                )
                # solve it and submit
                work = MiningWork(bytes.fromhex(resp[0][2:]), 1, 10)
                solver = DoubleSHA256(work)
                nonce = solver.mine(0, 10000).nonce
                mixhash = "0x" + sha3_256(b"").hex()
                resp = send_request(
                    "submitWork", shard_id, header_hash_hex, hex(nonce), mixhash
                )
                self.assertTrue(resp)

            # show progress on shard 0
            self.assertEqual(
                clusters[0].get_shard_state(1 | 0).get_tip().header.height, 1
            )
示例#21
0
 async def getTransactionById(self, tx_id):
     tx_hash, full_shard_id = tx_id
     shard_size = self.master.get_shard_size()
     branch = Branch.create(shard_size, (shard_size - 1) & full_shard_id)
     minor_block, i = await self.master.get_transaction_by_hash(tx_hash, branch)
     if not minor_block:
         return None
     if len(minor_block.tx_list) <= i:
         return None
     return tx_encoder(minor_block, i)
示例#22
0
    async def getTransactionReceipt(self, tx_id):
        tx_hash, full_shard_id = tx_id
        shard_size = self.master.get_shard_size()
        branch = Branch.create(shard_size, (shard_size - 1) & full_shard_id)
        resp = await self.master.get_transaction_receipt(tx_hash, branch)
        if not resp:
            return None
        minor_block, i, receipt = resp

        return receipt_encoder(minor_block, i, receipt)
示例#23
0
    def test_add_transaction(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)

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

            branch0 = Branch.create(2, 0)
            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.create(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())
示例#24
0
 async def getWork(self, shard):
     branch = None  # `None` means getting work from root chain
     if shard is not None:
         branch = Branch.create(self.master.get_shard_size(), shard)
     ret = await self.master.get_work(branch)
     if ret is None:
         return None
     return [
         data_encoder(ret.hash),
         quantity_encoder(ret.height),
         quantity_encoder(ret.difficulty),
     ]
示例#25
0
    def test_getTransactionCount(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(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

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 0
            )
            for i in range(3):
                tx = create_transfer_transaction(
                    shard_state=slaves[0].shards[branch].state,
                    key=id1.get_key(),
                    from_address=acc1,
                    to_address=acc1,
                    value=12345,
                )
                self.assertTrue(slaves[0].add_tx(tx))

                _, block = call_async(master.get_next_block_to_mine(address=acc1))
                self.assertEqual(i + 1, block.header.height)
                self.assertTrue(
                    call_async(clusters[0].get_shard(2 | 0).add_block(block))
                )

            response = send_request(
                "getTransactionCount", "0x" + acc2.serialize().hex()
            )
            self.assertEqual(response, "0x0")

            response = send_request(
                "getTransactionCount", "0x" + acc1.serialize().hex()
            )
            self.assertEqual(response, "0x3")
            response = send_request(
                "getTransactionCount", "0x" + acc1.serialize().hex(), "latest"
            )
            self.assertEqual(response, "0x3")

            for i in range(3):
                response = send_request(
                    "getTransactionCount", "0x" + acc1.serialize().hex(), hex(i + 1)
                )
                self.assertEqual(response, hex(i + 1))
示例#26
0
    async def getAccountData(self,
                             address,
                             block_height=None,
                             include_shards=False):
        # do not allow specify height if client wants info on all shards
        if include_shards and block_height is not None:
            return None

        address = Address.deserialize(address)
        if not include_shards:
            account_branch_data = await self.master.get_primary_account_data(
                address, block_height)
            branch = account_branch_data.branch
            balance = account_branch_data.balance
            count = account_branch_data.transaction_count
            primary = {
                "branch": quantity_encoder(branch.value),
                "shard": quantity_encoder(branch.get_shard_id()),
                "balance": quantity_encoder(balance),
                "transactionCount": quantity_encoder(count),
                "isContract": account_branch_data.is_contract,
            }
            return {"primary": primary}

        branch_to_account_branch_data = await self.master.get_account_data(
            address)
        shard_size = self.master.get_shard_size()

        shards = []
        for shard in range(shard_size):
            branch = Branch.create(shard_size, shard)
            account_branch_data = branch_to_account_branch_data[branch]
            data = {
                "branch":
                quantity_encoder(account_branch_data.branch.value),
                "shard":
                quantity_encoder(account_branch_data.branch.get_shard_id()),
                "balance":
                quantity_encoder(account_branch_data.balance),
                "transactionCount":
                quantity_encoder(account_branch_data.transaction_count),
                "isContract":
                account_branch_data.is_contract,
            }
            shards.append(data)

            if shard == address.get_shard_id(shard_size):
                primary = data

        return {"primary": primary, "shards": shards}
示例#27
0
 async def getMinorBlockByHeight(
     self, shard: int, height=None, include_transactions=False
 ):
     shard_size = self.master.get_shard_size()
     if height is not None:
         height = quantity_decoder(height)
     if shard >= shard_size:
         raise InvalidParams(
             "shard is larger than shard size {} > {}".format(shard, shard_size)
         )
     branch = Branch.create(shard_size, shard)
     block = await self.master.get_minor_block_by_height(height, branch)
     if not block:
         return None
     return minor_block_encoder(block, include_transactions)
示例#28
0
    def create_minor_block(self, root_block: RootBlock, shard_id: int,
                           evm_state: EvmState) -> MinorBlock:
        """ Create genesis block for shard.
        Genesis block's hash_prev_root_block is set to the genesis root block.
        Genesis state will be committed to the given evm_state.
        """
        branch = Branch.create(self._qkc_config.SHARD_SIZE, shard_id)
        shard_config = self._qkc_config.SHARD_LIST[shard_id]
        genesis = shard_config.GENESIS

        for address_hex, amount_in_wei in genesis.ALLOC.items():
            address = Address.create_from(bytes.fromhex(address_hex))
            check(
                address.get_shard_id(self._qkc_config.SHARD_SIZE) == shard_id)
            evm_state.full_shard_id = address.full_shard_id
            evm_state.delta_balance(address.recipient, amount_in_wei)

        evm_state.commit()

        meta = MinorBlockMeta(
            hash_merkle_root=bytes.fromhex(genesis.HASH_MERKLE_ROOT),
            hash_evm_state_root=evm_state.trie.root_hash,
        )

        local_fee_rate = 1 - self._qkc_config.reward_tax_rate  # type: Fraction
        coinbase_amount = (shard_config.COINBASE_AMOUNT *
                           local_fee_rate.numerator //
                           local_fee_rate.denominator)
        coinbase_address = Address.create_empty_account(shard_id)

        header = MinorBlockHeader(
            version=genesis.VERSION,
            height=genesis.HEIGHT,
            branch=branch,
            hash_prev_minor_block=bytes.fromhex(genesis.HASH_PREV_MINOR_BLOCK),
            hash_prev_root_block=root_block.header.get_hash(),
            evm_gas_limit=genesis.GAS_LIMIT,
            hash_meta=sha3_256(meta.serialize()),
            coinbase_amount=coinbase_amount,
            coinbase_address=coinbase_address,
            create_time=genesis.TIMESTAMP,
            difficulty=genesis.DIFFICULTY,
            extra_data=bytes.fromhex(genesis.EXTRA_DATA),
        )
        return MinorBlock(header=header, meta=meta, tx_list=[])
示例#29
0
    async def create_shards(self, root_block: RootBlock):
        """ Create shards based on GENESIS config and root block height if they have
        not been created yet."""
        futures = []
        for shard_id, shard_config in enumerate(self.env.quark_chain_config.SHARD_LIST):
            branch = Branch.create(self.env.quark_chain_config.SHARD_SIZE, shard_id)
            if branch in self.shards:
                continue
            if not self.__cover_shard_id(shard_id) or not shard_config.GENESIS:
                continue
            if root_block.header.height >= shard_config.GENESIS.ROOT_HEIGHT:
                shard = Shard(self.env, shard_id, self)
                futures.append(shard.init_from_root_block(root_block))
                self.shards[branch] = shard
                if self.mining:
                    shard.miner.start()

        await asyncio.gather(*futures)
示例#30
0
    def test_sendTransaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=1)

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

            branch = Branch.create(2, 0)
            evm_tx = EvmTransaction(
                nonce=0,
                gasprice=6,
                startgas=30000,
                to=acc2.recipient,
                value=15,
                data=b"",
                from_full_shard_id=acc1.full_shard_id,
                to_full_shard_id=acc2.full_shard_id,
                network_id=slaves[0].env.quark_chain_config.NETWORK_ID,
            )
            evm_tx.sign(id1.get_key())
            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",  # 15
                v=quantity_encoder(evm_tx.v),
                r=quantity_encoder(evm_tx.r),
                s=quantity_encoder(evm_tx.s),
                nonce="0x0",
                fromFullShardId="0x00000000",
                toFullShardId="0x00000001",
                network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID),
            )
            tx = Transaction(code=Code.create_evm_code(evm_tx))
            response = send_request("sendTransaction", [request])

            self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000")
            self.assertEqual(len(slaves[0].shards[branch].state.tx_queue), 1)
            self.assertEqual(
                slaves[0].shards[branch].state.tx_queue.pop_transaction(),
                evm_tx)