1313//  You should have received a copy of the GNU General Public License
1414//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
1515
16+ #include  < category/core/assert.h> 
1617#include  < category/core/bytes.hpp> 
1718#include  < category/core/config.hpp> 
19+ #include  < category/core/int.hpp> 
1820#include  < category/core/keccak.hpp> 
1921#include  < category/core/result.hpp> 
22+ #include  < category/execution/ethereum/core/account.hpp> 
2023#include  < category/execution/ethereum/core/address.hpp> 
2124#include  < category/execution/ethereum/core/eth_ctypes.h> 
2225#include  < category/execution/ethereum/core/rlp/transaction_rlp.hpp> 
2528#include  < category/execution/ethereum/event/exec_event_recorder.hpp> 
2629#include  < category/execution/ethereum/event/record_txn_events.hpp> 
2730#include  < category/execution/ethereum/execute_transaction.hpp> 
31+ #include  < category/execution/ethereum/state3/account_state.hpp> 
32+ #include  < category/execution/ethereum/state3/state.hpp> 
33+ #include  < category/execution/ethereum/state3/version_stack.hpp> 
2834#include  < category/execution/ethereum/trace/call_frame.hpp> 
2935#include  < category/execution/ethereum/validate_transaction.hpp> 
3036
3137#include  < bit> 
38+ #include  < cstddef> 
3239#include  < cstdint> 
40+ #include  < memory> 
3341#include  < optional> 
3442#include  < span> 
3543#include  < utility> 
@@ -66,6 +74,209 @@ void init_txn_header_start(
6674        static_cast <uint32_t >(txn.authorization_list .size ());
6775}
6876
77+ //  Tracks information about an accessed account, including (1) the prestate and
78+ //  the (2) the modified state if a write access modified anything, with helper
79+ //  functions to determine what was modified
80+ struct  AccountAccessInfo 
81+ {
82+     Address const  *address;
83+     OriginalAccountState const  *prestate; //  State as it existed in original
84+     AccountState const  *modified_state; //  Last state as it existed in current
85+ 
86+     bool  is_read_only_access () const 
87+     {
88+         return  modified_state == nullptr ;
89+     }
90+ 
91+     std::pair<uint64_t , bool > get_nonce_modification () const 
92+     {
93+         if  (is_read_only_access ()) {
94+             return  {0 , false };
95+         }
96+         uint64_t  const  prestate_nonce =
97+             is_dead (prestate->account_ ) ? 0  : prestate->account_ ->nonce ;
98+         uint64_t  const  modified_nonce = is_dead (modified_state->account_ )
99+                                             ? 0 
100+                                             : modified_state->account_ ->nonce ;
101+         return  {modified_nonce, prestate_nonce != modified_nonce};
102+     }
103+ 
104+     std::pair<uint256_t , bool > get_balance_modification () const 
105+     {
106+         if  (is_read_only_access ()) {
107+             return  {0 , false };
108+         }
109+ 
110+         uint256_t  const  prestate_balance =
111+             is_dead (prestate->account_ ) ? 0  : prestate->account_ ->balance ;
112+         uint256_t  const  modified_balance =
113+             is_dead (modified_state->account_ )
114+                 ? 0 
115+                 : modified_state->account_ ->balance ;
116+         return  {modified_balance, prestate_balance != modified_balance};
117+     }
118+ };
119+ 
120+ // / Reserves either a block-level or transaction-level event, depending on
121+ // / whether opt_txn_num is set or not; the account access events are allocated
122+ // / this way, as some of them occur at system scope
123+ template  <typename  T>
124+ ReservedExecEvent<T> reserve_event (
125+     ExecutionEventRecorder *exec_recorder, monad_exec_event_type event_type,
126+     std::optional<uint32_t > opt_txn_num)
127+ {
128+     return  opt_txn_num
129+                ? exec_recorder->reserve_txn_event <T>(event_type, *opt_txn_num)
130+                : exec_recorder->reserve_block_event <T>(event_type);
131+ }
132+ 
133+ //  Records a MONAD_EXEC_STORAGE_ACCESS event for all reads and writes in the
134+ //  AccountState prestate and modified maps
135+ void  record_storage_events (
136+     ExecutionEventRecorder *exec_recorder,
137+     monad_exec_account_access_context ctx, std::optional<uint32_t > opt_txn_num,
138+     uint32_t  account_index, Address const  *address,
139+     AccountState::Map<bytes32_t , bytes32_t > const  *prestate_storage,
140+     AccountState::Map<bytes32_t , bytes32_t > const  *modified_storage,
141+     bool  is_transient)
142+ {
143+     for  (size_t  index = 0 ; auto  const  &[key, value] : *prestate_storage) {
144+         bool  is_modified = false ;
145+         bytes32_t  end_value = {};
146+ 
147+         if  (modified_storage) {
148+             if  (auto  const  i = modified_storage->find (key);
149+                 i != end (*modified_storage)) {
150+                 end_value = i->second ;
151+                 is_modified = end_value != value;
152+             }
153+         }
154+ 
155+         ReservedExecEvent const  storage_access =
156+             reserve_event<monad_exec_storage_access>(
157+                 exec_recorder, MONAD_EXEC_STORAGE_ACCESS, opt_txn_num);
158+         *storage_access.payload  = monad_exec_storage_access{
159+             .address  = *address,
160+             .index  = static_cast <uint32_t >(index),
161+             .access_context  = ctx,
162+             .modified  = is_modified,
163+             .transient  = is_transient,
164+             .key  = key,
165+             .start_value  = value,
166+             .end_value  = end_value,
167+         };
168+         storage_access.event ->content_ext [MONAD_FLOW_ACCOUNT_INDEX] =
169+             account_index;
170+         exec_recorder->commit (storage_access);
171+         ++index;
172+     }
173+ }
174+ 
175+ //  Records an MONAD_EXEC_ACCOUNT_ACCESS event, and delegates to
176+ //  record_storage_events to record both the ordinary and transient storage
177+ //  accesses
178+ void  record_account_events (
179+     ExecutionEventRecorder *exec_recorder,
180+     monad_exec_account_access_context ctx, std::optional<uint32_t > opt_txn_num,
181+     uint32_t  index, AccountAccessInfo const  &account_info)
182+ {
183+     MONAD_ASSERT (account_info.prestate );
184+     monad_c_eth_account_state initial_state;
185+     Account const  &account = is_dead (account_info.prestate ->account_ )
186+                                  ? Account{}
187+                                  : *account_info.prestate ->account_ ;
188+ 
189+     initial_state.nonce  = account.nonce ;
190+     initial_state.balance  = account.balance ;
191+     initial_state.code_hash  = account.code_hash ;
192+ 
193+     auto  const  [modified_balance, is_balance_modified] =
194+         account_info.get_balance_modification ();
195+     auto  const  [modified_nonce, is_nonce_modified] =
196+         account_info.get_nonce_modification ();
197+ 
198+     ReservedExecEvent const  account_access =
199+         reserve_event<monad_exec_account_access>(
200+             exec_recorder, MONAD_EXEC_ACCOUNT_ACCESS, opt_txn_num);
201+     *account_access.payload  = monad_exec_account_access{
202+         .index  = index,
203+         .address  = *account_info.address ,
204+         .access_context  = ctx,
205+         .is_balance_modified  = is_balance_modified,
206+         .is_nonce_modified  = is_nonce_modified,
207+         .prestate  = initial_state,
208+         .modified_balance  = modified_balance,
209+         .modified_nonce  = modified_nonce,
210+         .storage_key_count  =
211+             static_cast <uint32_t >(size (account_info.prestate ->storage_ )),
212+         .transient_count  = static_cast <uint32_t >(
213+             size (account_info.prestate ->transient_storage_ ))};
214+     exec_recorder->commit (account_access);
215+ 
216+     auto  const  *const  post_state_storage_map =
217+         account_info.is_read_only_access ()
218+             ? nullptr 
219+             : &account_info.modified_state ->storage_ ;
220+     record_storage_events (
221+         exec_recorder,
222+         ctx,
223+         opt_txn_num,
224+         index,
225+         account_info.address ,
226+         &account_info.prestate ->storage_ ,
227+         post_state_storage_map,
228+         false );
229+ 
230+     auto  const  *const  post_state_transient_map =
231+         account_info.is_read_only_access ()
232+             ? nullptr 
233+             : &account_info.modified_state ->transient_storage_ ;
234+     record_storage_events (
235+         exec_recorder,
236+         ctx,
237+         opt_txn_num,
238+         index,
239+         account_info.address ,
240+         &account_info.prestate ->transient_storage_ ,
241+         post_state_transient_map,
242+         true );
243+ }
244+ 
245+ //  Function that records all state accesses and changes that occurred in some
246+ //  scope, either the block prologue, block epilogue, or in the scope of some
247+ //  transaction
248+ void  record_account_access_events_internal (
249+     ExecutionEventRecorder *exec_recorder,
250+     monad_exec_account_access_context ctx, std::optional<uint32_t > opt_txn_num,
251+     State const  &state)
252+ {
253+     auto  const  &prestate_map = state.original ();
254+ 
255+     ReservedExecEvent const  list_header =
256+         reserve_event<monad_exec_account_access_list_header>(
257+             exec_recorder, MONAD_EXEC_ACCOUNT_ACCESS_LIST_HEADER, opt_txn_num);
258+     *list_header.payload  = monad_exec_account_access_list_header{
259+         .entry_count  = static_cast <uint32_t >(prestate_map.size ()),
260+         .access_context  = ctx};
261+     exec_recorder->commit (list_header);
262+ 
263+     auto  const  ¤t_state_map = state.current ();
264+     for  (uint32_t  index = 0 ; auto  const  &[address, prestate] : prestate_map) {
265+         AccountState const  *current_state = nullptr ;
266+         if  (auto  const  i = current_state_map.find (address);
267+             i != end (current_state_map)) {
268+             current_state = std::addressof (i->second .recent ());
269+         }
270+         record_account_events (
271+             exec_recorder,
272+             ctx,
273+             opt_txn_num,
274+             index,
275+             AccountAccessInfo{&address, &prestate, current_state});
276+         index++;
277+     }
278+ }
279+ 
69280MONAD_ANONYMOUS_NAMESPACE_END
70281
71282MONAD_NAMESPACE_BEGIN
@@ -74,7 +285,7 @@ void record_txn_events(
74285    uint32_t  txn_num, Transaction const  &transaction, Address const  &sender,
75286    std::span<std::optional<Address> const > authorities,
76287    Result<Receipt> const  &receipt_result,
77-     std::span<CallFrame const > const  call_frames)
288+     std::span<CallFrame const > const  call_frames, State  const  &txn_state )
78289{
79290    ExecutionEventRecorder *const  exec_recorder = g_exec_event_recorder.get ();
80291    if  (exec_recorder == nullptr ) {
@@ -223,7 +434,23 @@ void record_txn_events(
223434        ++index;
224435    }
225436
437+     //  Account access records for the transaction
438+     record_account_access_events_internal (
439+         exec_recorder, MONAD_ACCT_ACCESS_TRANSACTION, txn_num, txn_state);
440+ 
226441    exec_recorder->record_txn_marker_event (MONAD_EXEC_TXN_END, txn_num);
227442}
228443
444+ //  The externally-visible wrapper of the account-access-recording function that
445+ //  is called from execute_block.cpp, to record prologue and epilogue accesses;
446+ //  transaction-scope state accesses use record_txn_exec_result_events instead
447+ void  record_account_access_events (
448+     monad_exec_account_access_context ctx, State const  &state)
449+ {
450+     if  (ExecutionEventRecorder *const  e = g_exec_event_recorder.get ()) {
451+         return  record_account_access_events_internal (
452+             e, ctx, std::nullopt , state);
453+     }
454+ }
455+ 
229456MONAD_NAMESPACE_END
0 commit comments