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), ))
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
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
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)
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)
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")
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)
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