def get_minor_block_by_hash(self,
                             h,
                             consistency_check=True
                             ) -> Optional[MinorBlock]:
     if consistency_check and h not in self.m_header_pool:
         return None
     return MinorBlock.deserialize(self.db.get(b"mblock_" + h))
    def recover_state(self, r_header, m_header):
        """ When recovering from local database, we can only guarantee the consistency of the best chain.
        Forking blocks can be in inconsistent state and thus should be pruned from the database
        so that they can be retried in the future.
        """
        r_hash = r_header.get_hash()
        while (len(self.r_header_pool) <
               self.env.quark_chain_config.ROOT.max_root_blocks_in_memory):
            block = RootBlock.deserialize(self.db.get(b"rblock_" + r_hash))
            self.r_minor_header_pool[
                r_hash] = self.__get_last_minor_block_in_root_block(block)
            self.r_header_pool[r_hash] = block.header
            if (block.header.height <=
                    self.env.quark_chain_config.get_genesis_root_height(
                        self.branch.get_shard_id())):
                break
            r_hash = block.header.hash_prev_block

        m_hash = m_header.get_hash()
        shard_config = self.env.quark_chain_config.SHARD_LIST[
            self.branch.get_shard_id()]
        while len(
                self.m_header_pool) < shard_config.max_minor_blocks_in_memory:
            block = MinorBlock.deserialize(self.db.get(b"mblock_" + m_hash))
            self.m_header_pool[m_hash] = block.header
            self.m_meta_pool[m_hash] = block.meta
            if block.header.height <= 0:
                break
            m_hash = block.header.hash_prev_minor_block

        Logger.info("[{}] recovered {} minor blocks and {} root blocks".format(
            self.branch.get_shard_id(),
            len(self.m_header_pool),
            len(self.r_header_pool),
        ))
Esempio n. 3
0
 def get_minor_block_by_hash(self,
                             h: bytes,
                             consistency_check=True
                             ) -> Optional[MinorBlock]:
     if consistency_check and h not in self.m_header_pool:
         return None
     data = self.db.get(b"mblock_" + h, None)
     return MinorBlock.deserialize(data) if data else None
Esempio n. 4
0
 def get_minor_block_by_hash(self, h: bytes) -> Optional[MinorBlock]:
     key = b"mblock_" + h
     if key in self.mblock_cache:
         return self.mblock_cache[key]
     raw_block = self.db.get(key, None)
     block = raw_block and MinorBlock.deserialize(raw_block)
     if block is not None:
         self.mblock_cache[key] = block
     return block
Esempio n. 5
0
    def test_getNextBlockToMine_with_shard_mask(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):
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x2")
            self.assertFalse(response["isRootBlock"])
            block1 = MinorBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))
            self.assertEqual(block1.header.branch.value, 0b10)

            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x3")
            self.assertFalse(response["isRootBlock"])
            block1 = MinorBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))
            self.assertEqual(block1.header.branch.value, 0b11)
Esempio n. 6
0
    async def handle_add_minor_block_request(self, req):
        """ For local miner to submit mined blocks through master """
        try:
            block = MinorBlock.deserialize(req.minor_block_data)
        except Exception:
            return AddMinorBlockResponse(error_code=errno.EBADMSG)
        shard = self.shards.get(block.header.branch, None)
        if not shard:
            return AddMinorBlockResponse(error_code=errno.EBADMSG)

        if block.header.hash_prev_minor_block != shard.state.header_tip.get_hash(
        ):
            # Tip changed, don't bother creating a fork
            Logger.info("[{}] dropped stale block {} mined locally".format(
                block.header.branch.get_shard_id(), block.header.height))
            return AddMinorBlockResponse(error_code=0)

        success = await shard.add_block(block)
        return AddMinorBlockResponse(error_code=0 if success else errno.EFAULT)
Esempio n. 7
0
    def test_getNextBlockToMine_and_addBlock(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc3 = 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

            # Expect to mine root that confirms the genesis minor blocks
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x0")
            self.assertTrue(response["isRootBlock"])
            block = RootBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))

            self.assertEqual(block.header.height, 1)
            self.assertEqual(len(block.minor_block_header_list), 2)
            self.assertEqual(block.minor_block_header_list[0].height, 0)
            self.assertEqual(block.minor_block_header_list[1].height, 0)

            send_request("addBlock", "0x0", response["blockData"])

            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc3,
                value=14,
                gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            # Expect to mine shard 0 since it has one tx
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x0")
            self.assertFalse(response["isRootBlock"])
            block1 = MinorBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))
            self.assertEqual(block1.header.branch.value, 0b10)

            self.assertTrue(
                send_request("addBlock", "0x2", response["blockData"]))
            self.assertEqual(
                clusters[0].get_shard_state(1).get_balance(acc3.recipient, 0),
                0)

            # Expect to mine shard 1 due to proof-of-progress
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x0")
            self.assertFalse(response["isRootBlock"])
            block2 = MinorBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))
            self.assertEqual(block2.header.branch.value, 0b11)

            self.assertTrue(
                send_request("addBlock", "0x3", response["blockData"]))

            # Expect to mine root
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x0")
            self.assertTrue(response["isRootBlock"])
            block = RootBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))

            self.assertEqual(block.header.height, 2)
            self.assertEqual(len(block.minor_block_header_list), 2)
            self.assertEqual(block.minor_block_header_list[0], block1.header)
            self.assertEqual(block.minor_block_header_list[1], block2.header)

            send_request("addBlock", "0x0", response["blockData"])
            self.assertEqual(
                clusters[0].get_shard_state(1).get_balance(acc3.recipient, 0),
                0)

            # Expect to mine shard 1 for the gas on xshard tx to acc3
            response = send_request("getNextBlockToMine",
                                    "0x" + acc1.serialize().hex(), "0x0")
            self.assertFalse(response["isRootBlock"])
            block3 = MinorBlock.deserialize(
                bytes.fromhex(response["blockData"][2:]))
            self.assertEqual(block3.header.branch.value, 0b11)

            self.assertTrue(
                send_request("addBlock", "0x3", response["blockData"]))
            # Expect withdrawTo is included in acc3's balance
            resp = send_request("getBalance", "0x" + acc3.serialize().hex())
            self.assertEqual(resp["branch"], "0x3")
            self.assertEqual(resp["balance"], "0xe")
Esempio n. 8
0
 def get_genesis_block(self, root_block_hash):
     data = self.db.get(b"genesis_" + root_block_hash, None)
     if not data:
         return None
     else:
         return MinorBlock.deserialize(data)
Esempio n. 9
0
 def get_minor_block_by_hash(self, h: bytes) -> Optional[MinorBlock]:
     data = self.db.get(b"mblock_" + h, None)
     return MinorBlock.deserialize(data) if data else None