Exemplo n.º 1
0
    def __init__(self,
                 chain: AsyncChainAPI,
                 db: BaseAsyncChainDB,
                 peer_pool: ETHPeerPool,
                 enable_backfill: bool = True,
                 checkpoint: Checkpoint = None) -> None:
        self.logger = get_logger('trinity.sync.header.chain.HeaderChainSyncer')
        self._db = db
        self._checkpoint = checkpoint
        self._enable_backfill = enable_backfill
        self._chain = chain
        self._peer_pool = peer_pool

        if checkpoint is None:
            self._launch_strategy: SyncLaunchStrategyAPI = FromGenesisLaunchStrategy(
                db)
        else:
            self._launch_strategy = FromCheckpointLaunchStrategy(
                db,
                chain,
                checkpoint,
                peer_pool,
            )

        self._header_syncer = ETHHeaderChainSyncer(chain, db, peer_pool,
                                                   self._launch_strategy)
Exemplo n.º 2
0
    def __init__(
            self,
            chain: AsyncChainAPI,
            db: AtomicDatabaseAPI,
            chain_db: BaseAsyncChainDB,
            peer_pool: ETHPeerPool,
            event_bus: EndpointAPI,
            metrics_registry: MetricsRegistry,
            checkpoint: Checkpoint = None,
            force_beam_block_number: BlockNumber = None,
            enable_backfill: bool = True,
            enable_state_backfill: bool = True) -> None:
        self.logger = get_logger('trinity.sync.beam.chain.BeamSyncer')

        self.metrics_registry = metrics_registry
        self._body_for_header_exists = body_for_header_exists(chain_db, chain)

        if checkpoint is None:
            self._launch_strategy: SyncLaunchStrategyAPI = FromGenesisLaunchStrategy(chain_db)
        else:
            self._launch_strategy = FromCheckpointLaunchStrategy(
                chain_db,
                chain,
                checkpoint,
                peer_pool,
            )

        self._header_syncer = ETHHeaderChainSyncer(
            chain,
            chain_db,
            peer_pool,
            self._launch_strategy,
        )
        self._header_persister = HeaderOnlyPersist(
            self._header_syncer,
            chain_db,
            force_beam_block_number,
            self._launch_strategy,
        )

        self._backfiller = BeamStateBackfill(db, peer_pool)

        if enable_state_backfill:
            self._queen_queue: QueenTrackerAPI = self._backfiller
        else:
            self._queen_queue = QueeningQueue(peer_pool)

        self._state_downloader = BeamDownloader(
            db,
            peer_pool,
            self._queen_queue,
            event_bus,
        )
        self._data_hunter = MissingDataEventHandler(
            self._state_downloader,
            event_bus,
            self.metrics_registry,
        )

        self._block_importer = BeamBlockImporter(
            chain,
            db,
            self._state_downloader,
            self._backfiller,
            event_bus,
            self.metrics_registry,
        )
        self._launchpoint_header_syncer = HeaderLaunchpointSyncer(self._header_syncer)
        self._body_syncer = RegularChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._launchpoint_header_syncer,
            self._block_importer,
        )

        self._manual_header_syncer = ManualHeaderSyncer()
        self._fast_syncer = RigorousFastChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._manual_header_syncer,
        )

        self._header_backfill = SequentialHeaderChainGapSyncer(chain, chain_db, peer_pool)
        self._block_backfill = BodyChainGapSyncer(chain, chain_db, peer_pool)

        self._chain = chain
        self._enable_backfill = enable_backfill
        self._enable_state_backfill = enable_state_backfill
