@@ -78,11 +78,25 @@ type simBlockResult struct {
78
78
chainConfig * params.ChainConfig
79
79
Block * types.Block
80
80
Calls []simCallResult
81
+ // senders is a map of transaction hashes to their senders.
82
+ senders map [common.Hash ]common.Address
81
83
}
82
84
83
85
func (r * simBlockResult ) MarshalJSON () ([]byte , error ) {
84
86
blockData := RPCMarshalBlock (r .Block , true , r .fullTx , r .chainConfig )
85
87
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
+ }
86
100
return json .Marshal (blockData )
87
101
}
88
102
@@ -181,18 +195,18 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
181
195
parent = sim .base
182
196
)
183
197
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 )
185
199
if err != nil {
186
200
return nil , err
187
201
}
188
202
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 }
190
204
parent = result .Header ()
191
205
}
192
206
return results , nil
193
207
}
194
208
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 ) {
196
210
// Set header fields that depend only on parent block.
197
211
// Parent hash is needed for evm.GetHashFn to work.
198
212
header .ParentHash = parent .Hash ()
@@ -222,7 +236,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
222
236
precompiles := sim .activePrecompiles (sim .base )
223
237
// State overrides are applied prior to execution of a block
224
238
if err := block .StateOverrides .Apply (sim .state , precompiles ); err != nil {
225
- return nil , nil , err
239
+ return nil , nil , nil , err
226
240
}
227
241
var (
228
242
gasUsed , blobGasUsed uint64
@@ -235,6 +249,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
235
249
NoBaseFee : ! sim .validate ,
236
250
Tracer : tracer .Hooks (),
237
251
}
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 )
238
256
)
239
257
tracingStateDB := vm .StateDB (sim .state )
240
258
if hooks := tracer .Hooks (); hooks != nil {
@@ -255,24 +273,25 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
255
273
var allLogs []* types.Log
256
274
for i , call := range block .Calls {
257
275
if err := ctx .Err (); err != nil {
258
- return nil , nil , err
276
+ return nil , nil , nil , err
259
277
}
260
278
if err := sim .sanitizeCall (& call , sim .state , header , blockContext , & gasUsed ); err != nil {
261
- return nil , nil , err
279
+ return nil , nil , nil , err
262
280
}
263
281
var (
264
282
tx = call .ToTransaction (types .DynamicFeeTxType )
265
283
txHash = tx .Hash ()
266
284
)
267
285
txes [i ] = tx
286
+ senders [txHash ] = call .from ()
268
287
tracer .reset (txHash , uint (i ))
269
288
sim .state .SetTxContext (txHash , i )
270
289
// EoA check is always skipped, even in validation mode.
271
290
msg := call .ToMessage (header .BaseFee , ! sim .validate , true )
272
291
result , err := applyMessageWithEVM (ctx , evm , msg , timeout , sim .gp )
273
292
if err != nil {
274
293
txErr := txValidationError (err )
275
- return nil , nil , txErr
294
+ return nil , nil , nil , txErr
276
295
}
277
296
// Update the state with pending changes.
278
297
var root []byte
@@ -311,15 +330,15 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
311
330
requests = [][]byte {}
312
331
// EIP-6110
313
332
if err := core .ParseDepositLogs (& requests , allLogs , sim .chainConfig ); err != nil {
314
- return nil , nil , err
333
+ return nil , nil , nil , err
315
334
}
316
335
// EIP-7002
317
336
if err := core .ProcessWithdrawalQueue (& requests , evm ); err != nil {
318
- return nil , nil , err
337
+ return nil , nil , nil , err
319
338
}
320
339
// EIP-7251
321
340
if err := core .ProcessConsolidationQueue (& requests , evm ); err != nil {
322
- return nil , nil , err
341
+ return nil , nil , nil , err
323
342
}
324
343
}
325
344
if requests != nil {
@@ -330,10 +349,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
330
349
chainHeadReader := & simChainHeadReader {ctx , sim .b }
331
350
b , err := sim .b .Engine ().FinalizeAndAssemble (chainHeadReader , header , sim .state , blockBody , receipts )
332
351
if err != nil {
333
- return nil , nil , err
352
+ return nil , nil , nil , err
334
353
}
335
354
repairLogs (callResults , b .Hash ())
336
- return b , callResults , nil
355
+ return b , callResults , senders , nil
337
356
}
338
357
339
358
// repairLogs updates the block hash in the logs present in the result of
0 commit comments