async def get_sync_start_block(self, peer: LESPeer, head_info: les.HeadInfo) -> int: chain_head = await self.headerdb.coro_get_canonical_head() last_peer_announcement = self._last_processed_announcements.get(peer) if chain_head.block_number == GENESIS_BLOCK_NUMBER: start_block = GENESIS_BLOCK_NUMBER elif last_peer_announcement is None: # It's the first time we hear from this peer, need to figure out which headers to # get from it. We can't simply fetch headers starting from our current head # number because there may have been a chain reorg, so we fetch some headers prior # to our head from the peer, and insert any missing ones in our DB, essentially # making our canonical chain identical to the peer's up to # chain_head.block_number. oldest_ancestor_to_consider = max( 0, chain_head.block_number - peer.max_headers_fetch + 1) try: headers = await self.fetch_headers(oldest_ancestor_to_consider, peer) except EmptyGetBlockHeadersReply: raise LESAnnouncementProcessingError( "No common ancestors found between us and {}".format(peer)) except TooManyTimeouts: raise LESAnnouncementProcessingError( "Too many timeouts when fetching headers from {}".format( peer)) for header in headers: await self.headerdb.coro_persist_header(header) start_block = chain_head.block_number else: start_block = last_peer_announcement.block_number - head_info.reorg_depth return start_block
async def _import_headers_from_peer(self, headers, peer): """ :return: the block number of the new tip after importing the header """ new_tip = None for header in headers: try: await self._validate_header(header) except ValidationError as exc: raise LESAnnouncementProcessingError("Peer {} sent invalid header {}: {}".format( peer, header, exc, )) else: await self.wait(self.headerdb.coro_persist_header(header)) new_tip = header.block_number return new_tip
async def process_announcement(self, peer: LESPeer, head_info: les.HeadInfo) -> None: if await self.chaindb.coro_header_exists(head_info.block_hash): self.logger.debug( "Skipping processing of %s from %s as head has already been fetched", head_info, peer) return start_block = await self.get_sync_start_block(peer, head_info) while start_block < head_info.block_number: try: # We should use "start_block + 1" here, but we always re-fetch the last synced # block to work around https://github.com/ethereum/go-ethereum/issues/15447 batch = await self.fetch_headers(start_block, peer) except TooManyTimeouts: raise LESAnnouncementProcessingError( "Too many timeouts when fetching headers from {}".format(peer)) for header in batch: await self.chaindb.coro_persist_header(header) start_block = header.block_number self.logger.info("synced headers up to #%s", start_block)