@@ -743,7 +743,21 @@ type CallArgs struct {
743
743
Data * hexutil.Bytes `json:"data"`
744
744
}
745
745
746
- func DoCall (ctx context.Context , b Backend , args CallArgs , blockNr rpc.BlockNumber , vmCfg vm.Config , timeout time.Duration , globalGasCap * big.Int ) ([]byte , uint64 , bool , error ) {
746
+ // account indicates the overriding fields of account during the execution of
747
+ // a message call.
748
+ // Note, state and stateDiff can't be specified at the same time. If state is
749
+ // set, message execution will only use the data in the given state. Otherwise
750
+ // if statDiff is set, all diff will be applied first and then execute the call
751
+ // message.
752
+ type account struct {
753
+ Nonce * hexutil.Uint64 `json:"nonce"`
754
+ Code * hexutil.Bytes `json:"code"`
755
+ Balance * * hexutil.Big `json:"balance"`
756
+ State * map [common.Hash ]common.Hash `json:"state"`
757
+ StateDiff * map [common.Hash ]common.Hash `json:"stateDiff"`
758
+ }
759
+
760
+ func DoCall (ctx context.Context , b Backend , args CallArgs , blockNr rpc.BlockNumber , overrides map [common.Address ]account , vmCfg vm.Config , timeout time.Duration , globalGasCap * big.Int ) ([]byte , uint64 , bool , error ) {
747
761
defer func (start time.Time ) { log .Debug ("Executing EVM call finished" , "runtime" , time .Since (start )) }(time .Now ())
748
762
749
763
state , header , err := b .StateAndHeaderByNumber (ctx , blockNr )
@@ -761,6 +775,34 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
761
775
} else {
762
776
addr = * args .From
763
777
}
778
+ // Override the fields of specified contracts before execution.
779
+ for addr , account := range overrides {
780
+ // Override account nonce.
781
+ if account .Nonce != nil {
782
+ state .SetNonce (addr , uint64 (* account .Nonce ))
783
+ }
784
+ // Override account(contract) code.
785
+ if account .Code != nil {
786
+ state .SetCode (addr , * account .Code )
787
+ }
788
+ // Override account balance.
789
+ if account .Balance != nil {
790
+ state .SetBalance (addr , (* big .Int )(* account .Balance ))
791
+ }
792
+ if account .State != nil && account .StateDiff != nil {
793
+ return nil , 0 , false , fmt .Errorf ("account %s has both 'state' and 'stateDiff'" , addr .Hex ())
794
+ }
795
+ // Replace entire state if caller requires.
796
+ if account .State != nil {
797
+ state .SetStorage (addr , * account .State )
798
+ }
799
+ // Apply state diff into specified accounts.
800
+ if account .StateDiff != nil {
801
+ for key , value := range * account .StateDiff {
802
+ state .SetState (addr , key , value )
803
+ }
804
+ }
805
+ }
764
806
// Set default gas & gas price if none were set
765
807
gas := uint64 (math .MaxUint64 / 2 )
766
808
if args .Gas != nil {
@@ -827,9 +869,17 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
827
869
}
828
870
829
871
// Call executes the given transaction on the state for the given block number.
830
- // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
831
- func (s * PublicBlockChainAPI ) Call (ctx context.Context , args CallArgs , blockNr rpc.BlockNumber ) (hexutil.Bytes , error ) {
832
- result , _ , _ , err := DoCall (ctx , s .b , args , blockNr , vm.Config {}, 5 * time .Second , s .b .RPCGasCap ())
872
+ //
873
+ // Additionally, the caller can specify a batch of contract for fields overriding.
874
+ //
875
+ // Note, this function doesn't make and changes in the state/blockchain and is
876
+ // useful to execute and retrieve values.
877
+ func (s * PublicBlockChainAPI ) Call (ctx context.Context , args CallArgs , blockNr rpc.BlockNumber , overrides * map [common.Address ]account ) (hexutil.Bytes , error ) {
878
+ var accounts map [common.Address ]account
879
+ if overrides != nil {
880
+ accounts = * overrides
881
+ }
882
+ result , _ , _ , err := DoCall (ctx , s .b , args , blockNr , accounts , vm.Config {}, 5 * time .Second , s .b .RPCGasCap ())
833
883
return (hexutil .Bytes )(result ), err
834
884
}
835
885
@@ -860,7 +910,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
860
910
executable := func (gas uint64 ) bool {
861
911
args .Gas = (* hexutil .Uint64 )(& gas )
862
912
863
- _ , _ , failed , err := DoCall (ctx , b , args , rpc .PendingBlockNumber , vm.Config {}, 0 , gasCap )
913
+ _ , _ , failed , err := DoCall (ctx , b , args , rpc .PendingBlockNumber , nil , vm.Config {}, 0 , gasCap )
864
914
if err != nil || failed {
865
915
return false
866
916
}
0 commit comments