Exemplo n.º 3
0
class BeamSyncer(BaseService):
    """
    Organizes several moving parts to coordinate beam sync. Roughly:

        - Sync *only* headers up until you have caught up with a peer, ie~ the checkpoint
        - Launch a service responsible for serving event bus requests for missing state data
        - When you catch up with a peer, start downloading transactions needed to execute a block
        - At the checkpoint, switch to full block imports, with a custom importer

    This syncer relies on a seperately orchestrated beam sync plugin, which:

        - listens for DoStatelessBlockImport events
        - emits events when data is missing, like CollectMissingAccount
        - emits StatelessBlockImportDone when the block import is completed in the DB

    There is an option, currently only used for testing, to force beam sync at a particular
    block number (rather than trigger it when catching up with a peer).
    """
    def __init__(self,
                 chain: AsyncChainAPI,
                 db: BaseAtomicDB,
                 chain_db: BaseAsyncChainDB,
                 peer_pool: ETHPeerPool,
                 event_bus: EndpointAPI,
                 checkpoint: Checkpoint = None,
                 force_beam_block_number: int = None,
                 token: CancelToken = None) -> None:
        super().__init__(token=token)

        if checkpoint is None:
            self._launch_strategy: SyncLaunchStrategyAPI = FromGenesisLaunchStrategy(
                chain_db, chain)
        else:
            self._launch_strategy = FromCheckpointLaunchStrategy(
                chain_db,
                chain,
                checkpoint,
                peer_pool,
            )

        self._header_syncer = ETHHeaderChainSyncer(chain, chain_db, peer_pool,
                                                   self._launch_strategy,
                                                   self.cancel_token)
        self._header_persister = HeaderOnlyPersist(
            self._header_syncer,
            chain_db,
            force_beam_block_number,
            self._launch_strategy,
            self.cancel_token,
        )
        self._state_downloader = BeamDownloader(db, peer_pool, event_bus,
                                                self.cancel_token)
        self._data_hunter = MissingDataEventHandler(
            self._state_downloader,
            event_bus,
            token=self.cancel_token,
        )

        self._block_importer = BeamBlockImporter(
            chain,
            db,
            self._state_downloader,
            event_bus,
            self.cancel_token,
        )
        self._checkpoint_header_syncer = HeaderCheckpointSyncer(
            self._header_syncer)
        self._body_syncer = RegularChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._checkpoint_header_syncer,
            self._block_importer,
            self.cancel_token,
        )

        self._manual_header_syncer = ManualHeaderSyncer()
        self._fast_syncer = RigorousFastChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._manual_header_syncer,
            self.cancel_token,
        )

        self._chain = chain

    async def _run(self) -> None:

        try:
            await self.wait(self._launch_strategy.fulfill_prerequisites())
        except TimeoutError:
            self.logger.error(
                "Timed out while trying to fulfill prerequisites of"
                f"sync launch strategy: {self._launch_strategy}")
            await self.cancel()

        self.run_daemon(self._header_syncer)

        # Kick off the body syncer early (it hangs on the checkpoint header syncer anyway)
        # It needs to start early because we want to "re-run" the header at the tip,
        # which it gets grumpy about. (it doesn't want to receive the canonical header tip
        # as a header to process)
        self.run_daemon(self._body_syncer)

        # Launch the state syncer endpoint early
        self.run_daemon(self._data_hunter)

        # Only persist headers at start
        await self.wait(self._header_persister.run())
        # When header store exits, we have caught up

        # We want to trigger beam sync on the last block received,
        # not wait for the next one to be broadcast
        final_headers = self._header_persister.get_final_headers()

        # First, download block bodies for previous 6 blocks, for validation
        await self._download_blocks(final_headers[0])

        # Now let the beam sync importer kick in
        self._checkpoint_header_syncer.set_checkpoint_headers(final_headers)

        # TODO wait until first header with a body comes in?...
        # Start state downloader service
        self.run_daemon(self._state_downloader)

        # run sync until cancelled
        await self.cancellation()

    async def _download_blocks(self, before_header: BlockHeader) -> None:
        """
        When importing a block, we need to validate uncles against the previous
        six blocks, so download those bodies and persist them to the database.
        """
        # We need MAX_UNCLE_DEPTH + 1 headers to check during uncle validation
        # We need to request one more header, to set the starting tip
        parents_needed = MAX_UNCLE_DEPTH + 2

        self.logger.info(
            "Downloading %d block bodies for uncle validation, before %s",
            parents_needed,
            before_header,
        )

        # select the recent ancestors to sync block bodies for
        parent_headers = tuple(
            reversed([
                header
                async for header in self._get_ancestors(parents_needed,
                                                        header=before_header)
            ]))

        # identify starting tip and headers with possible uncle conflicts for validation
        if len(parent_headers) < parents_needed:
            self.logger.info(
                "Collecting %d blocks to genesis for uncle validation",
                len(parent_headers),
            )
            sync_from_tip = await self._chain.coro_get_canonical_block_by_number(
                BlockNumber(0))
            uncle_conflict_headers = parent_headers
        else:
            sync_from_tip = parent_headers[0]
            uncle_conflict_headers = parent_headers[1:]

        # check if we already have the blocks for the uncle conflict headers
        if await self._all_verification_bodies_present(uncle_conflict_headers):
            self.logger.debug("All needed block bodies are already available")
        else:
            # tell the header syncer to emit those headers
            self._manual_header_syncer.emit(uncle_conflict_headers)

            # tell the fast syncer which tip to start from
            self._fast_syncer.set_starting_tip(sync_from_tip)

            # run the fast syncer (which downloads block bodies and then exits)
            self.logger.info("Getting recent block data for uncle validation")
            await self._fast_syncer.run()

        # When this completes, we have all the uncles needed to validate
        self.logger.info(
            "Have all data needed for Beam validation, continuing...")

    async def _get_ancestors(
            self, limit: int,
            header: BlockHeader) -> AsyncIterator[BlockHeader]:
        """
        Return `limit` number of ancestor headers from the specified header.
        """
        headers_returned = 0
        while header.parent_hash != GENESIS_PARENT_HASH and headers_returned < limit:
            parent = await self._chain.coro_get_block_header_by_hash(
                header.parent_hash)
            yield parent
            headers_returned += 1
            header = parent

    async def _all_verification_bodies_present(
            self,
            headers_with_potential_conflicts: Iterable[BlockHeader]) -> bool:

        for header in headers_with_potential_conflicts:
            if not await self._fast_syncer._should_skip_header(header):
                return False
        return True
