@@ -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
@@ -185,18 +199,18 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
185199 parent = sim .base
186200 )
187201 for bi , block := range blocks {
188- result , callResults , err := sim .processBlock (ctx , & block , headers [bi ], parent , headers [:bi ], timeout )
202+ result , callResults , senders , err := sim .processBlock (ctx , & block , headers [bi ], parent , headers [:bi ], timeout )
189203 if err != nil {
190204 return nil , err
191205 }
192206 headers [bi ] = result .Header ()
193- results [bi ] = & simBlockResult {fullTx : sim .fullTx , chainConfig : sim .chainConfig , Block : result , Calls : callResults }
207+ results [bi ] = & simBlockResult {fullTx : sim .fullTx , chainConfig : sim .chainConfig , Block : result , Calls : callResults , senders : senders }
194208 parent = result .Header ()
195209 }
196210 return results , nil
197211}
198212
199- func (sim * simulator ) processBlock (ctx context.Context , block * simBlock , header , parent * types.Header , headers []* types.Header , timeout time.Duration ) (* types.Block , []simCallResult , error ) {
213+ 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 ) {
200214 // Set header fields that depend only on parent block.
201215 // Parent hash is needed for evm.GetHashFn to work.
202216 header .ParentHash = parent .Hash ()
@@ -226,7 +240,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
226240 precompiles := sim .activePrecompiles (sim .base )
227241 // State overrides are applied prior to execution of a block
228242 if err := block .StateOverrides .Apply (sim .state , precompiles ); err != nil {
229- return nil , nil , err
243+ return nil , nil , nil , err
230244 }
231245 var (
232246 gasUsed , blobGasUsed uint64
@@ -239,6 +253,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
239253 NoBaseFee : ! sim .validate ,
240254 Tracer : tracer .Hooks (),
241255 }
256+ // senders is a map of transaction hashes to their senders.
257+ // Transaction objects contain only the signature, and we lose track
258+ // of the sender when translating the arguments into a transaction object.
259+ senders = make (map [common.Hash ]common.Address )
242260 )
243261 tracingStateDB := vm .StateDB (sim .state )
244262 if hooks := tracer .Hooks (); hooks != nil {
@@ -259,24 +277,25 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
259277 var allLogs []* types.Log
260278 for i , call := range block .Calls {
261279 if err := ctx .Err (); err != nil {
262- return nil , nil , err
280+ return nil , nil , nil , err
263281 }
264282 if err := sim .sanitizeCall (& call , sim .state , header , blockContext , & gasUsed ); err != nil {
265- return nil , nil , err
283+ return nil , nil , nil , err
266284 }
267285 var (
268286 tx = call .ToTransaction (types .DynamicFeeTxType )
269287 txHash = tx .Hash ()
270288 )
271289 txes [i ] = tx
290+ senders [txHash ] = call .from ()
272291 tracer .reset (txHash , uint (i ))
273292 sim .state .SetTxContext (txHash , i )
274293 // EoA check is always skipped, even in validation mode.
275294 msg := call .ToMessage (header .BaseFee , ! sim .validate , true )
276295 result , err := applyMessageWithEVM (ctx , evm , msg , timeout , sim .gp )
277296 if err != nil {
278297 txErr := txValidationError (err )
279- return nil , nil , txErr
298+ return nil , nil , nil , txErr
280299 }
281300 // Update the state with pending changes.
282301 var root []byte
@@ -315,15 +334,15 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
315334 requests = [][]byte {}
316335 // EIP-6110
317336 if err := core .ParseDepositLogs (& requests , allLogs , sim .chainConfig ); err != nil {
318- return nil , nil , err
337+ return nil , nil , nil , err
319338 }
320339 // EIP-7002
321340 if err := core .ProcessWithdrawalQueue (& requests , evm ); err != nil {
322- return nil , nil , err
341+ return nil , nil , nil , err
323342 }
324343 // EIP-7251
325344 if err := core .ProcessConsolidationQueue (& requests , evm ); err != nil {
326- return nil , nil , err
345+ return nil , nil , nil , err
327346 }
328347 }
329348 if requests != nil {
@@ -334,10 +353,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
334353 chainHeadReader := & simChainHeadReader {ctx , sim .b }
335354 b , err := sim .b .Engine ().FinalizeAndAssemble (chainHeadReader , header , sim .state , blockBody , receipts )
336355 if err != nil {
337- return nil , nil , err
356+ return nil , nil , nil , err
338357 }
339358 repairLogs (callResults , b .Hash ())
340- return b , callResults , nil
359+ return b , callResults , senders , nil
341360}
342361
343362// repairLogs updates the block hash in the logs present in the result of
0 commit comments