@@ -78,11 +78,25 @@ type simBlockResult struct {
7878 chainConfig * params.ChainConfig
7979 Block * types.Block
8080 Calls []simCallResult
81+ // senders is a map of transaction hashes to their senders.
82+ senders map [common.Hash ]common.Address
8183}
8284
8385func (r * simBlockResult ) MarshalJSON () ([]byte , error ) {
8486 blockData := RPCMarshalBlock (r .Block , true , r .fullTx , r .chainConfig )
8587 blockData ["calls" ] = r .Calls
88+ // Set tx sender if user requested full tx objects.
89+ if r .fullTx {
90+ if raw , ok := blockData ["transactions" ].([]any ); ok {
91+ for _ , tx := range raw {
92+ if tx , ok := tx .(* RPCTransaction ); ok {
93+ tx .From = r .senders [tx .Hash ]
94+ } else {
95+ return nil , errors .New ("simulated transaction result has invalid type" )
96+ }
97+ }
98+ }
99+ }
86100 return json .Marshal (blockData )
87101}
88102
@@ -181,18 +195,18 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
181195 parent = sim .base
182196 )
183197 for bi , block := range blocks {
184- result , callResults , err := sim .processBlock (ctx , & block , headers [bi ], parent , headers [:bi ], timeout )
198+ result , callResults , senders , err := sim .processBlock (ctx , & block , headers [bi ], parent , headers [:bi ], timeout )
185199 if err != nil {
186200 return nil , err
187201 }
188202 headers [bi ] = result .Header ()
189- results [bi ] = & simBlockResult {fullTx : sim .fullTx , chainConfig : sim .chainConfig , Block : result , Calls : callResults }
203+ results [bi ] = & simBlockResult {fullTx : sim .fullTx , chainConfig : sim .chainConfig , Block : result , Calls : callResults , senders : senders }
190204 parent = result .Header ()
191205 }
192206 return results , nil
193207}
194208
195- func (sim * simulator ) processBlock (ctx context.Context , block * simBlock , header , parent * types.Header , headers []* types.Header , timeout time.Duration ) (* types.Block , []simCallResult , error ) {
209+ func (sim * simulator ) processBlock (ctx context.Context , block * simBlock , header , parent * types.Header , headers []* types.Header , timeout time.Duration ) (* types.Block , []simCallResult , map [common. Hash ]common. Address , error ) {
196210 // Set header fields that depend only on parent block.
197211 // Parent hash is needed for evm.GetHashFn to work.
198212 header .ParentHash = parent .Hash ()
@@ -222,7 +236,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
222236 precompiles := sim .activePrecompiles (sim .base )
223237 // State overrides are applied prior to execution of a block
224238 if err := block .StateOverrides .Apply (sim .state , precompiles ); err != nil {
225- return nil , nil , err
239+ return nil , nil , nil , err
226240 }
227241 var (
228242 gasUsed , blobGasUsed uint64
@@ -235,6 +249,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
235249 NoBaseFee : ! sim .validate ,
236250 Tracer : tracer .Hooks (),
237251 }
252+ // senders is a map of transaction hashes to their senders.
253+ // Transaction objects contain only the signature, and we lose track
254+ // of the sender when translating the arguments into a transaction object.
255+ senders = make (map [common.Hash ]common.Address )
238256 )
239257 tracingStateDB := vm .StateDB (sim .state )
240258 if hooks := tracer .Hooks (); hooks != nil {
@@ -255,24 +273,25 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
255273 var allLogs []* types.Log
256274 for i , call := range block .Calls {
257275 if err := ctx .Err (); err != nil {
258- return nil , nil , err
276+ return nil , nil , nil , err
259277 }
260278 if err := sim .sanitizeCall (& call , sim .state , header , blockContext , & gasUsed ); err != nil {
261- return nil , nil , err
279+ return nil , nil , nil , err
262280 }
263281 var (
264282 tx = call .ToTransaction (types .DynamicFeeTxType )
265283 txHash = tx .Hash ()
266284 )
267285 txes [i ] = tx
286+ senders [txHash ] = call .from ()
268287 tracer .reset (txHash , uint (i ))
269288 sim .state .SetTxContext (txHash , i )
270289 // EoA check is always skipped, even in validation mode.
271290 msg := call .ToMessage (header .BaseFee , ! sim .validate , true )
272291 result , err := applyMessageWithEVM (ctx , evm , msg , timeout , sim .gp )
273292 if err != nil {
274293 txErr := txValidationError (err )
275- return nil , nil , txErr
294+ return nil , nil , nil , txErr
276295 }
277296 // Update the state with pending changes.
278297 var root []byte
@@ -311,15 +330,15 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
311330 requests = [][]byte {}
312331 // EIP-6110
313332 if err := core .ParseDepositLogs (& requests , allLogs , sim .chainConfig ); err != nil {
314- return nil , nil , err
333+ return nil , nil , nil , err
315334 }
316335 // EIP-7002
317336 if err := core .ProcessWithdrawalQueue (& requests , evm ); err != nil {
318- return nil , nil , err
337+ return nil , nil , nil , err
319338 }
320339 // EIP-7251
321340 if err := core .ProcessConsolidationQueue (& requests , evm ); err != nil {
322- return nil , nil , err
341+ return nil , nil , nil , err
323342 }
324343 }
325344 if requests != nil {
@@ -330,10 +349,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
330349 chainHeadReader := & simChainHeadReader {ctx , sim .b }
331350 b , err := sim .b .Engine ().FinalizeAndAssemble (chainHeadReader , header , sim .state , blockBody , receipts )
332351 if err != nil {
333- return nil , nil , err
352+ return nil , nil , nil , err
334353 }
335354 repairLogs (callResults , b .Hash ())
336- return b , callResults , nil
355+ return b , callResults , senders , nil
337356}
338357
339358// repairLogs updates the block hash in the logs present in the result of
0 commit comments