Exemplo n.º 4
0
    def __init__(self,
                 chain: AsyncChainAPI,
                 db: BaseAtomicDB,
                 chain_db: BaseAsyncChainDB,
                 peer_pool: ETHPeerPool,
                 event_bus: EndpointAPI,
                 checkpoint: Checkpoint = None,
                 force_beam_block_number: int = None,
                 token: CancelToken = None) -> None:
        super().__init__(token=token)

        if checkpoint is None:
            self._launch_strategy: SyncLaunchStrategyAPI = FromGenesisLaunchStrategy(
                chain_db, chain)
        else:
            self._launch_strategy = FromCheckpointLaunchStrategy(
                chain_db,
                chain,
                checkpoint,
                peer_pool,
            )

        self._header_syncer = ETHHeaderChainSyncer(chain, chain_db, peer_pool,
                                                   self._launch_strategy,
                                                   self.cancel_token)
        self._header_persister = HeaderOnlyPersist(
            self._header_syncer,
            chain_db,
            force_beam_block_number,
            self._launch_strategy,
            self.cancel_token,
        )
        self._state_downloader = BeamDownloader(db, peer_pool, event_bus,
                                                self.cancel_token)
        self._data_hunter = MissingDataEventHandler(
            self._state_downloader,
            event_bus,
            token=self.cancel_token,
        )

        self._block_importer = BeamBlockImporter(
            chain,
            db,
            self._state_downloader,
            event_bus,
            self.cancel_token,
        )
        self._checkpoint_header_syncer = HeaderCheckpointSyncer(
            self._header_syncer)
        self._body_syncer = RegularChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._checkpoint_header_syncer,
            self._block_importer,
            self.cancel_token,
        )

        self._manual_header_syncer = ManualHeaderSyncer()
        self._fast_syncer = RigorousFastChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._manual_header_syncer,
            self.cancel_token,
        )

        self._chain = chain
Exemplo n.º 5
0
    def __init__(self,
                 chain: AsyncChainAPI,
                 db: AtomicDatabaseAPI,
                 chain_db: BaseAsyncChainDB,
                 peer_pool: ETHPeerPool,
                 event_bus: EndpointAPI,
                 checkpoint: Checkpoint = None,
                 force_beam_block_number: BlockNumber = None) -> None:
        self.logger = get_logger('trinity.sync.beam.chain.BeamSyncer')
        if checkpoint is None:
            self._launch_strategy: SyncLaunchStrategyAPI = FromGenesisLaunchStrategy(
                chain_db, chain)
        else:
            self._launch_strategy = FromCheckpointLaunchStrategy(
                chain_db,
                chain,
                checkpoint,
                peer_pool,
            )

        self._header_syncer = ETHHeaderChainSyncer(
            chain,
            chain_db,
            peer_pool,
            self._launch_strategy,
        )
        self._header_persister = HeaderOnlyPersist(
            self._header_syncer,
            chain_db,
            force_beam_block_number,
            self._launch_strategy,
        )

        self._backfiller = BeamStateBackfill(db, peer_pool)

        self._state_downloader = BeamDownloader(
            db,
            peer_pool,
            self._backfiller,
            event_bus,
        )
        self._data_hunter = MissingDataEventHandler(
            self._state_downloader,
            event_bus,
        )

        self._block_importer = BeamBlockImporter(
            chain,
            db,
            self._state_downloader,
            self._backfiller,
            event_bus,
        )
        self._checkpoint_header_syncer = HeaderCheckpointSyncer(
            self._header_syncer)
        self._body_syncer = RegularChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._checkpoint_header_syncer,
            self._block_importer,
        )

        self._manual_header_syncer = ManualHeaderSyncer()
        self._fast_syncer = RigorousFastChainBodySyncer(
            chain,
            chain_db,
            peer_pool,
            self._manual_header_syncer,
        )

        self._chain = chain