@@ -111,6 +111,91 @@ where
111111 MiningConfig :: from_env ( )
112112 } ;
113113
114+ // Register the sparse-trie state-root spawner, if enabled.
115+ //
116+ // We construct a long-lived `PayloadProcessor` keyed to a fresh `BscEvmConfig`
117+ // (built from chain_spec — same source as the rest of the BSC pipeline). For
118+ // each build job, the registered closure constructs a one-shot
119+ // `OverlayStateProviderFactory` anchored at the parent block hash and calls
120+ // `spawn_state_root` to get a `StateRootHandle`.
121+ //
122+ // `TreeConfig::default()` is used here as a workaround — the engine-launch
123+ // `TreeConfig` (which honors `--engine.*` CLI flags) is not reachable from
124+ // `BscPayloadServiceBuilder`. Default values are reasonable for the sparse-trie
125+ // background task; revisit if performance testing shows we need CLI-tunable
126+ // worker counts or cache sizes.
127+ if mining_config. use_sparse_trie_state_root
128+ && !rust_eth_triedb:: triedb_manager:: is_triedb_active ( )
129+ {
130+ use reth_engine_tree:: tree:: {
131+ payload_processor:: PayloadProcessor , precompile_cache:: PrecompileCacheMap ,
132+ TreeConfig ,
133+ } ;
134+ use reth_provider:: providers:: { OverlayBuilder , OverlayStateProviderFactory } ;
135+ use reth_tasks:: { Runtime , RuntimeBuilder , RuntimeConfig , TokioConfig } ;
136+ use reth_trie_db:: ChangesetCache ;
137+
138+ let chain_spec = Arc :: new ( ctx. config ( ) . chain . clone ( ) . as_ref ( ) . clone ( ) ) ;
139+ let bsc_evm_config = crate :: node:: evm:: config:: BscEvmConfig :: new ( chain_spec) ;
140+ let tree_config = Arc :: new ( TreeConfig :: default ( ) ) ;
141+ let provider = ctx. provider ( ) . clone ( ) ;
142+
143+ // Build a dedicated `reth_tasks::Runtime` for the sparse-trie pools,
144+ // attached to the existing tokio handle so we don't spin up a second tokio
145+ // executor. Rayon pools default to `available_parallelism()`, matching what
146+ // the engine uses for its own PayloadProcessor.
147+ //
148+ // TODO: in a follow-up, share the engine's Runtime instead of constructing
149+ // a parallel one — this currently means two sets of rayon pools competing
150+ // for CPU. Acceptable for a first cut; revisit if perf testing shows
151+ // contention.
152+ let tokio_handle = ctx. task_executor ( ) . handle ( ) . clone ( ) ;
153+ let runtime = RuntimeBuilder :: new (
154+ RuntimeConfig :: default ( ) . with_tokio ( TokioConfig :: existing_handle ( tokio_handle) ) ,
155+ )
156+ . build ( )
157+ . map_err ( |e| eyre:: eyre!( "failed to build sparse-trie Runtime: {e}" ) ) ?;
158+ let _: & Runtime = & runtime; // type-check anchor
159+
160+ let payload_processor = std:: sync:: Arc :: new ( PayloadProcessor :: new (
161+ runtime,
162+ bsc_evm_config,
163+ tree_config. as_ref ( ) ,
164+ PrecompileCacheMap :: default ( ) ,
165+ ) ) ;
166+
167+ let tree_config_for_closure = tree_config. clone ( ) ;
168+ let spawn_fn: crate :: shared:: SparseTrieSpawnFn = std:: sync:: Arc :: new (
169+ move |parent_hash : alloy_primitives:: B256 ,
170+ parent_state_root : alloy_primitives:: B256 | {
171+ let overlay_factory = OverlayStateProviderFactory :: new (
172+ provider. clone ( ) ,
173+ OverlayBuilder :: < crate :: BscPrimitives > :: new (
174+ parent_hash,
175+ ChangesetCache :: default ( ) ,
176+ ) ,
177+ ) ;
178+ Some ( payload_processor. spawn_state_root (
179+ overlay_factory,
180+ parent_state_root,
181+ false , // halve_workers
182+ tree_config_for_closure. as_ref ( ) ,
183+ ) )
184+ } ,
185+ ) ;
186+
187+ if crate :: shared:: set_sparse_trie_spawn_fn ( spawn_fn) . is_err ( ) {
188+ tracing:: warn!(
189+ "Sparse-trie spawner already registered, keeping existing one"
190+ ) ;
191+ } else {
192+ info ! (
193+ "Sparse-trie state-root spawner registered \
194+ (use_sparse_trie_state_root=true, triedb=inactive)"
195+ ) ;
196+ }
197+ }
198+
114199 // Skip mining setup if disabled
115200 if !mining_config. is_mining_enabled ( ) {
116201 info ! ( "Mining is disabled in configuration" ) ;
0 commit comments