@@ -47,6 +47,7 @@ import (
4747 "github.com/scroll-tech/go-ethereum/p2p"
4848 "github.com/scroll-tech/go-ethereum/params"
4949 "github.com/scroll-tech/go-ethereum/rlp"
50+ "github.com/scroll-tech/go-ethereum/rollup/fees"
5051 "github.com/scroll-tech/go-ethereum/rpc"
5152)
5253
@@ -848,11 +849,12 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
848849// if statDiff is set, all diff will be applied first and then execute the call
849850// message.
850851type OverrideAccount struct {
851- Nonce * hexutil.Uint64 `json:"nonce"`
852- Code * hexutil.Bytes `json:"code"`
853- Balance * * hexutil.Big `json:"balance"`
854- State * map [common.Hash ]common.Hash `json:"state"`
855- StateDiff * map [common.Hash ]common.Hash `json:"stateDiff"`
852+ Nonce * hexutil.Uint64 `json:"nonce"`
853+ Code * hexutil.Bytes `json:"code"`
854+ Balance * * hexutil.Big `json:"balance"`
855+ BalanceAdd * * hexutil.Big `json:"balanceAdd"`
856+ State * map [common.Hash ]common.Hash `json:"state"`
857+ StateDiff * map [common.Hash ]common.Hash `json:"stateDiff"`
856858}
857859
858860// StateOverride is the collection of overridden accounts.
@@ -873,9 +875,16 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
873875 state .SetCode (addr , * account .Code )
874876 }
875877 // Override account balance.
878+ if account .Balance != nil && account .BalanceAdd != nil {
879+ return fmt .Errorf ("account %s has both 'balance' and 'balanceAdd'" , addr .Hex ())
880+ }
876881 if account .Balance != nil {
877882 state .SetBalance (addr , (* big .Int )(* account .Balance ))
878883 }
884+ if account .BalanceAdd != nil {
885+ balance := big .NewInt (0 ).Add (state .GetBalance (addr ), (* big .Int )(* account .BalanceAdd ))
886+ state .SetBalance (addr , balance )
887+ }
879888 if account .State != nil && account .StateDiff != nil {
880889 return fmt .Errorf ("account %s has both 'state' and 'stateDiff'" , addr .Hex ())
881890 }
@@ -893,6 +902,54 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
893902 return nil
894903}
895904
905+ func newRPCBalance (balance * big.Int ) * * hexutil.Big {
906+ rpcBalance := (* hexutil .Big )(balance )
907+ return & rpcBalance
908+ }
909+
910+ func CalculateL1MsgFee (ctx context.Context , b Backend , args TransactionArgs , blockNrOrHash rpc.BlockNumberOrHash , overrides * StateOverride , timeout time.Duration , globalGasCap uint64 , config * params.ChainConfig ) (* big.Int , error ) {
911+ if ! config .UsingScroll {
912+ return big .NewInt (0 ), nil
913+ }
914+
915+ state , header , err := b .StateAndHeaderByNumberOrHash (ctx , blockNrOrHash )
916+ if state == nil || err != nil {
917+ return nil , err
918+ }
919+ if err := overrides .Apply (state ); err != nil {
920+ return nil , err
921+ }
922+ // Setup context so it may be cancelled the call has completed
923+ // or, in case of unmetered gas, setup a context with a timeout.
924+ var cancel context.CancelFunc
925+ if timeout > 0 {
926+ ctx , cancel = context .WithTimeout (ctx , timeout )
927+ } else {
928+ ctx , cancel = context .WithCancel (ctx )
929+ }
930+ // Make sure the context is cancelled when the call has completed
931+ // this makes sure resources are cleaned up.
932+ defer cancel ()
933+
934+ // Get a new instance of the EVM.
935+ msg , err := args .ToMessage (globalGasCap , header .BaseFee )
936+ if err != nil {
937+ return nil , err
938+ }
939+ evm , _ , err := b .GetEVM (ctx , msg , state , header , & vm.Config {NoBaseFee : true })
940+ if err != nil {
941+ return nil , err
942+ }
943+ // Wait for the context to be done and cancel the evm. Even if the
944+ // EVM has finished, cancelling may be done (repeatedly)
945+ go func () {
946+ <- ctx .Done ()
947+ evm .Cancel ()
948+ }()
949+
950+ return fees .CalculateL1MsgFee (msg , evm .StateDB )
951+ }
952+
896953func DoCall (ctx context.Context , b Backend , args TransactionArgs , blockNrOrHash rpc.BlockNumberOrHash , overrides * StateOverride , timeout time.Duration , globalGasCap uint64 ) (* core.ExecutionResult , error ) {
897954 defer func (start time.Time ) { log .Debug ("Executing EVM call finished" , "runtime" , time .Since (start )) }(time .Now ())
898955
@@ -985,6 +1042,26 @@ func (e *revertError) ErrorData() interface{} {
9851042// Note, this function doesn't make and changes in the state/blockchain and is
9861043// useful to execute and retrieve values.
9871044func (s * PublicBlockChainAPI ) Call (ctx context.Context , args TransactionArgs , blockNrOrHash rpc.BlockNumberOrHash , overrides * StateOverride ) (hexutil.Bytes , error ) {
1045+ // If gasPrice is 0 and no state override is set, make sure
1046+ // that the account has sufficient balance to cover `l1Fee`.
1047+ isGasPriceZero := args .GasPrice == nil || args .GasPrice .ToInt ().Cmp (big .NewInt (0 )) == 0
1048+
1049+ if overrides == nil {
1050+ overrides = & StateOverride {}
1051+ }
1052+ _ , isOverrideSet := (* overrides )[args .from ()]
1053+
1054+ if isGasPriceZero && ! isOverrideSet {
1055+ l1Fee , err := CalculateL1MsgFee (ctx , s .b , args , blockNrOrHash , overrides , s .b .RPCEVMTimeout (), s .b .RPCGasCap (), s .b .ChainConfig ())
1056+ if err != nil {
1057+ return nil , err
1058+ }
1059+
1060+ (* overrides )[args .from ()] = OverrideAccount {
1061+ BalanceAdd : newRPCBalance (l1Fee ),
1062+ }
1063+ }
1064+
9881065 result , err := DoCall (ctx , s .b , args , blockNrOrHash , overrides , s .b .RPCEVMTimeout (), s .b .RPCGasCap ())
9891066 if err != nil {
9901067 return nil , err
@@ -1040,12 +1117,25 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
10401117 }
10411118 balance := state .GetBalance (* args .From ) // from can't be nil
10421119 available := new (big.Int ).Set (balance )
1120+
1121+ // account for tx value
10431122 if args .Value != nil {
10441123 if args .Value .ToInt ().Cmp (available ) >= 0 {
10451124 return 0 , errors .New ("insufficient funds for transfer" )
10461125 }
10471126 available .Sub (available , args .Value .ToInt ())
10481127 }
1128+
1129+ // account for l1 fee
1130+ l1Fee , err := CalculateL1MsgFee (ctx , b , args , blockNrOrHash , nil , 0 , gasCap , b .ChainConfig ())
1131+ if err != nil {
1132+ return 0 , err
1133+ }
1134+ if l1Fee .Cmp (available ) >= 0 {
1135+ return 0 , errors .New ("insufficient funds for l1 fee" )
1136+ }
1137+ available .Sub (available , l1Fee )
1138+
10491139 allowance := new (big.Int ).Div (available , feeCap )
10501140
10511141 // If the allowance is larger than maximum uint64, skip checking
0 commit comments