4444#include < quill/Quill.h>
4545
4646#include < algorithm>
47+ #include < array>
4748#include < chrono>
4849#include < memory>
4950#include < optional>
@@ -81,17 +82,61 @@ void log_tps(
8182
8283#pragma GCC diagnostic pop
8384
85+ struct RecoveredSendersAndAuthorities
86+ {
87+ std::vector<Address> senders;
88+ ankerl::unordered_dense::segmented_set<Address> senders_and_authorities;
89+ std::vector<std::vector<std::optional<Address>>> authorities;
90+ };
91+
92+ // Recover senders and authorities from a block
93+ Result<RecoveredSendersAndAuthorities> recover_senders_and_authorities (
94+ std::vector<Transaction> const &transactions,
95+ fiber::PriorityPool &priority_pool, bool require_all_senders)
96+ {
97+ auto const recovered_senders = recover_senders (transactions, priority_pool);
98+ auto const recovered_authorities =
99+ recover_authorities (transactions, priority_pool);
100+ std::vector<Address> senders (transactions.size ());
101+ for (unsigned i = 0 ; i < recovered_senders.size (); ++i) {
102+ if (recovered_senders[i].has_value ()) {
103+ senders[i] = recovered_senders[i].value ();
104+ }
105+ else if (require_all_senders) {
106+ return TransactionError::MissingSender;
107+ }
108+ }
109+ ankerl::unordered_dense::segmented_set<Address> senders_and_authorities;
110+ for (unsigned i = 0 ; i < recovered_senders.size (); ++i) {
111+ if (recovered_senders[i].has_value ()) {
112+ senders_and_authorities.insert (recovered_senders[i].value ());
113+ }
114+ }
115+ for (std::vector<std::optional<Address>> const &authorities :
116+ recovered_authorities) {
117+ for (std::optional<Address> const &authority : authorities) {
118+ if (authority.has_value ()) {
119+ senders_and_authorities.insert (authority.value ());
120+ }
121+ }
122+ }
123+ return RecoveredSendersAndAuthorities{
124+ .senders = std::move (senders),
125+ .senders_and_authorities = std::move (senders_and_authorities),
126+ .authorities = std::move (recovered_authorities)};
127+ }
128+
84129// Process a single Monad block stored in Ethereum format
85130template <Traits traits>
86131Result<void > process_monad_block (
87132 MonadChain const &chain, Db &db, vm::VM &vm,
88133 BlockHashBufferFinalized &block_hash_buffer,
89134 fiber::PriorityPool &priority_pool, Block &block, bytes32_t const &block_id,
90135 bytes32_t const &parent_block_id, bool const enable_tracing,
91- ankerl::unordered_dense::segmented_set<Address> const
92- *grandparent_senders_and_authorities,
93- ankerl::unordered_dense::segmented_set<Address> const
94- *parent_senders_and_authorities ,
136+ uint64_t const block_num,
137+ std::array<
138+ std::optional< ankerl::unordered_dense::segmented_set<Address>>, 3 > const
139+ &block_senders_and_authorities ,
95140 ankerl::unordered_dense::segmented_set<Address>
96141 &senders_and_authorities_out)
97142{
@@ -104,36 +149,15 @@ Result<void> process_monad_block(
104149
105150 // Sender and authority recovery
106151 auto const sender_recovery_begin = std::chrono::steady_clock::now ();
107- auto const recovered_senders =
108- recover_senders (block. transactions , priority_pool);
109- auto const recovered_authorities =
110- recover_authorities ( block.transactions , priority_pool);
152+ BOOST_OUTCOME_TRY (
153+ auto const recovered,
154+ recover_senders_and_authorities (
155+ block.transactions , priority_pool, true ) );
111156 [[maybe_unused]] auto const sender_recovery_time =
112157 std::chrono::duration_cast<std::chrono::microseconds>(
113158 std::chrono::steady_clock::now () - sender_recovery_begin);
114- std::vector<Address> senders (block.transactions .size ());
115- for (unsigned i = 0 ; i < recovered_senders.size (); ++i) {
116- if (recovered_senders[i].has_value ()) {
117- senders[i] = recovered_senders[i].value ();
118- }
119- else {
120- return TransactionError::MissingSender;
121- }
122- }
123- ankerl::unordered_dense::segmented_set<Address> senders_and_authorities;
124- for (Address const &sender : senders) {
125- senders_and_authorities.insert (sender);
126- }
127- for (std::vector<std::optional<Address>> const &authorities :
128- recovered_authorities) {
129- for (std::optional<Address> const &authority : authorities) {
130- if (authority.has_value ()) {
131- senders_and_authorities.insert (authority.value ());
132- }
133- }
134- }
135- BOOST_OUTCOME_TRY (
136- static_validate_monad_body<traits>(senders, block.transactions ));
159+ BOOST_OUTCOME_TRY (static_validate_monad_body<traits>(
160+ recovered.senders , block.transactions ));
137161
138162 // Call tracer initialization
139163 std::vector<std::vector<CallFrame>> call_frames{block.transactions .size ()};
@@ -152,15 +176,24 @@ Result<void> process_monad_block(
152176 std::make_unique<trace::StateTracer>(std::monostate{})};
153177 }
154178
155- senders_and_authorities_out = senders_and_authorities;
179+ senders_and_authorities_out = recovered. senders_and_authorities ;
156180
181+ auto const grandparent_idx = (block_num - 2 ) % 3 ;
182+ auto const parent_idx = (block_num - 1 ) % 3 ;
157183 MonadChainContext chain_context{
158184 .grandparent_senders_and_authorities =
159- grandparent_senders_and_authorities,
160- .parent_senders_and_authorities = parent_senders_and_authorities,
161- .senders_and_authorities = senders_and_authorities,
162- .senders = senders,
163- .authorities = recovered_authorities};
185+ (block_num > 2 &&
186+ block_senders_and_authorities[grandparent_idx].has_value ())
187+ ? &block_senders_and_authorities[grandparent_idx].value ()
188+ : nullptr ,
189+ .parent_senders_and_authorities =
190+ (block_num > 1 &&
191+ block_senders_and_authorities[parent_idx].has_value ())
192+ ? &block_senders_and_authorities[parent_idx].value ()
193+ : nullptr ,
194+ .senders_and_authorities = recovered.senders_and_authorities ,
195+ .senders = recovered.senders ,
196+ .authorities = recovered.authorities };
164197
165198 // Core execution: transaction-level EVM execution that tracks state
166199 // changes but does not commit them
@@ -175,8 +208,8 @@ Result<void> process_monad_block(
175208 execute_block<traits>(
176209 chain,
177210 block,
178- senders,
179- recovered_authorities ,
211+ recovered. senders ,
212+ recovered. authorities ,
180213 block_state,
181214 block_hash_buffer,
182215 priority_pool.fiber_group (),
@@ -207,7 +240,7 @@ Result<void> process_monad_block(
207240 block.header ,
208241 receipts,
209242 call_frames,
210- senders,
243+ recovered. senders ,
211244 block.transactions ,
212245 block.ommers ,
213246 block.withdrawals );
@@ -293,73 +326,35 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
293326 bytes32_t parent_block_id{};
294327 uint64_t block_num = finalized_block_num;
295328
296- std::optional<ankerl::unordered_dense::segmented_set<Address>>
297- parent_senders_and_authorities;
298- std::optional<ankerl::unordered_dense::segmented_set<Address>>
299- grandparent_senders_and_authorities;
329+ std::
330+ array<std::optional<ankerl::unordered_dense::segmented_set<Address>>, 3 >
331+ block_senders_and_authorities;
300332
301333 if (block_num > 1 ) {
302334 Block parent_block;
303335 MONAD_ASSERT_PRINTF (
304336 block_db.get (block_num - 1 , parent_block),
305337 " Could not query %lu from blockdb for parent" ,
306338 block_num - 1 );
307- auto const recovered_senders =
308- recover_senders (parent_block.transactions , priority_pool);
309- auto const recovered_authorities =
310- recover_authorities (parent_block.transactions , priority_pool);
311- std::vector<Address> senders (parent_block.transactions .size ());
312- for (unsigned j = 0 ; j < recovered_senders.size (); ++j) {
313- if (recovered_senders[j].has_value ()) {
314- senders[j] = recovered_senders[j].value ();
315- }
316- }
317- ankerl::unordered_dense::segmented_set<Address> parent_set;
318- for (Address const &sender : senders) {
319- parent_set.insert (sender);
320- }
321- for (std::vector<std::optional<Address>> const &authorities :
322- recovered_authorities) {
323- for (std::optional<Address> const &authority : authorities) {
324- if (authority.has_value ()) {
325- parent_set.insert (authority.value ());
326- }
327- }
328- }
329- parent_senders_and_authorities = std::move (parent_set);
339+ BOOST_OUTCOME_TRY (
340+ auto const parent_recovered,
341+ recover_senders_and_authorities (
342+ parent_block.transactions , priority_pool, false ));
343+ block_senders_and_authorities[(block_num - 1 ) % 3 ] =
344+ std::move (parent_recovered.senders_and_authorities );
330345
331346 if (block_num > 2 ) {
332347 Block grandparent_block;
333348 MONAD_ASSERT_PRINTF (
334349 block_db.get (block_num - 2 , grandparent_block),
335350 " Could not query %lu from blockdb for grandparent" ,
336351 block_num - 2 );
337- auto const grandparent_recovered_senders =
338- recover_senders (grandparent_block.transactions , priority_pool);
339- auto const grandparent_recovered_authorities = recover_authorities (
340- grandparent_block.transactions , priority_pool);
341- std::vector<Address> grandparent_senders (
342- grandparent_block.transactions .size ());
343- for (unsigned j = 0 ; j < grandparent_recovered_senders.size ();
344- ++j) {
345- if (grandparent_recovered_senders[j].has_value ()) {
346- grandparent_senders[j] =
347- grandparent_recovered_senders[j].value ();
348- }
349- }
350- ankerl::unordered_dense::segmented_set<Address> grandparent_set;
351- for (Address const &sender : grandparent_senders) {
352- grandparent_set.insert (sender);
353- }
354- for (std::vector<std::optional<Address>> const &authorities :
355- grandparent_recovered_authorities) {
356- for (std::optional<Address> const &authority : authorities) {
357- if (authority.has_value ()) {
358- grandparent_set.insert (authority.value ());
359- }
360- }
361- }
362- grandparent_senders_and_authorities = std::move (grandparent_set);
352+ BOOST_OUTCOME_TRY (
353+ auto const grandparent_recovered,
354+ recover_senders_and_authorities (
355+ grandparent_block.transactions , priority_pool, false ));
356+ block_senders_and_authorities[(block_num - 2 ) % 3 ] =
357+ std::move (grandparent_recovered.senders_and_authorities );
363358 }
364359 }
365360
@@ -387,12 +382,8 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
387382 block_id,
388383 parent_block_id,
389384 enable_tracing,
390- grandparent_senders_and_authorities.has_value ()
391- ? &grandparent_senders_and_authorities.value ()
392- : nullptr ,
393- parent_senders_and_authorities.has_value ()
394- ? &parent_senders_and_authorities.value ()
395- : nullptr ,
385+ block_num,
386+ block_senders_and_authorities,
396387 senders_and_authorities);
397388 MONAD_ABORT_PRINTF (" unhandled rev switch case: %d" , rev);
398389 }());
@@ -416,9 +407,8 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
416407 batch_begin = std::chrono::steady_clock::now ();
417408 }
418409
419- grandparent_senders_and_authorities =
420- std::move (parent_senders_and_authorities);
421- parent_senders_and_authorities = std::move (senders_and_authorities);
410+ block_senders_and_authorities[block_num % 3 ] =
411+ std::move (senders_and_authorities);
422412
423413 parent_block_id = block_id;
424414 ++block_num;
0 commit comments