Skip to content

Commit 88eb640

Browse files
authored
chore: apply state overrides to eth_estimateGas api (cosmos#743)
* fix(rpc): apply state overrides to eth_estimateGas api * fix(rpc): use blockNumberOrHash instead of blockNumber for eth_estimateGas api * fix(v/xm): state overrides for EstimateGas * test(jsonrpc): enhance eth_estimateGas api * chore: fix codeQL warning * chore: update CHANGELOG.md
1 parent ea2ee10 commit 88eb640

File tree

10 files changed

+538
-24
lines changed

10 files changed

+538
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
- [\#710](https://github.com/cosmos/evm/pull/710) Fix EoA-CA Identification logic
7979
- [\#711](https://github.com/cosmos/evm/pull/711) Add debug_traceCall api
8080
- [\#734](https://github.com/cosmos/evm/pull/734) Disable evm mempool if max-txs set to -1.
81-
81+
- [\#743](https://github.com/cosmos/evm/pull/743) Apply state overrides to eth_estimateGas api
8282

8383
### FEATURES
8484

rpc/backend/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ type EVMBackend interface {
116116
Resend(args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error)
117117
SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
118118
SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error)
119-
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
119+
EstimateGas(args evmtypes.TransactionArgs, blockNrOrHash *types.BlockNumberOrHash, overrides *json.RawMessage) (hexutil.Uint64, error)
120120
DoCall(args evmtypes.TransactionArgs, blockNr types.BlockNumber, overrides *json.RawMessage) (*evmtypes.MsgEthereumTxResponse, error)
121121
GasPrice() (*hexutil.Big, error)
122122

rpc/backend/call_tx.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ func (b *Backend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Transac
299299
}
300300

301301
blockNr := rpctypes.NewBlockNumber(big.NewInt(0))
302-
estimated, err := b.EstimateGas(callArgs, &blockNr)
302+
blockNrOrHash := rpctypes.BlockNumberOrHash{BlockNumber: &blockNr}
303+
estimated, err := b.EstimateGas(callArgs, &blockNrOrHash, nil)
303304
if err != nil {
304305
return args, err
305306
}
@@ -317,11 +318,16 @@ func (b *Backend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Transac
317318
// EstimateGas returns an estimate of gas usage for the given smart contract call.
318319
func (b *Backend) EstimateGas(
319320
args evmtypes.TransactionArgs,
320-
blockNrOptional *rpctypes.BlockNumber,
321+
blockNrOrHash *rpctypes.BlockNumberOrHash,
322+
overrides *json.RawMessage,
321323
) (hexutil.Uint64, error) {
322324
blockNr := rpctypes.EthPendingBlockNumber
323-
if blockNrOptional != nil {
324-
blockNr = *blockNrOptional
325+
if blockNrOrHash != nil {
326+
var err error
327+
blockNr, err = b.BlockNumberFromComet(*blockNrOrHash)
328+
if err != nil {
329+
return 0, err
330+
}
325331
}
326332

327333
bz, err := json.Marshal(&args)
@@ -335,11 +341,17 @@ func (b *Backend) EstimateGas(
335341
return 0, errors.New("header not found")
336342
}
337343

344+
var bzOverrides []byte
345+
if overrides != nil {
346+
bzOverrides = *overrides
347+
}
348+
338349
req := evmtypes.EthCallRequest{
339350
Args: bz,
340351
GasCap: b.RPCGasCap(),
341352
ProposerAddress: sdk.ConsAddress(header.Header.ProposerAddress),
342353
ChainId: b.EvmChainID.Int64(),
354+
Overrides: bzOverrides,
343355
}
344356

345357
// From ContextWithHeight: if the provided height is 0,

rpc/namespaces/ethereum/eth/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ type EthereumAPI interface {
7474
// Returns information on the Ethereum network and internal settings.
7575
ProtocolVersion() hexutil.Uint
7676
GasPrice() (*hexutil.Big, error)
77-
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error)
77+
EstimateGas(args evmtypes.TransactionArgs, blockNrOrHash *rpctypes.BlockNumberOrHash, overrides *json.RawMessage) (hexutil.Uint64, error)
7878
FeeHistory(blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error)
7979
MaxPriorityFeePerGas() (*hexutil.Big, error)
8080
ChainId() (*hexutil.Big, error)
@@ -322,9 +322,9 @@ func (e *PublicAPI) GasPrice() (*hexutil.Big, error) {
322322
}
323323

324324
// EstimateGas returns an estimate of gas usage for the given smart contract call.
325-
func (e *PublicAPI) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rpctypes.BlockNumber) (hexutil.Uint64, error) {
325+
func (e *PublicAPI) EstimateGas(args evmtypes.TransactionArgs, blockNrOrHash *rpctypes.BlockNumberOrHash, overrides *json.RawMessage) (hexutil.Uint64, error) {
326326
e.logger.Debug("eth_estimateGas")
327-
return e.backend.EstimateGas(args, blockNrOptional)
327+
return e.backend.EstimateGas(args, blockNrOrHash, overrides)
328328
}
329329

330330
func (e *PublicAPI) FeeHistory(

tests/integration/rpc/backend/test_call_tx.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,150 @@ func (s *TestSuite) TestGasPrice() {
627627
})
628628
}
629629
}
630+
631+
func (s *TestSuite) TestEstimateGas() {
632+
gasPrice := (*hexutil.Big)(big.NewInt(1))
633+
toAddr := utiltx.GenerateAddress()
634+
evmChainID := (*hexutil.Big)(s.backend.EvmChainID)
635+
callArgs := evmtypes.TransactionArgs{
636+
From: nil,
637+
To: &toAddr,
638+
Gas: nil,
639+
GasPrice: nil,
640+
MaxFeePerGas: gasPrice,
641+
MaxPriorityFeePerGas: gasPrice,
642+
Value: gasPrice,
643+
Input: nil,
644+
Data: nil,
645+
AccessList: nil,
646+
ChainID: evmChainID,
647+
}
648+
argsBz, err := json.Marshal(callArgs)
649+
s.Require().NoError(err)
650+
651+
overrides := json.RawMessage(`{
652+
"` + toAddr.Hex() + `": {
653+
"balance": "0x0"
654+
}
655+
}`)
656+
invalidOverrides := json.RawMessage(`{"invalid": json}`)
657+
emptyOverrides := json.RawMessage(`{}`)
658+
659+
testCases := []struct {
660+
name string
661+
registerMock func()
662+
callArgs evmtypes.TransactionArgs
663+
overrides *json.RawMessage
664+
expGas hexutil.Uint64
665+
expPass bool
666+
}{
667+
{
668+
"fail - Invalid request",
669+
func() {
670+
_, bz := s.buildEthereumTx()
671+
client := s.backend.ClientCtx.Client.(*mocks.Client)
672+
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
673+
height := int64(1)
674+
RegisterHeader(client, &height, bz)
675+
RegisterEstimateGasError(QueryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: s.backend.EvmChainID.Int64()})
676+
},
677+
callArgs,
678+
nil,
679+
0,
680+
false,
681+
},
682+
{
683+
"pass - Returned gas estimate",
684+
func() {
685+
_, bz := s.buildEthereumTx()
686+
client := s.backend.ClientCtx.Client.(*mocks.Client)
687+
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
688+
height := int64(1)
689+
RegisterHeader(client, &height, bz)
690+
RegisterEstimateGas(QueryClient, callArgs)
691+
},
692+
callArgs,
693+
nil,
694+
21000,
695+
true,
696+
},
697+
{
698+
"pass - With state overrides",
699+
func() {
700+
_, bz := s.buildEthereumTx()
701+
client := s.backend.ClientCtx.Client.(*mocks.Client)
702+
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
703+
height := int64(1)
704+
RegisterHeader(client, &height, bz)
705+
expected := &evmtypes.EthCallRequest{
706+
Args: argsBz,
707+
ChainId: s.backend.EvmChainID.Int64(),
708+
Overrides: overrides,
709+
}
710+
RegisterEstimateGasWithOverrides(QueryClient, expected)
711+
},
712+
callArgs,
713+
&overrides,
714+
21000,
715+
true,
716+
},
717+
{
718+
"fail - Invalid state overrides JSON",
719+
func() {
720+
_, bz := s.buildEthereumTx()
721+
client := s.backend.ClientCtx.Client.(*mocks.Client)
722+
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
723+
height := int64(1)
724+
RegisterHeader(client, &height, bz)
725+
expected := &evmtypes.EthCallRequest{
726+
Args: argsBz,
727+
ChainId: s.backend.EvmChainID.Int64(),
728+
Overrides: invalidOverrides,
729+
}
730+
RegisterEstimateGasError(QueryClient, expected)
731+
},
732+
callArgs,
733+
&invalidOverrides,
734+
0,
735+
false,
736+
},
737+
{
738+
"pass - Empty state overrides",
739+
func() {
740+
_, bz := s.buildEthereumTx()
741+
client := s.backend.ClientCtx.Client.(*mocks.Client)
742+
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
743+
height := int64(1)
744+
RegisterHeader(client, &height, bz)
745+
expected := &evmtypes.EthCallRequest{
746+
Args: argsBz,
747+
ChainId: s.backend.EvmChainID.Int64(),
748+
Overrides: emptyOverrides,
749+
}
750+
RegisterEstimateGasWithOverrides(QueryClient, expected)
751+
},
752+
callArgs,
753+
&emptyOverrides,
754+
21000,
755+
true,
756+
},
757+
}
758+
759+
for _, tc := range testCases {
760+
s.Run(fmt.Sprintf("case %s", tc.name), func() {
761+
s.SetupTest() // reset test and queries
762+
tc.registerMock()
763+
764+
blockNum := rpctypes.BlockNumber(1)
765+
blockNrOrHash := rpctypes.BlockNumberOrHash{BlockNumber: &blockNum}
766+
gas, err := s.backend.EstimateGas(tc.callArgs, &blockNrOrHash, tc.overrides)
767+
768+
if tc.expPass {
769+
s.Require().NoError(err)
770+
s.Require().Equal(tc.expGas, gas)
771+
} else {
772+
s.Require().Error(err)
773+
}
774+
})
775+
}
776+
}

tests/integration/rpc/backend/test_evm_query_client.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,17 @@ func RegisterEthCallError(queryClient *mocks.EVMQueryClient, request *evmtypes.E
194194
func RegisterEstimateGas(queryClient *mocks.EVMQueryClient, args evmtypes.TransactionArgs) {
195195
bz, _ := json.Marshal(args)
196196
queryClient.On("EstimateGas", rpc.ContextWithHeight(1), &evmtypes.EthCallRequest{Args: bz, ChainId: args.ChainID.ToInt().Int64()}).
197-
Return(&evmtypes.EstimateGasResponse{}, nil)
197+
Return(&evmtypes.EstimateGasResponse{Gas: 21000}, nil)
198+
}
199+
200+
func RegisterEstimateGasError(queryClient *mocks.EVMQueryClient, req *evmtypes.EthCallRequest) {
201+
queryClient.On("EstimateGas", rpc.ContextWithHeight(1), req).
202+
Return(nil, errortypes.ErrInvalidRequest)
203+
}
204+
205+
func RegisterEstimateGasWithOverrides(queryClient *mocks.EVMQueryClient, req *evmtypes.EthCallRequest) {
206+
queryClient.On("EstimateGas", rpc.ContextWithHeight(1), req).
207+
Return(&evmtypes.EstimateGasResponse{Gas: 21000}, nil)
198208
}
199209

200210
// BaseFee

0 commit comments

Comments
 (0)