-
-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🧪 Test: Add more test coverage to actions #1467
Changes from all commits
ea1a139
fa87a5e
efb8b71
b14c990
bb288ba
cb6cad5
14dd8f1
18c889c
5e3cec8
1f7cef7
47dba07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@tevm/test-utils": minor | ||
--- | ||
|
||
Added a new BlockReader contract. BlockReader is a contract that can be used to test reading blocks from the evm. Used internally to test block overrides |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@tevm/actions": patch | ||
"@tevm/vm": patch | ||
--- | ||
|
||
Fixed bug with block override set missing a state root |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@tevm/actions": patch | ||
--- | ||
|
||
Fixed bug in tevm_call json-rpc procedure where deployedBytecode, createTrace and createAccessList were not forwarded to the underlying handler. This bug only affected users using JSON-RPC directly |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,9 +39,12 @@ export const callProcedure = (client) => async (request) => { | |
} | ||
: {}), | ||
...(request.params[0].code ? { code: request.params[0].code } : {}), | ||
...(request.params[0].data ? { data: request.params[0].data } : {}), | ||
...(request.params[0].deployedBytecode ? { deployedBytecode: request.params[0].deployedBytecode } : {}), | ||
...(request.params[0].createTrace ? { createTrace: request.params[0].createTrace } : {}), | ||
...(request.params[0].createAccessList ? { createAccessList: request.params[0].createAccessList } : {}), | ||
Comment on lines
+42
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure proper validation and sanitization of new request parameters. The new parameters |
||
...(request.params[0].blobVersionedHashes ? { blobVersionedHashes: request.params[0].blobVersionedHashes } : {}), | ||
...(request.params[0].caller ? { caller: request.params[0].caller } : {}), | ||
...(request.params[0].data ? { data: request.params[0].data } : {}), | ||
...(request.params[0].depth ? { depth: request.params[0].depth } : {}), | ||
...(request.params[0].gasPrice ? { gasPrice: hexToBigInt(request.params[0].gasPrice) } : {}), | ||
...(request.params[0].gas ? { gas: hexToBigInt(request.params[0].gas) } : {}), | ||
|
@@ -59,8 +62,6 @@ export const callProcedure = (client) => async (request) => { | |
...(request.params[0].maxPriorityFeePerGas | ||
? { maxPriorityFeePerGas: hexToBigInt(request.params[0].maxPriorityFeePerGas) } | ||
: {}), | ||
// TODO add support for manually setting nonce | ||
// ...(request.params[0].nonce ? { nonce: hexToBigInt(request.params[0].nonce) } : {}), | ||
}) | ||
if (errors.length > 0) { | ||
const error = /** @type {import('./TevmCallError.js').TevmCallError}*/ (errors[0]) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
import { createAddress } from '@tevm/address' | ||
import { ERC20 } from '@tevm/contract' | ||
import { type TevmNode, createTevmNode } from '@tevm/node' | ||
import { encodeFunctionData, numberToHex, parseEther } from '@tevm/utils' | ||
import { BlockReader, SimpleContract } from '@tevm/test-utils' | ||
import { type Address, type Hex, decodeFunctionResult, encodeFunctionData, numberToHex, parseEther } from '@tevm/utils' | ||
import { beforeEach, describe, expect, it } from 'vitest' | ||
import { deployHandler } from '../Deploy/deployHandler.js' | ||
import { mineHandler } from '../Mine/mineHandler.js' | ||
import { setAccountHandler } from '../SetAccount/setAccountHandler.js' | ||
import type { CallJsonRpcRequest } from './CallJsonRpcRequest.js' | ||
import { callProcedure } from './callProcedure.js' | ||
|
@@ -77,7 +81,102 @@ describe('callProcedure', () => { | |
expect(response.result).toMatchSnapshot() | ||
}) | ||
|
||
it.todo('should handle a call with block override', async () => {}) | ||
it('should handle a call with block override', async () => { | ||
const blockReaderAddress = createAddress(1234) | ||
await setAccountHandler(client)({ | ||
address: blockReaderAddress.toString(), | ||
deployedBytecode: BlockReader.deployedBytecode, | ||
}) | ||
|
||
const request: CallJsonRpcRequest = { | ||
jsonrpc: '2.0', | ||
method: 'tevm_call', | ||
id: 1, | ||
params: [ | ||
{ | ||
to: blockReaderAddress.toString(), | ||
data: encodeFunctionData(BlockReader.read.getBlockInfo()), | ||
}, | ||
{}, // No state override | ||
{ | ||
number: numberToHex(1000n), | ||
time: numberToHex(1234567890n), | ||
coinbase: '0x1000000000000000000000000000000000000000', | ||
baseFee: numberToHex(1n), | ||
}, | ||
], | ||
} | ||
|
||
const response = await callProcedure(client)(request) | ||
expect(response.error).toBeUndefined() | ||
expect(response.result).toBeDefined() | ||
expect(response.method).toBe('tevm_call') | ||
expect(response.id).toBe(request.id as any) | ||
|
||
Comment on lines
+114
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid unnecessary casting to Casting Also applies to: 146-147, 158-159 |
||
const decodedResult = decodeFunctionResult({ | ||
abi: BlockReader.read.getBlockInfo.abi, | ||
data: response.result?.rawData as Hex, | ||
functionName: 'getBlockInfo', | ||
}) | ||
expect(decodedResult).toEqual([1000n, 1234567890n, '0x1000000000000000000000000000000000000000', 1n]) | ||
}) | ||
Comment on lines
+84
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor common test setup code to improve maintainability The test cases Also applies to: 124-179 |
||
|
||
it('should handle a call with tracing enabled', async () => { | ||
const { createdAddress } = await deployHandler(client)(SimpleContract.deploy(0n)) | ||
await mineHandler(client)() | ||
|
||
const request: CallJsonRpcRequest = { | ||
jsonrpc: '2.0', | ||
method: 'tevm_call', | ||
id: 1, | ||
params: [ | ||
{ | ||
to: createdAddress as Address, | ||
data: encodeFunctionData(SimpleContract.write.set(100n)), | ||
createTransaction: true, | ||
createTrace: true, | ||
createAccessList: true, | ||
}, | ||
], | ||
} | ||
|
||
const response = await callProcedure(client)(request) | ||
expect(response.error).toBeUndefined() | ||
expect(response.result).toBeDefined() | ||
expect(response.method).toBe('tevm_call') | ||
expect(response.result?.logs).toMatchInlineSnapshot(` | ||
[ | ||
{ | ||
"address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", | ||
"data": "0x0000000000000000000000000000000000000000000000000000000000000064", | ||
"topics": [ | ||
"0x012c78e2b84325878b1bd9d250d772cfe5bda7722d795f45036fa5e1e6e303fc", | ||
], | ||
}, | ||
] | ||
`) | ||
expect(response.id).toBe(request.id as any) | ||
expect(response.result?.trace).toBeDefined() | ||
expect(response.result?.trace?.structLogs).toBeInstanceOf(Array) | ||
expect(response.result?.trace?.structLogs?.length).toBeGreaterThan(0) | ||
expect(response.result?.trace?.structLogs[0]).toMatchInlineSnapshot(` | ||
{ | ||
"depth": 0, | ||
"gas": "0x1c970ac", | ||
"gasCost": "0x6", | ||
"op": "PUSH1", | ||
"pc": 0, | ||
"stack": [], | ||
} | ||
`) | ||
expect(response.result?.accessList).toMatchInlineSnapshot(` | ||
{ | ||
"0x5fbdb2315678afecb367f032d93f642f64180aa3": [ | ||
"0x0000000000000000000000000000000000000000000000000000000000000000", | ||
], | ||
} | ||
`) | ||
}) | ||
|
||
it('should handle errors from callHandler', async () => { | ||
const request: CallJsonRpcRequest = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html | ||
|
||
exports[`should dump state for a specific block number 1`] = ` | ||
[ | ||
[InternalError: Unexpected error | ||
|
||
Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ | ||
Details: /reference/tevm/errors/classes/unknownblockerror/ | ||
Version: 1.1.0.next-73], | ||
] | ||
`; | ||
|
||
exports[`should handle block not found 1`] = ` | ||
[ | ||
[InternalError: Unexpected error | ||
|
||
Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ | ||
Details: /reference/tevm/errors/classes/unknownblockerror/ | ||
Version: 1.1.0.next-73], | ||
] | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,3 +39,18 @@ test('should dump important account info and storage', async () => { | |
|
||
expect(accountStorage).toEqual(storageValue) | ||
}) | ||
|
||
test('should handle block not found', async () => { | ||
const client = createTevmNode() | ||
const { errors } = await dumpStateHandler(client)({ blockTag: 1n, throwOnFail: false }) | ||
expect(errors).toBeDefined() | ||
expect(errors).toHaveLength(1) | ||
expect(errors).toMatchInlineSnapshot(` | ||
[ | ||
[UnknownBlock: Block number 1 does not exist | ||
|
||
Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ | ||
Version: 1.1.0.next-73], | ||
] | ||
`) | ||
}) | ||
Comment on lines
+43
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Good addition of error handling test, consider these improvements:
Here's a suggested improvement for points 1 and 2: test('should handle block not found', async () => {
const client = createTevmNode()
+ // Use 1n as a non-existent block number to trigger the error
const { errors } = await dumpStateHandler(client)({ blockTag: 1n, throwOnFail: false })
expect(errors).toBeDefined()
expect(errors).toHaveLength(1)
- expect(errors).toMatchInlineSnapshot(`
- [
- [UnknownBlock: Block number 1 does not exist
-
- Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/
- Version: 1.1.0.next-73],
- ]
- `)
+ expect(errors[0]).toBeInstanceOf(Error)
+ expect(errors[0].message).toContain('Block number 1 does not exist')
+ expect(errors[0].message).toContain('https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/')
}) For point 3, consider adding a new test case: test('should throw when block not found and throwOnFail is true', async () => {
const client = createTevmNode()
await expect(dumpStateHandler(client)({ blockTag: 1n, throwOnFail: true })).rejects.toThrow('Block number 1 does not exist')
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Include
stateRoot
in the type definitionsThe comment notes that
stateRoot
isn't in the type definition but is required to prevent block overrides from failing. To ensure type safety and clarity, consider updating the type definitions to includestateRoot
.Apply this change to update the type definitions accordingly.