@@ -20,6 +20,7 @@ import (
20
20
"bytes"
21
21
"context"
22
22
"crypto/ecdsa"
23
+ "encoding/json"
23
24
"errors"
24
25
"fmt"
25
26
"math/big"
@@ -198,7 +199,7 @@ func TestTraceCall(t *testing.T) {
198
199
var testSuite = []struct {
199
200
blockNumber rpc.BlockNumber
200
201
call ethapi.CallArgs
201
- config * TraceConfig
202
+ config * TraceCallConfig
202
203
expectErr error
203
204
expect interface {}
204
205
}{
@@ -305,6 +306,147 @@ func TestTraceCall(t *testing.T) {
305
306
}
306
307
}
307
308
309
+ func TestOverridenTraceCall (t * testing.T ) {
310
+ t .Parallel ()
311
+
312
+ // Initialize test accounts
313
+ accounts := newAccounts (3 )
314
+ genesis := & core.Genesis {Alloc : core.GenesisAlloc {
315
+ accounts [0 ].addr : {Balance : big .NewInt (params .Ether )},
316
+ accounts [1 ].addr : {Balance : big .NewInt (params .Ether )},
317
+ accounts [2 ].addr : {Balance : big .NewInt (params .Ether )},
318
+ }}
319
+ genBlocks := 10
320
+ signer := types.HomesteadSigner {}
321
+ api := NewAPI (newTestBackend (t , genBlocks , genesis , func (i int , b * core.BlockGen ) {
322
+ // Transfer from account[0] to account[1]
323
+ // value: 1000 wei
324
+ // fee: 0 wei
325
+ tx , _ := types .SignTx (types .NewTransaction (uint64 (i ), accounts [1 ].addr , big .NewInt (1000 ), params .TxGas , big .NewInt (0 ), nil ), signer , accounts [0 ].key )
326
+ b .AddTx (tx )
327
+ }))
328
+ randomAccounts , tracer := newAccounts (3 ), "callTracer"
329
+
330
+ var testSuite = []struct {
331
+ blockNumber rpc.BlockNumber
332
+ call ethapi.CallArgs
333
+ config * TraceCallConfig
334
+ expectErr error
335
+ expect * callTrace
336
+ }{
337
+ // Succcessful call with state overriding
338
+ {
339
+ blockNumber : rpc .PendingBlockNumber ,
340
+ call : ethapi.CallArgs {
341
+ From : & randomAccounts [0 ].addr ,
342
+ To : & randomAccounts [1 ].addr ,
343
+ Value : (* hexutil .Big )(big .NewInt (1000 )),
344
+ },
345
+ config : & TraceCallConfig {
346
+ Tracer : & tracer ,
347
+ StateOverrides : & ethapi.StateOverride {
348
+ randomAccounts [0 ].addr : ethapi.OverrideAccount {Balance : newRPCBalance (new (big.Int ).Mul (big .NewInt (1 ), big .NewInt (params .Ether )))},
349
+ },
350
+ },
351
+ expectErr : nil ,
352
+ expect : & callTrace {
353
+ Type : "CALL" ,
354
+ From : randomAccounts [0 ].addr ,
355
+ To : randomAccounts [1 ].addr ,
356
+ Gas : newRPCUint64 (24979000 ),
357
+ GasUsed : newRPCUint64 (0 ),
358
+ Value : (* hexutil .Big )(big .NewInt (1000 )),
359
+ },
360
+ },
361
+ // Invalid call without state overriding
362
+ {
363
+ blockNumber : rpc .PendingBlockNumber ,
364
+ call : ethapi.CallArgs {
365
+ From : & randomAccounts [0 ].addr ,
366
+ To : & randomAccounts [1 ].addr ,
367
+ Value : (* hexutil .Big )(big .NewInt (1000 )),
368
+ },
369
+ config : & TraceCallConfig {
370
+ Tracer : & tracer ,
371
+ },
372
+ expectErr : core .ErrInsufficientFundsForTransfer ,
373
+ expect : nil ,
374
+ },
375
+ // Sucessful simple contract call
376
+ //
377
+ // // SPDX-License-Identifier: GPL-3.0
378
+ //
379
+ // pragma solidity >=0.7.0 <0.8.0;
380
+ //
381
+ // /**
382
+ // * @title Storage
383
+ // * @dev Store & retrieve value in a variable
384
+ // */
385
+ // contract Storage {
386
+ // uint256 public number;
387
+ // constructor() {
388
+ // number = block.number;
389
+ // }
390
+ // }
391
+ {
392
+ blockNumber : rpc .PendingBlockNumber ,
393
+ call : ethapi.CallArgs {
394
+ From : & randomAccounts [0 ].addr ,
395
+ To : & randomAccounts [2 ].addr ,
396
+ Data : newRPCBytes (common .Hex2Bytes ("8381f58a" )), // call number()
397
+ },
398
+ config : & TraceCallConfig {
399
+ Tracer : & tracer ,
400
+ StateOverrides : & ethapi.StateOverride {
401
+ randomAccounts [2 ].addr : ethapi.OverrideAccount {
402
+ Code : newRPCBytes (common .Hex2Bytes ("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033" )),
403
+ StateDiff : newStates ([]common.Hash {{}}, []common.Hash {common .BigToHash (big .NewInt (123 ))}),
404
+ },
405
+ },
406
+ },
407
+ expectErr : nil ,
408
+ expect : & callTrace {
409
+ Type : "CALL" ,
410
+ From : randomAccounts [0 ].addr ,
411
+ To : randomAccounts [2 ].addr ,
412
+ Input : hexutil .Bytes (common .Hex2Bytes ("8381f58a" )),
413
+ Output : hexutil .Bytes (common .BigToHash (big .NewInt (123 )).Bytes ()),
414
+ Gas : newRPCUint64 (24978936 ),
415
+ GasUsed : newRPCUint64 (2283 ),
416
+ Value : (* hexutil .Big )(big .NewInt (0 )),
417
+ },
418
+ },
419
+ }
420
+ for _ , testspec := range testSuite {
421
+ result , err := api .TraceCall (context .Background (), testspec .call , rpc.BlockNumberOrHash {BlockNumber : & testspec .blockNumber }, testspec .config )
422
+ if testspec .expectErr != nil {
423
+ if err == nil {
424
+ t .Errorf ("Expect error %v, get nothing" , testspec .expectErr )
425
+ continue
426
+ }
427
+ if ! errors .Is (err , testspec .expectErr ) {
428
+ t .Errorf ("Error mismatch, want %v, get %v" , testspec .expectErr , err )
429
+ }
430
+ } else {
431
+ if err != nil {
432
+ t .Errorf ("Expect no error, get %v" , err )
433
+ continue
434
+ }
435
+ ret := new (callTrace )
436
+ if err := json .Unmarshal (result .(json.RawMessage ), ret ); err != nil {
437
+ t .Fatalf ("failed to unmarshal trace result: %v" , err )
438
+ }
439
+ if ! jsonEqual (ret , testspec .expect ) {
440
+ // uncomment this for easier debugging
441
+ //have, _ := json.MarshalIndent(ret, "", " ")
442
+ //want, _ := json.MarshalIndent(testspec.expect, "", " ")
443
+ //t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want))
444
+ t .Fatalf ("trace mismatch: \n have %+v\n want %+v" , ret , testspec .expect )
445
+ }
446
+ }
447
+ }
448
+ }
449
+
308
450
func TestTraceTransaction (t * testing.T ) {
309
451
t .Parallel ()
310
452
@@ -469,3 +611,29 @@ func newAccounts(n int) (accounts Accounts) {
469
611
sort .Sort (accounts )
470
612
return accounts
471
613
}
614
+
615
+ func newRPCBalance (balance * big.Int ) * * hexutil.Big {
616
+ rpcBalance := (* hexutil .Big )(balance )
617
+ return & rpcBalance
618
+ }
619
+
620
+ func newRPCUint64 (number uint64 ) * hexutil.Uint64 {
621
+ rpcUint64 := hexutil .Uint64 (number )
622
+ return & rpcUint64
623
+ }
624
+
625
+ func newRPCBytes (bytes []byte ) * hexutil.Bytes {
626
+ rpcBytes := hexutil .Bytes (bytes )
627
+ return & rpcBytes
628
+ }
629
+
630
+ func newStates (keys []common.Hash , vals []common.Hash ) * map [common.Hash ]common.Hash {
631
+ if len (keys ) != len (vals ) {
632
+ panic ("invalid input" )
633
+ }
634
+ m := make (map [common.Hash ]common.Hash )
635
+ for i := 0 ; i < len (keys ); i ++ {
636
+ m [keys [i ]] = vals [i ]
637
+ }
638
+ return & m
639
+ }
0 commit comments