class AsyncChainMixin(BaseAsyncChain): coro_get_ancestors = async_method('get_ancestors') coro_get_ancestor_headers = async_method('get_ancestor_headers') coro_get_block_by_hash = async_method('get_block_by_hash') coro_get_block_by_header = async_method('get_block_by_header') coro_get_block_header_by_hash = async_method('get_block_header_by_hash') coro_get_canonical_block_by_number = async_method( 'get_canonical_block_by_number') coro_import_block = async_method('import_block') coro_validate_chain = async_method('validate_chain') coro_validate_receipt = async_method('validate_receipt')
class AsyncChainMixin(AsyncChainAPI): chaindb_class: Type[ChainDatabaseAPI] = AsyncChainDB coro_get_ancestors = async_method(Chain.get_ancestors) coro_get_block_by_hash = async_method(Chain.get_block_by_hash) coro_get_block_by_header = async_method(Chain.get_block_by_header) coro_get_block_header_by_hash = async_method(Chain.get_block_header_by_hash) coro_get_canonical_block_by_number = async_method(Chain.get_canonical_block_by_number) coro_get_canonical_head = async_method(Chain.get_canonical_head) coro_import_block = async_method(Chain.import_block) coro_validate_chain = async_method(Chain.validate_chain) coro_validate_receipt = async_method(Chain.validate_receipt)
class AsyncWitnessDB(AsyncWitnessDataBaseAPI): _recent_blocks_with_witnesses_lookup_key = b'recent-blocks-with-witness-hashes' _max_witness_history = 256 def __init__(self, db: DatabaseAPI) -> None: self.db = db def _make_block_witness_hashes_lookup_key(self, block_hash: Hash32) -> bytes: return b'block-witness-hashes:%s' % block_hash def _get_recent_blocks_with_witnesses(self) -> Tuple[Hash32, ...]: return tuple( rlp.decode(self.db[self._recent_blocks_with_witnesses_lookup_key])) def get_witness_hashes(self, block_hash: Hash32) -> Tuple[Hash32, ...]: try: return tuple( rlp.decode(self.db[self._make_block_witness_hashes_lookup_key( block_hash)])) except KeyError: raise WitnessHashesUnavailable("No witness hashes for block %s", encode_hex(block_hash)) def persist_witness_hashes(self, block_hash: Hash32, witness_hashes: Tuple[Hash32, ...]) -> None: try: recent_blocks_with_witnesses = list( self._get_recent_blocks_with_witnesses()) except KeyError: recent_blocks_with_witnesses = [] while len(recent_blocks_with_witnesses) >= self._max_witness_history: oldest_block_witness = recent_blocks_with_witnesses.pop(0) del self.db[self._make_block_witness_hashes_lookup_key( oldest_block_witness)] recent_blocks_with_witnesses.append(block_hash) self.db[self._recent_blocks_with_witnesses_lookup_key] = rlp.encode( recent_blocks_with_witnesses) self.db[self._make_block_witness_hashes_lookup_key( block_hash)] = rlp.encode(witness_hashes) coro_get_witness_hashes = async_method(get_witness_hashes) coro_persist_witness_hashes = async_method(persist_witness_hashes)
class AsyncHeaderDB(BaseAsyncHeaderDB): coro_get_block_header_by_hash = async_method( BaseAsyncHeaderDB.get_block_header_by_hash) coro_get_canonical_block_hash = async_method( BaseAsyncHeaderDB.get_canonical_block_hash) coro_get_canonical_block_header_by_number = async_method( BaseAsyncHeaderDB.get_canonical_block_header_by_number) # noqa: E501 coro_get_canonical_head = async_method( BaseAsyncHeaderDB.get_canonical_head) coro_get_score = async_method(BaseAsyncHeaderDB.get_score) coro_header_exists = async_method(BaseAsyncHeaderDB.header_exists) coro_get_canonical_block_hash = async_method( BaseAsyncHeaderDB.get_canonical_block_hash) coro_persist_checkpoint_header = async_method( BaseAsyncHeaderDB.persist_checkpoint_header) coro_persist_header = async_method(BaseAsyncHeaderDB.persist_header) coro_persist_header_chain = async_method( BaseAsyncHeaderDB.persist_header_chain)
class LightDispatchChain(AsyncChainAPI, Chain): """ Provide the :class:`ChainAPI` API, even though only a :class:`BaseLightPeerChain` is syncing. Store results locally so that not all requests hit the light peer network. """ chaindb_class = AsyncChainDB ASYNC_TIMEOUT_SECONDS = 10 _loop = None def __init__(self, headerdb: HeaderDatabaseAPI, peer_chain: BaseLightPeerChain) -> None: self._headerdb = headerdb self._peer_chain = peer_chain self._peer_chain_loop = asyncio.get_event_loop() # # Helpers # @classmethod def get_chaindb_class(cls) -> Type[ChainDatabaseAPI]: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # Chain API # @classmethod def from_genesis(cls, base_db: DatabaseAPI, genesis_params: Dict[str, HeaderParams], genesis_state: AccountState=None) -> 'LightDispatchChain': raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) @classmethod def from_genesis_header(cls, base_db: DatabaseAPI, genesis_header: BlockHeaderAPI) -> 'LightDispatchChain': raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_chain_at_block_parent(self, block: BlockAPI) -> 'LightDispatchChain': raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # VM API # def get_vm(self, header: BlockHeaderAPI=None) -> VirtualMachineAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # Header API # def create_header_from_parent(self, parent_header: BlockHeaderAPI, **header_params: HeaderParams) -> BlockHeaderAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_block_header_by_hash(self, block_hash: Hash32) -> BlockHeaderAPI: return self._headerdb.get_block_header_by_hash(block_hash) coro_get_block_header_by_hash = async_method(Chain.get_block_header_by_hash) def get_canonical_head(self) -> BlockHeaderAPI: return self._headerdb.get_canonical_head() coro_get_canonical_head = async_method(Chain.get_canonical_head) def get_score(self, block_hash: Hash32) -> int: return self._headerdb.get_score(block_hash) # # Block API # def get_ancestors(self, limit: int, header: BlockHeaderAPI) -> Tuple[BlockAPI, ...]: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) async def coro_get_ancestors(self, limit: int, header: BlockHeaderAPI) -> Tuple[BlockAPI, ...]: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_block(self) -> BlockAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_block_by_hash(self, block_hash: Hash32) -> BlockAPI: raise NotImplementedError("Use coro_get_block_by_hash") async def coro_get_block_by_hash(self, block_hash: Hash32) -> BlockAPI: header = self._headerdb.get_block_header_by_hash(block_hash) return await self.coro_get_block_by_header(header) def get_block_by_header(self, header: BlockHeaderAPI) -> BlockAPI: raise NotImplementedError("Use coro_get_block_by_header") async def coro_get_block_by_header(self, header: BlockHeaderAPI) -> BlockAPI: # TODO check local cache, before hitting peer block_body = await self._peer_chain.coro_get_block_body_by_hash(header.hash) block_class = self.get_vm_class_for_block_number(header.block_number).get_block_class() transactions = [ block_class.transaction_class.from_base_transaction(tx) for tx in block_body.transactions ] return block_class( header=header, transactions=transactions, uncles=block_body.uncles, ) def get_canonical_block_by_number(self, block_number: BlockNumber) -> BlockAPI: raise NotImplementedError("Use coro_get_canonical_block_by_number") async def coro_get_canonical_block_by_number(self, block_number: BlockNumber) -> BlockAPI: """ Return the block with the given number from the canonical chain. Raises HeaderNotFound if it is not found. """ header = self._headerdb.get_canonical_block_header_by_number(block_number) return await self.get_block_by_header(header) def get_canonical_block_hash(self, block_number: BlockNumber) -> Hash32: return self._headerdb.get_canonical_block_hash(block_number) def build_block_with_transactions(self, transactions: Tuple[SignedTransactionAPI, ...], parent_header: BlockHeaderAPI=None) -> Tuple[BlockAPI, Tuple[ReceiptAPI, ...], Tuple[ComputationAPI, ...]]: # noqa: E501 raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # Transaction API # def create_transaction(self, *args: Any, **kwargs: Any) -> SignedTransactionAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def create_unsigned_transaction(cls, *, nonce: int, gas_price: int, gas: int, to: Address, value: int, data: bytes) -> UnsignedTransactionAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_canonical_transaction(self, transaction_hash: Hash32) -> SignedTransactionAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_transaction_receipt(self, transaction_hash: Hash32) -> ReceiptAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # Execution API # def apply_transaction( self, transaction: SignedTransactionAPI) -> Tuple[BlockAPI, ReceiptAPI, ComputationAPI]: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def get_transaction_result( self, transaction: SignedTransactionAPI, at_header: BlockHeaderAPI) -> bytes: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def estimate_gas( self, transaction: SignedTransactionAPI, at_header: BlockHeaderAPI=None) -> int: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def import_block(self, block: BlockAPI, perform_validation: bool=True) -> BlockAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) async def coro_import_block(self, block: BlockAPI, perform_validation: bool=True) -> BlockAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def mine_block(self, *args: Any, **kwargs: Any) -> BlockAPI: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) # # Validation API # def validate_receipt(self, receipt: ReceiptAPI, at_header: BlockHeaderAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) async def coro_validate_receipt(self, receipt: ReceiptAPI, at_header: BlockHeaderAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def validate_block(self, block: BlockAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def validate_gaslimit(self, header: BlockHeaderAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def validate_seal(self, header: BlockHeaderAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) def validate_uncles(self, block: BlockAPI) -> None: raise NotImplementedError("Chain classes must implement " + inspect.stack()[0][3]) coro_validate_chain = async_method(Chain.validate_chain)
class AsyncBeaconChainDB(BaseAsyncBeaconChainDB): coro_persist_block = async_method(BaseAsyncBeaconChainDB.persist_block) coro_get_canonical_block_root = async_method( BaseAsyncBeaconChainDB.get_canonical_block_root) # noqa: E501 coro_get_genesis_block_root = async_method( BaseAsyncBeaconChainDB.get_genesis_block_root) coro_get_canonical_block_by_slot = async_method( BaseAsyncBeaconChainDB.get_canonical_block_by_slot) # noqa: E501 coro_get_canonical_head = async_method( BaseAsyncBeaconChainDB.get_canonical_head) coro_get_canonical_head_root = async_method( BaseAsyncBeaconChainDB.get_canonical_head_root) # noqa: E501 coro_get_finalized_head = async_method( BaseAsyncBeaconChainDB.get_finalized_head) coro_get_block_by_root = async_method( BaseAsyncBeaconChainDB.get_block_by_root) coro_get_score = async_method(BaseAsyncBeaconChainDB.get_score) coro_block_exists = async_method(BaseAsyncBeaconChainDB.block_exists) coro_persist_block_chain = async_method( BaseAsyncBeaconChainDB.persist_block_chain) coro_get_state_by_root = async_method( BaseAsyncBeaconChainDB.get_state_by_root) coro_persist_state = async_method(BaseAsyncBeaconChainDB.persist_state) coro_get_attestation_key_by_root = async_method( BaseAsyncBeaconChainDB.get_attestation_key_by_root) # noqa: E501 coro_attestation_exists = async_method( BaseAsyncBeaconChainDB.attestation_exists) coro_exists = async_method(BaseAsyncBeaconChainDB.exists) coro_get = async_method(BaseAsyncBeaconChainDB.get)
class AsyncWitnessDB(AsyncWitnessDataBaseAPI): _recent_blocks_with_witnesses_lookup_key = b'recent-blocks-with-witness-hashes' _max_witness_history = 256 def __init__(self, db: DatabaseAPI) -> None: self.db = db def _make_block_witness_hashes_lookup_key(self, block_hash: Hash32) -> bytes: return b'block-witness-hashes:%s' % block_hash def _get_recent_blocks_with_witnesses(self) -> Tuple[Hash32, ...]: return tuple( rlp.decode(self.db[self._recent_blocks_with_witnesses_lookup_key])) def get_witness_hashes(self, block_hash: Hash32) -> Tuple[Hash32, ...]: try: return tuple( rlp.decode(self.db[self._make_block_witness_hashes_lookup_key( block_hash)])) except KeyError: raise WitnessHashesUnavailable("No witness hashes for block %s", encode_hex(block_hash)) def persist_witness_hashes(self, block_hash: Hash32, witness_hashes: Tuple[Hash32, ...]) -> None: try: recent_blocks_with_witnesses = list( self._get_recent_blocks_with_witnesses()) except KeyError: recent_blocks_with_witnesses = [] # Add in the new block, if it's not already present if block_hash not in recent_blocks_with_witnesses: recent_blocks_with_witnesses.append(block_hash) # Flush out old witnesses while len(recent_blocks_with_witnesses) > self._max_witness_history: oldest_block_witness = recent_blocks_with_witnesses.pop(0) del self.db[self._make_block_witness_hashes_lookup_key( oldest_block_witness)] # Store new reference to existing witness self.db[self._recent_blocks_with_witnesses_lookup_key] = rlp.encode( recent_blocks_with_witnesses) try: # Note: if this call is converted to async, watch out for the race # condition of two persists that interleave. It would be # possible for one to overwrite the other. For now, the synchronous # approach means that that isn't a concern. existing_hashes = self.get_witness_hashes(block_hash) except WitnessHashesUnavailable: existing_hashes = () block_hashes_key = self._make_block_witness_hashes_lookup_key( block_hash) combined_hashes = tuple(set(existing_hashes).union(witness_hashes)) self.db[block_hashes_key] = rlp.encode(combined_hashes) coro_get_witness_hashes = async_method(get_witness_hashes) coro_persist_witness_hashes = async_method(persist_witness_hashes)
class AsyncChainDB(BaseAsyncChainDB): coro_exists = async_method(BaseAsyncChainDB.exists) coro_get = async_method(BaseAsyncChainDB.get) coro_get_block_header_by_hash = async_method( BaseAsyncChainDB.get_block_header_by_hash) coro_get_canonical_head = async_method(BaseAsyncChainDB.get_canonical_head) coro_get_score = async_method(BaseAsyncChainDB.get_score) coro_header_exists = async_method(BaseAsyncChainDB.header_exists) coro_get_canonical_block_hash = async_method( BaseAsyncChainDB.get_canonical_block_hash) coro_get_canonical_block_header_by_number = async_method( BaseAsyncChainDB.get_canonical_block_header_by_number) # noqa: E501 coro_persist_checkpoint_header = async_method( BaseAsyncChainDB.persist_checkpoint_header) coro_persist_header = async_method(BaseAsyncChainDB.persist_header) coro_persist_header_chain = async_method( BaseAsyncChainDB.persist_header_chain) coro_persist_block = async_method(BaseAsyncChainDB.persist_block) coro_persist_header_chain = async_method( BaseAsyncChainDB.persist_header_chain) coro_persist_uncles = async_method(BaseAsyncChainDB.persist_uncles) coro_persist_trie_data_dict = async_method( BaseAsyncChainDB.persist_trie_data_dict) coro_get_block_transactions = async_method( BaseAsyncChainDB.get_block_transactions) coro_get_block_uncles = async_method(BaseAsyncChainDB.get_block_uncles) coro_get_receipts = async_method(BaseAsyncChainDB.get_receipts)