Skip to content

Commit

Permalink
🐛 Fix: eth_estimateGas (#1430)
Browse files Browse the repository at this point in the history
## Description

1. Typescript type for estimateGas json request wrong
2. State overrides and block tag handled wrong

## Testing

Explain the quality checks that have been done on the code changes

## Additional Information

- [ ] I read the [contributing docs](../docs/contributing.md) (if this
is your first contribution)

Your ENS/address:



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced gas estimation accuracy for Ethereum transactions by fixing a
bug related to the `eth_estimateGas` method.
- Introduced optional parameters for gas estimation requests, allowing
for greater flexibility in specifying block tags and state overrides.

- **Bug Fixes**
- Resolved issues with handling block tags and state overrides in gas
estimation.

- **Tests**
- Added new test cases to improve coverage for gas estimation
functionality, including scenarios for handling block tags and specific
contract interactions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: William Cory <[email protected]>
  • Loading branch information
roninjin10 and William Cory committed Sep 13, 2024
1 parent a308502 commit 5942568
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/forty-mugs-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tevm/procedures": patch
---

Fixed bug with eth_estimateGas json-rpc not handling block tag and state overrides correctly
7 changes: 7 additions & 0 deletions packages/memory-client/src/test/viem/estimateGas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ beforeEach(async () => {

describe('estimateGas', () => {
it('should work', async () => {
expect(
await mc.estimateGas({
to: c.simpleContract.address,
data: encodeFunctionData(c.simpleContract.write.set(69n)),
blockTag: 'latest',
}),
).toBe(27_784n)
expect(
await mc.estimateGas({
to: c.simpleContract.address,
Expand Down
10 changes: 9 additions & 1 deletion packages/procedures/src/eth/EthJsonRpcRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,15 @@ export type EthCoinbaseJsonRpcRequest = JsonRpcRequest<'eth_coinbase', readonly
/**
* JSON-RPC request for `eth_estimateGas` procedure
*/
export type EthEstimateGasJsonRpcRequest = JsonRpcRequest<'eth_estimateGas', readonly [tx: JsonRpcTransaction]>
export type EthEstimateGasJsonRpcRequest = JsonRpcRequest<
'eth_estimateGas',
readonly [
tx: JsonRpcTransaction,
tag?: BlockTag | Hex,
stateOverrideSet?: SerializeToJson<BaseCallParams['stateOverrideSet']>,
blockOverrideSet?: SerializeToJson<BaseCallParams['blockOverrideSet']>,
]
>
// eth_hashrate
/**
* JSON-RPC request for `eth_hashrate` procedure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

exports[`ethEstimateGasJsonRpcProcedure > should estimate gas successfully 1`] = `"0x5208"`;

exports[`ethEstimateGasJsonRpcProcedure > should handle block tag 1`] = `"0x5208"`;

exports[`ethEstimateGasJsonRpcProcedure > should handle errors from callProcedure 1`] = `
{
"code": -32602,
Expand Down
23 changes: 22 additions & 1 deletion packages/procedures/src/eth/ethEstimateGasProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,30 @@ import { callProcedure } from '../call/callProcedure.js'
export const ethEstimateGasJsonRpcProcedure = (client) => {
return async (request) => {
const estimateGasRequest = /** @type {import('./EthJsonRpcRequest.js').EthEstimateGasJsonRpcRequest}*/ (request)
const [_params, blockTag, stateOverrides, blockOverrides] = estimateGasRequest.params

const getParams = () => {
/**
* @type {import('../call/CallJsonRpcRequest.js').CallJsonRpcRequest['params']}
*/
const params = [
{
..._params,
...(blockTag !== undefined ? { blockTag } : {}),
},
]
if (blockOverrides !== undefined) {
params.push(stateOverrides ?? {}, blockOverrides)
}
if (stateOverrides !== undefined) {
params.push(...params, stateOverrides)
}
return params
}

const callResult = await callProcedure(client)({
...estimateGasRequest,
params: [...estimateGasRequest.params],
params: getParams(),
method: 'tevm_call',
})
if (callResult.error || !callResult.result) {
Expand Down
24 changes: 24 additions & 0 deletions packages/procedures/src/eth/ethEstimateGasProcedure.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type TevmNode, createTevmNode } from '@tevm/node'
import { numberToHex } from '@tevm/utils'
import { beforeEach, describe, expect, it } from 'vitest'
import type { EthEstimateGasJsonRpcRequest } from './EthJsonRpcRequest.js'
import { ethEstimateGasJsonRpcProcedure } from './ethEstimateGasProcedure.js'
Expand Down Expand Up @@ -31,6 +32,29 @@ describe('ethEstimateGasJsonRpcProcedure', () => {
expect(response.id).toBe(request.id as any)
expect(response.result).toMatchSnapshot()
})
it('should handle block tag', async () => {
const latestBlock = await client.getVm().then((vm) => vm.blockchain.getCanonicalHeadBlock())
const request: EthEstimateGasJsonRpcRequest = {
jsonrpc: '2.0',
method: 'eth_estimateGas',
id: 1,
params: [
{
from: '0x0000000000000000000000000000000000000000',
to: '0x0000000000000000000000000000000000000000',
data: '0x',
},
numberToHex(latestBlock.header.number),
],
}

const response = await ethEstimateGasJsonRpcProcedure(client)(request)
expect(response.error).toBeUndefined()
expect(response.result).toBeDefined()
expect(response.method).toBe('eth_estimateGas')
expect(response.id).toBe(request.id as any)
expect(response.result).toMatchSnapshot()
})

it('should handle errors from callProcedure', async () => {
const request: EthEstimateGasJsonRpcRequest = {
Expand Down

0 comments on commit 5942568

Please sign in to comment.