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 );
@@ -292,73 +325,35 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
292325 bytes32_t parent_block_id{};
293326 uint64_t block_num = finalized_block_num;
294327
295- std::optional<ankerl::unordered_dense::segmented_set<Address>>
296- parent_senders_and_authorities;
297- std::optional<ankerl::unordered_dense::segmented_set<Address>>
298- grandparent_senders_and_authorities;
328+ std::
329+ array<std::optional<ankerl::unordered_dense::segmented_set<Address>>, 3 >
330+ block_senders_and_authorities;
299331
300332 if (block_num > 1 ) {
301333 Block parent_block;
302334 MONAD_ASSERT_PRINTF (
303335 block_db.get (block_num - 1 , parent_block),
304336 " Could not query %lu from blockdb for parent" ,
305337 block_num - 1 );
306- auto const recovered_senders =
307- recover_senders (parent_block.transactions , priority_pool);
308- auto const recovered_authorities =
309- recover_authorities (parent_block.transactions , priority_pool);
310- std::vector<Address> senders (parent_block.transactions .size ());
311- for (unsigned j = 0 ; j < recovered_senders.size (); ++j) {
312- if (recovered_senders[j].has_value ()) {
313- senders[j] = recovered_senders[j].value ();
314- }
315- }
316- ankerl::unordered_dense::segmented_set<Address> parent_set;
317- for (Address const &sender : senders) {
318- parent_set.insert (sender);
319- }
320- for (std::vector<std::optional<Address>> const &authorities :
321- recovered_authorities) {
322- for (std::optional<Address> const &authority : authorities) {
323- if (authority.has_value ()) {
324- parent_set.insert (authority.value ());
325- }
326- }
327- }
328- parent_senders_and_authorities = std::move (parent_set);
338+ BOOST_OUTCOME_TRY (
339+ auto const parent_recovered,
340+ recover_senders_and_authorities (
341+ parent_block.transactions , priority_pool, false ));
342+ block_senders_and_authorities[(block_num - 1 ) % 3 ] =
343+ std::move (parent_recovered.senders_and_authorities );
329344
330345 if (block_num > 2 ) {
331346 Block grandparent_block;
332347 MONAD_ASSERT_PRINTF (
333348 block_db.get (block_num - 2 , grandparent_block),
334349 " Could not query %lu from blockdb for grandparent" ,
335350 block_num - 2 );
336- auto const grandparent_recovered_senders =
337- recover_senders (grandparent_block.transactions , priority_pool);
338- auto const grandparent_recovered_authorities = recover_authorities (
339- grandparent_block.transactions , priority_pool);
340- std::vector<Address> grandparent_senders (
341- grandparent_block.transactions .size ());
342- for (unsigned j = 0 ; j < grandparent_recovered_senders.size ();
343- ++j) {
344- if (grandparent_recovered_senders[j].has_value ()) {
345- grandparent_senders[j] =
346- grandparent_recovered_senders[j].value ();
347- }
348- }
349- ankerl::unordered_dense::segmented_set<Address> grandparent_set;
350- for (Address const &sender : grandparent_senders) {
351- grandparent_set.insert (sender);
352- }
353- for (std::vector<std::optional<Address>> const &authorities :
354- grandparent_recovered_authorities) {
355- for (std::optional<Address> const &authority : authorities) {
356- if (authority.has_value ()) {
357- grandparent_set.insert (authority.value ());
358- }
359- }
360- }
361- grandparent_senders_and_authorities = std::move (grandparent_set);
351+ BOOST_OUTCOME_TRY (
352+ auto const grandparent_recovered,
353+ recover_senders_and_authorities (
354+ grandparent_block.transactions , priority_pool, false ));
355+ block_senders_and_authorities[(block_num - 2 ) % 3 ] =
356+ std::move (grandparent_recovered.senders_and_authorities );
362357 }
363358 }
364359
@@ -386,12 +381,8 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
386381 block_id,
387382 parent_block_id,
388383 enable_tracing,
389- grandparent_senders_and_authorities.has_value ()
390- ? &grandparent_senders_and_authorities.value ()
391- : nullptr ,
392- parent_senders_and_authorities.has_value ()
393- ? &parent_senders_and_authorities.value ()
394- : nullptr ,
384+ block_num,
385+ block_senders_and_authorities,
395386 senders_and_authorities);
396387 MONAD_ABORT_PRINTF (" unhandled rev switch case: %d" , rev);
397388 }());
@@ -415,9 +406,8 @@ Result<std::pair<uint64_t, uint64_t>> runloop_monad_ethblocks(
415406 batch_begin = std::chrono::steady_clock::now ();
416407 }
417408
418- grandparent_senders_and_authorities =
419- std::move (parent_senders_and_authorities);
420- parent_senders_and_authorities = std::move (senders_and_authorities);
409+ block_senders_and_authorities[block_num % 3 ] =
410+ std::move (senders_and_authorities);
421411
422412 parent_block_id = block_id;
423413 ++block_num;
0 commit comments