From d1897950f8b0062ebb8932c393d03d055d004ee1 Mon Sep 17 00:00:00 2001 From: Amir Date: Mon, 19 May 2025 23:37:37 -0700 Subject: [PATCH 01/24] Make runStateTests and helpers test-framework agnostic --- .../tester/runners/GeneralStateTestsRunner.ts | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index 389c4f7efe4..9832ea6b3d6 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -13,6 +13,7 @@ import { } from '@ethereumjs/util' import { createVerkleTree } from '@ethereumjs/verkle' import * as verkle from 'micro-eth-signer/verkle' +import { assert } from 'vitest' import { createVM, runTx } from '../../../src/index.ts' import { makeBlockFromEnv, makeTx, setupPreConditions } from '../../util.ts' @@ -76,7 +77,7 @@ function parseTestCases( return testCases } -async function runTestCase(options: any, testData: any, t: tape.Test) { +async function runTestCase(options: any, testData: any, t: tape.Test | undefined) { const begin = Date.now() // Copy the common object to not create long-lasting // references in memory which might prevent GC @@ -147,7 +148,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) { opName: e.opcode.name, } - t.comment(JSON.stringify(opTrace)) + t && t.comment(JSON.stringify(opTrace)) resolve?.() } @@ -155,7 +156,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) { const stateRoot = { stateRoot: bytesToHex(await vm.stateManager.getStateRoot()), } - t.comment(JSON.stringify(stateRoot)) + t && t.comment(JSON.stringify(stateRoot)) resolve?.() } @@ -189,7 +190,13 @@ async function runTestCase(options: any, testData: any, t: tape.Test) { const end = Date.now() const timeSpent = `${(end - begin) / 1000} secs` - t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) + t && t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) + const msg = `error running test case for fork: ${options.forkConfigTestSuite}` + if (t !== undefined) { + t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) + } else { + assert.isTrue(stateRootsAreEqual, msg) + } vm.evm.events!.removeListener('step', stepHandler) vm.events.removeListener('afterTx', afterTxHandler) @@ -199,32 +206,27 @@ async function runTestCase(options: any, testData: any, t: tape.Test) { return parseFloat(timeSpent) } -export async function runStateTest(options: any, testData: any, t: tape.Test) { - try { - const testCases = parseTestCases( - options.forkConfigTestSuite, - testData, - options.data, - options.gasLimit, - options.value, - ) - if (testCases.length === 0) { - t.comment(`No ${options.forkConfigTestSuite} post state defined, skip test`) - return - } - for (const testCase of testCases) { - if (options.reps !== undefined && options.reps > 0) { - let totalTimeSpent = 0 - for (let x = 0; x < options.reps; x++) { - totalTimeSpent += await runTestCase(options, testCase, t) - } - t.comment(`Average test run: ${(totalTimeSpent / options.reps).toLocaleString()} s`) - } else { - await runTestCase(options, testCase, t) +export async function runStateTest(options: any, testData: any, t: tape.Test | undefined) { + const testCases = parseTestCases( + options.forkConfigTestSuite, + testData, + options.data, + options.gasLimit, + options.value, + ) + if (testCases.length === 0) { + t && t.comment(`No ${options.forkConfigTestSuite} post state defined, skip test`) + return + } + for (const testCase of testCases) { + if (options.reps !== undefined && options.reps > 0) { + let totalTimeSpent = 0 + for (let x = 0; x < options.reps; x++) { + totalTimeSpent += await runTestCase(options, testCase, t) } + t && t.comment(`Average test run: ${(totalTimeSpent / options.reps).toLocaleString()} s`) + } else { + await runTestCase(options, testCase, t) } - } catch (e: any) { - console.log(e) - t.fail(`error running test case for fork: ${options.forkConfigTestSuite}`) } } From 037829ffdd71358f23b0c0b1d267791a360f8bc1 Mon Sep 17 00:00:00 2001 From: Amir Date: Mon, 19 May 2025 23:39:59 -0700 Subject: [PATCH 02/24] Add simplified test runner --- packages/vm/test/tester/stateRunner.spec.ts | 428 ++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 packages/vm/test/tester/stateRunner.spec.ts diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts new file mode 100644 index 00000000000..71bc977e598 --- /dev/null +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -0,0 +1,428 @@ +import type { Common } from '@ethereumjs/common' + +import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' +import * as mcl from 'mcl-wasm' +import minimist from 'minimist' +import { describe, it } from 'vitest' + +import { KZG as microEthKZG } from 'micro-eth-signer/kzg' + +import { + type EVMBLSInterface, + type EVMBN254Interface, + MCLBLS, + NobleBLS, + NobleBN254, + RustBN254, +} from '@ethereumjs/evm' +import { initRustBN } from 'rustbn-wasm' +import { DEFAULT_FORK_CONFIG, getCommon, getRequiredForkConfigAlias } from './config.ts' +import { runStateTest } from './runners/GeneralStateTestsRunner.ts' + +const testDataObject = { + wrongBlobhashVersion: { + _info: { + comment: 'BLOB001', + 'filling-rpc-server': 'evm version 1.14.4-unstable-3d8028a6-20240513', + 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++', + generatedTestHash: '121104d3f52ee80ee2f762e750fba7476c87fdaa7e8d48b565e26a68f677d80c', + lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', + solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', + source: + 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/wrongBlobhashVersionFiller.yml', + sourceHash: '32cfd908b12300b9128770c6c0b944a35d546f25d3ddc2e237cd3cd3395607a5', + }, + env: { + currentBaseFee: '0x07', + currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', + currentDifficulty: '0x020000', + currentExcessBlobGas: '0x00', + currentGasLimit: '0x1000000000', + currentNumber: '0x01', + currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', + currentTimestamp: '0x03e8', + }, + post: { + Cancun: [ + { + expectException: 'TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH', + hash: '0x66887abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2', + indexes: { + data: 0, + gas: 0, + value: 0, + }, + logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + txbytes: + '0x03f9010c01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af842a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8a045a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0daa1a9e47f815525ac6e11929160073fea1abf7acee286d4858fd4b1d9611fcda054d245d4a23cf599e6a8611692fdeab9be366108af5ba72554062346fa41a55a', + }, + ], + }, + pre: { + '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { + balance: '0x0de0b6b3a7640000', + code: '0x60004960005500', + nonce: '0x00', + storage: {}, + }, + '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { + balance: '0x0de0b6b3a7640000', + code: '0x', + nonce: '0x00', + storage: {}, + }, + }, + transaction: { + accessLists: [ + [ + { + address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + ], + }, + ], + ], + blobVersionedHashes: [ + '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', + '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', + ], + data: ['0x00'], + gasLimit: ['0x3d0900'], + maxFeePerBlobGas: '0x0a', + maxFeePerGas: '0x012a05f200', + maxPriorityFeePerGas: '0x02', + nonce: '0x00', + secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', + sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', + to: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', + value: ['0x0186a0'], + }, + }, + createBlobhashTx: { + _info: { + comment: 'BLOB002', + 'filling-rpc-server': 'evm version 1.14.4-unstable-3d8028a6-20240513', + 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++', + generatedTestHash: '14e2a257401391d59db3660d65588cd10e65eafdeb01efee34ccad42466e7998', + lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', + solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', + source: + 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/createBlobhashTxFiller.yml', + sourceHash: '57888e10e405e2329fd6d49f955f81fb04136c0bc699ab8c69919ed5e36e5b11', + }, + env: { + currentBaseFee: '0x07', + currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', + currentDifficulty: '0x020000', + currentExcessBlobGas: '0x00', + currentGasLimit: '0x1000000000', + currentNumber: '0x01', + currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', + currentTimestamp: '0x03e8', + }, + post: { + Cancun: [ + { + expectException: 'TransactionException.TYPE_3_TX_CONTRACT_CREATION', + hash: '0x668817abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2', + indexes: { + data: 0, + gas: 0, + value: 0, + }, + logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + txbytes: + '0x03f8d601800285012a05f200833d090080830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0fc12b67159a3567f8bdbc49e0be369a2e20e09d57a51c41310543a4128409464a02de0cfe5495c4f58ff60645ceda0afd67a4c90a70bc89fe207269435b35e5b67', + }, + ], + }, + pre: { + '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { + balance: '0x0de0b6b3a7640000', + code: '0x60004960005500', + nonce: '0x00', + storage: {}, + }, + '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { + balance: '0x0de0b6b3a7640000', + code: '0x', + nonce: '0x00', + storage: {}, + }, + }, + transaction: { + accessLists: [ + [ + { + address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + ], + }, + ], + ], + blobVersionedHashes: ['0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8'], + data: ['0x00'], + gasLimit: ['0x3d0900'], + maxFeePerBlobGas: '0x0a', + maxFeePerGas: '0x012a05f200', + maxPriorityFeePerGas: '0x02', + nonce: '0x00', + secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', + sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', + to: '', + value: ['0x0186a0'], + }, + }, + blobhashListBounds4: { + _info: { + comment: 'BLOB006', + 'filling-rpc-server': 'evm version 1.13.11-unstable-765f2904-20240124', + 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.ea13235b.Linux.g++', + generatedTestHash: '98c5bce6c1b8cd5a8bdafc9333b5d86587efe3a53d0515873d9f27110d3e3935', + lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', + solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', + source: + 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/blobhashListBounds4Filler.yml', + sourceHash: '5d992d68f3b613a49469fff6db6a6db728dc4526c36b03341da4d165b77b9bca', + }, + env: { + currentBaseFee: '0x07', + currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', + currentDifficulty: '0x020000', + currentExcessBlobGas: '0x00', + currentGasLimit: '0x1000000000', + currentNumber: '0x01', + currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', + currentTimestamp: '0x03e8', + }, + post: { + Cancun: [ + { + hash: '0xdfef0eb2235050b176af2aa3d2b1ce64184bfa1fe5fa598c048a0adb2bbb7d86', + indexes: { + data: 0, + gas: 0, + value: 0, + }, + logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + txbytes: + '0x03f9014e01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af884a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0001a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0002a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0003a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f000401a04050f623a6a761402057018dbe8f7e9581bd8eed6362e7271e81b2861ca4cbdaa0671bf16648962e2435bf04e0e6c4eb9c0bc9971b251771f25d75e32a21fb3a7b', + }, + ], + }, + pre: { + '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { + balance: '0x0de0b6b3a7640000', + code: '0x600a4960005500', + nonce: '0x00', + storage: {}, + }, + '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { + balance: '0x0de0b6b3a7640000', + code: '0x', + nonce: '0x00', + storage: {}, + }, + }, + transaction: { + accessLists: [ + [ + { + address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + ], + }, + ], + ], + blobVersionedHashes: [ + '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0001', + '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0002', + '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0003', + '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0004', + ], + data: ['0x00'], + gasLimit: ['0x3d0900'], + maxFeePerBlobGas: '0x0a', + maxFeePerGas: '0x012a05f200', + maxPriorityFeePerGas: '0x02', + nonce: '0x00', + secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', + sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', + to: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', + value: ['0x0186a0'], + }, + }, +} + +const argv = minimist(process.argv.slice(2)) + +const RUN_PROFILER: boolean = argv.profile ?? false + +argv.fork = 'Cancun' + +const FORK_CONFIG: string = argv.fork !== undefined ? argv.fork : DEFAULT_FORK_CONFIG +const FORK_CONFIG_TEST_SUITE = getRequiredForkConfigAlias(FORK_CONFIG) + +// Examples: Istanbul -> istanbul, MuirGlacier -> muirGlacier +const FORK_CONFIG_VM = FORK_CONFIG.charAt(0).toLowerCase() + FORK_CONFIG.substring(1) + +let bls: EVMBLSInterface +if (argv.bls !== undefined && argv.bls.toLowerCase() === 'mcl') { + await mcl.init(mcl.BLS12_381) + bls = new MCLBLS(mcl) + console.log('BLS library used: MCL (WASM)') +} else { + console.log('BLS library used: Noble (JavaScript)') + bls = new NobleBLS() +} + +let bn254: EVMBN254Interface +if (argv.bn254 !== undefined && argv.bn254.toLowerCase() === 'mcl') { + const rustBN = await initRustBN() + bn254 = new RustBN254(rustBN) + console.log('BN254 (alt_BN128) library used: rustbn.js (WASM)') +} else { + console.log('BN254 (alt_BN128) library used: Noble (JavaScript)') + bn254 = new NobleBN254() +} + +/** + * Run-time configuration + */ +const kzg = new microEthKZG(trustedSetup) +const runnerArgs: { + forkConfigVM: string + forkConfigTestSuite: string + common: Common + jsontrace?: boolean + dist?: boolean + data?: number + gasLimit?: number + value?: number + debug?: boolean + reps?: number + profile: boolean + bls: EVMBLSInterface + bn254: EVMBN254Interface + stateManager: string +} = { + forkConfigVM: FORK_CONFIG_VM, + forkConfigTestSuite: FORK_CONFIG_TEST_SUITE, + common: getCommon(FORK_CONFIG_VM, kzg), + jsontrace: argv.jsontrace, + dist: argv.dist, + data: argv.data, // GeneralStateTests + gasLimit: argv.gas, // GeneralStateTests + value: argv.value, // GeneralStateTests + debug: argv.debug, // BlockchainTests + reps: argv.reps, // test repetitions + bls, + profile: RUN_PROFILER, + bn254, + stateManager: argv.stateManager, +} + +// bloat tests to see how long it takes to run all tests +// for (let i = 0; i < 1000; i++) { +// testDataObject[`${i}`] = { +// "_info" : { +// "comment" : "BLOB001", +// "filling-rpc-server" : "evm version 1.14.4-unstable-3d8028a6-20240513", +// "filling-tool-version" : "retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++", +// "generatedTestHash" : "121104d3f52ee80ee2f762e750fba7476c87fdaa7e8d48b565e26a68f677d80c", +// "lllcversion" : "Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++", +// "solidity" : "Version: 0.8.21+commit.d9974bed.Linux.g++", +// "source" : "src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/wrongBlobhashVersionFiller.yml", +// "sourceHash" : "32cfd908b12300b9128770c6c0b944a35d546f25d3ddc2e237cd3cd3395607a5" +// }, +// "env" : { +// "currentBaseFee" : "0x07", +// "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", +// "currentDifficulty" : "0x020000", +// "currentExcessBlobGas" : "0x00", +// "currentGasLimit" : "0x1000000000", +// "currentNumber" : "0x01", +// "currentRandom" : "0x0000000000000000000000000000000000000000000000000000000000020000", +// "currentTimestamp" : "0x03e8" +// }, +// "post" : { +// "Cancun" : [ +// { +// "expectException" : "TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH", +// "hash" : "0x668817abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2", +// "indexes" : { +// "data" : 0, +// "gas" : 0, +// "value" : 0 +// }, +// "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", +// "txbytes" : "0x03f9010c01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af842a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8a045a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0daa1a9e47f815525ac6e11929160073fea1abf7acee286d4858fd4b1d9611fcda054d245d4a23cf599e6a8611692fdeab9be366108af5ba72554062346fa41a55a" +// } +// ] +// }, +// "pre" : { +// "0x095e7baea6a6c7c4c2dfeb977efac326af552d87" : { +// "balance" : "0x0de0b6b3a7640000", +// "code" : "0x60004960005500", +// "nonce" : "0x00", +// "storage" : { +// } +// }, +// "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { +// "balance" : "0x0de0b6b3a7640000", +// "code" : "0x", +// "nonce" : "0x00", +// "storage" : { +// } +// } +// }, +// "transaction" : { +// "accessLists" : [ +// [ +// { +// "address" : "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", +// "storageKeys" : [ +// "0x0000000000000000000000000000000000000000000000000000000000000000", +// "0x0000000000000000000000000000000000000000000000000000000000000001" +// ] +// } +// ] +// ], +// "blobVersionedHashes" : [ +// "0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", +// "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" +// ], +// "data" : [ +// "0x00" +// ], +// "gasLimit" : [ +// "0x3d0900" +// ], +// "maxFeePerBlobGas" : "0x0a", +// "maxFeePerGas" : "0x012a05f200", +// "maxPriorityFeePerGas" : "0x02", +// "nonce" : "0x00", +// "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", +// "sender" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", +// "to" : "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", +// "value" : [ +// "0x0186a0" +// ] +// } +// } +// } + +describe('TransactionTests', async () => { + for (const [testName, testDataRaw] of Object.entries(testDataObject)) { + const forkName = 'Cancun' + it(`${testName} - [${forkName}]`, async () => { + await runStateTest(runnerArgs, testDataRaw, undefined) + }, 120000) + } +}) From 5c066615ef29326f0132af25db601036ff6065a2 Mon Sep 17 00:00:00 2001 From: Amir Date: Mon, 19 May 2025 23:46:06 -0700 Subject: [PATCH 03/24] Add types for vm state test data --- packages/tx/test/types.ts | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/tx/test/types.ts b/packages/tx/test/types.ts index 37fc111f1fa..45249b46b4e 100644 --- a/packages/tx/test/types.ts +++ b/packages/tx/test/types.ts @@ -66,3 +66,61 @@ export type OfficialTransactionTestData = { result: ForksData txbytes: string } + +export interface EnvData { + currentBaseFee: string + currentCoinbase: string + currentDifficulty: string + currentExcessBlobGas: string + currentGasLimit: string + currentNumber: string + currentRandom: string + currentTimestamp: string +} + +export interface AccountState { + balance: string + code: string + nonce: string + storage: Record +} + +export interface Indexes { + data: number + gas: number + value: number +} + +export interface PostReceipt { + hash: string + indexes: Indexes + logs: string + txbytes: string +} + +export interface BlobTransaction extends TxData { + accessLists: Array<{ address: string; storageKeys: string[] }> + blobVersionedHashes: string[] + maxFeePerBlobGas: string + maxFeePerGas: string + maxPriorityFeePerGas: string + secretKey: string + sender: string + to: string +} + +export type OfficialStateTestData = { + _info: { + comment: string + generatedTestHash: string + filledwith: string // cspell:disable-line + lllcversion: string // cspell:disable-line + solidity: string + source: string + sourceHash: string + } + env: EnvData + pre: Record + post: Partial> + transaction: BlobTransaction +} From 2ea4ef2ed6151b4cc917eb4fcc353758fdcdf0b4 Mon Sep 17 00:00:00 2001 From: Amir Date: Tue, 20 May 2025 00:04:44 -0700 Subject: [PATCH 04/24] Move assert import into stateRunner.spec.ts --- .../tester/runners/GeneralStateTestsRunner.ts | 31 +++++++++++-------- packages/vm/test/tester/stateRunner.spec.ts | 4 +-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index 9832ea6b3d6..cd18c8bd9b9 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -13,14 +13,12 @@ import { } from '@ethereumjs/util' import { createVerkleTree } from '@ethereumjs/verkle' import * as verkle from 'micro-eth-signer/verkle' -import { assert } from 'vitest' - -import { createVM, runTx } from '../../../src/index.ts' -import { makeBlockFromEnv, makeTx, setupPreConditions } from '../../util.ts' import type { StateManagerInterface } from '@ethereumjs/common' import type { VerkleTree } from '@ethereumjs/verkle' import type * as tape from 'tape' +import { createVM, runTx } from '../../../src/index.ts' +import { makeBlockFromEnv, makeTx, setupPreConditions } from '../../util.ts' const loadVerkleCrypto = () => Promise.resolve(verkle) function parseTestCases( @@ -77,7 +75,12 @@ function parseTestCases( return testCases } -async function runTestCase(options: any, testData: any, t: tape.Test | undefined) { +function isTape(t: tape.Test | Chai.AssertStatic): t is tape.Test { + // tape.Test has .comment, chai.AssertStatic does not + return typeof (t as tape.Test).comment === 'function' +} + +async function runTestCase(options: any, testData: any, t: tape.Test | Chai.AssertStatic) { const begin = Date.now() // Copy the common object to not create long-lasting // references in memory which might prevent GC @@ -148,7 +151,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test | undefined opName: e.opcode.name, } - t && t.comment(JSON.stringify(opTrace)) + isTape(t) && t.comment(JSON.stringify(opTrace)) resolve?.() } @@ -156,7 +159,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test | undefined const stateRoot = { stateRoot: bytesToHex(await vm.stateManager.getStateRoot()), } - t && t.comment(JSON.stringify(stateRoot)) + isTape(t) && t.comment(JSON.stringify(stateRoot)) resolve?.() } @@ -190,12 +193,13 @@ async function runTestCase(options: any, testData: any, t: tape.Test | undefined const end = Date.now() const timeSpent = `${(end - begin) / 1000} secs` - t && t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) + isTape(t) && + t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) const msg = `error running test case for fork: ${options.forkConfigTestSuite}` - if (t !== undefined) { + if (isTape(t)) { t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) } else { - assert.isTrue(stateRootsAreEqual, msg) + t.isTrue(stateRootsAreEqual, msg) } vm.evm.events!.removeListener('step', stepHandler) @@ -206,7 +210,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test | undefined return parseFloat(timeSpent) } -export async function runStateTest(options: any, testData: any, t: tape.Test | undefined) { +export async function runStateTest(options: any, testData: any, t: tape.Test | Chai.AssertStatic) { const testCases = parseTestCases( options.forkConfigTestSuite, testData, @@ -215,7 +219,7 @@ export async function runStateTest(options: any, testData: any, t: tape.Test | u options.value, ) if (testCases.length === 0) { - t && t.comment(`No ${options.forkConfigTestSuite} post state defined, skip test`) + isTape(t) && t.comment(`No ${options.forkConfigTestSuite} post state defined, skip test`) return } for (const testCase of testCases) { @@ -224,7 +228,8 @@ export async function runStateTest(options: any, testData: any, t: tape.Test | u for (let x = 0; x < options.reps; x++) { totalTimeSpent += await runTestCase(options, testCase, t) } - t && t.comment(`Average test run: ${(totalTimeSpent / options.reps).toLocaleString()} s`) + isTape(t) && + t.comment(`Average test run: ${(totalTimeSpent / options.reps).toLocaleString()} s`) } else { await runTestCase(options, testCase, t) } diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index 71bc977e598..6823904c35e 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -3,7 +3,7 @@ import type { Common } from '@ethereumjs/common' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import * as mcl from 'mcl-wasm' import minimist from 'minimist' -import { describe, it } from 'vitest' +import { assert, describe, it } from 'vitest' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' @@ -422,7 +422,7 @@ describe('TransactionTests', async () => { for (const [testName, testDataRaw] of Object.entries(testDataObject)) { const forkName = 'Cancun' it(`${testName} - [${forkName}]`, async () => { - await runStateTest(runnerArgs, testDataRaw, undefined) + await runStateTest(runnerArgs, testDataRaw, assert) }, 120000) } }) From d606cad9ebd837178b5fa1063236aa8c7fef0f91 Mon Sep 17 00:00:00 2001 From: Amir Date: Tue, 20 May 2025 23:48:28 -0700 Subject: [PATCH 05/24] Use current test loader for vm state tests running vitest --- packages/vm/test/tester/stateRunner.spec.ts | 411 ++++---------------- 1 file changed, 68 insertions(+), 343 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index 6823904c35e..44d5bea0c24 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -7,6 +7,7 @@ import { assert, describe, it } from 'vitest' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' +import path from 'path' import { type EVMBLSInterface, type EVMBN254Interface, @@ -16,256 +17,22 @@ import { RustBN254, } from '@ethereumjs/evm' import { initRustBN } from 'rustbn-wasm' -import { DEFAULT_FORK_CONFIG, getCommon, getRequiredForkConfigAlias } from './config.ts' +import { + DEFAULT_FORK_CONFIG, + DEFAULT_TESTS_PATH, + getCommon, + getRequiredForkConfigAlias, + getSkipTests, + getTestDirs, +} from './config.ts' import { runStateTest } from './runners/GeneralStateTestsRunner.ts' - -const testDataObject = { - wrongBlobhashVersion: { - _info: { - comment: 'BLOB001', - 'filling-rpc-server': 'evm version 1.14.4-unstable-3d8028a6-20240513', - 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++', - generatedTestHash: '121104d3f52ee80ee2f762e750fba7476c87fdaa7e8d48b565e26a68f677d80c', - lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', - solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', - source: - 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/wrongBlobhashVersionFiller.yml', - sourceHash: '32cfd908b12300b9128770c6c0b944a35d546f25d3ddc2e237cd3cd3395607a5', - }, - env: { - currentBaseFee: '0x07', - currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', - currentDifficulty: '0x020000', - currentExcessBlobGas: '0x00', - currentGasLimit: '0x1000000000', - currentNumber: '0x01', - currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', - currentTimestamp: '0x03e8', - }, - post: { - Cancun: [ - { - expectException: 'TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH', - hash: '0x66887abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2', - indexes: { - data: 0, - gas: 0, - value: 0, - }, - logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - txbytes: - '0x03f9010c01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af842a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8a045a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0daa1a9e47f815525ac6e11929160073fea1abf7acee286d4858fd4b1d9611fcda054d245d4a23cf599e6a8611692fdeab9be366108af5ba72554062346fa41a55a', - }, - ], - }, - pre: { - '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { - balance: '0x0de0b6b3a7640000', - code: '0x60004960005500', - nonce: '0x00', - storage: {}, - }, - '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { - balance: '0x0de0b6b3a7640000', - code: '0x', - nonce: '0x00', - storage: {}, - }, - }, - transaction: { - accessLists: [ - [ - { - address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', - storageKeys: [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000001', - ], - }, - ], - ], - blobVersionedHashes: [ - '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', - '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', - ], - data: ['0x00'], - gasLimit: ['0x3d0900'], - maxFeePerBlobGas: '0x0a', - maxFeePerGas: '0x012a05f200', - maxPriorityFeePerGas: '0x02', - nonce: '0x00', - secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', - sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', - to: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', - value: ['0x0186a0'], - }, - }, - createBlobhashTx: { - _info: { - comment: 'BLOB002', - 'filling-rpc-server': 'evm version 1.14.4-unstable-3d8028a6-20240513', - 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++', - generatedTestHash: '14e2a257401391d59db3660d65588cd10e65eafdeb01efee34ccad42466e7998', - lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', - solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', - source: - 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/createBlobhashTxFiller.yml', - sourceHash: '57888e10e405e2329fd6d49f955f81fb04136c0bc699ab8c69919ed5e36e5b11', - }, - env: { - currentBaseFee: '0x07', - currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', - currentDifficulty: '0x020000', - currentExcessBlobGas: '0x00', - currentGasLimit: '0x1000000000', - currentNumber: '0x01', - currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', - currentTimestamp: '0x03e8', - }, - post: { - Cancun: [ - { - expectException: 'TransactionException.TYPE_3_TX_CONTRACT_CREATION', - hash: '0x668817abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2', - indexes: { - data: 0, - gas: 0, - value: 0, - }, - logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - txbytes: - '0x03f8d601800285012a05f200833d090080830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0fc12b67159a3567f8bdbc49e0be369a2e20e09d57a51c41310543a4128409464a02de0cfe5495c4f58ff60645ceda0afd67a4c90a70bc89fe207269435b35e5b67', - }, - ], - }, - pre: { - '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { - balance: '0x0de0b6b3a7640000', - code: '0x60004960005500', - nonce: '0x00', - storage: {}, - }, - '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { - balance: '0x0de0b6b3a7640000', - code: '0x', - nonce: '0x00', - storage: {}, - }, - }, - transaction: { - accessLists: [ - [ - { - address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', - storageKeys: [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000001', - ], - }, - ], - ], - blobVersionedHashes: ['0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8'], - data: ['0x00'], - gasLimit: ['0x3d0900'], - maxFeePerBlobGas: '0x0a', - maxFeePerGas: '0x012a05f200', - maxPriorityFeePerGas: '0x02', - nonce: '0x00', - secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', - sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', - to: '', - value: ['0x0186a0'], - }, - }, - blobhashListBounds4: { - _info: { - comment: 'BLOB006', - 'filling-rpc-server': 'evm version 1.13.11-unstable-765f2904-20240124', - 'filling-tool-version': 'retesteth-0.3.2-cancun+commit.ea13235b.Linux.g++', - generatedTestHash: '98c5bce6c1b8cd5a8bdafc9333b5d86587efe3a53d0515873d9f27110d3e3935', - lllcversion: 'Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++', - solidity: 'Version: 0.8.21+commit.d9974bed.Linux.g++', - source: - 'src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/blobhashListBounds4Filler.yml', - sourceHash: '5d992d68f3b613a49469fff6db6a6db728dc4526c36b03341da4d165b77b9bca', - }, - env: { - currentBaseFee: '0x07', - currentCoinbase: '0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba', - currentDifficulty: '0x020000', - currentExcessBlobGas: '0x00', - currentGasLimit: '0x1000000000', - currentNumber: '0x01', - currentRandom: '0x0000000000000000000000000000000000000000000000000000000000020000', - currentTimestamp: '0x03e8', - }, - post: { - Cancun: [ - { - hash: '0xdfef0eb2235050b176af2aa3d2b1ce64184bfa1fe5fa598c048a0adb2bbb7d86', - indexes: { - data: 0, - gas: 0, - value: 0, - }, - logs: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - txbytes: - '0x03f9014e01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af884a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0001a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0002a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0003a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f000401a04050f623a6a761402057018dbe8f7e9581bd8eed6362e7271e81b2861ca4cbdaa0671bf16648962e2435bf04e0e6c4eb9c0bc9971b251771f25d75e32a21fb3a7b', - }, - ], - }, - pre: { - '0x095e7baea6a6c7c4c2dfeb977efac326af552d87': { - balance: '0x0de0b6b3a7640000', - code: '0x600a4960005500', - nonce: '0x00', - storage: {}, - }, - '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b': { - balance: '0x0de0b6b3a7640000', - code: '0x', - nonce: '0x00', - storage: {}, - }, - }, - transaction: { - accessLists: [ - [ - { - address: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', - storageKeys: [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000001', - ], - }, - ], - ], - blobVersionedHashes: [ - '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0001', - '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0002', - '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0003', - '0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065f0004', - ], - data: ['0x00'], - gasLimit: ['0x3d0900'], - maxFeePerBlobGas: '0x0a', - maxFeePerGas: '0x012a05f200', - maxPriorityFeePerGas: '0x02', - nonce: '0x00', - secretKey: '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8', - sender: '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', - to: '0x095e7baea6a6c7c4c2dfeb977efac326af552d87', - value: ['0x0186a0'], - }, - }, -} +import { getTestsFromArgs } from './testLoader.ts' const argv = minimist(process.argv.slice(2)) -const RUN_PROFILER: boolean = argv.profile ?? false - -argv.fork = 'Cancun' +argv.fork = import.meta.env.VITE_FORK // use VITE_ as prefix for env arguments +const RUN_PROFILER: boolean = argv.profile ?? false const FORK_CONFIG: string = argv.fork !== undefined ? argv.fork : DEFAULT_FORK_CONFIG const FORK_CONFIG_TEST_SUITE = getRequiredForkConfigAlias(FORK_CONFIG) @@ -292,9 +59,6 @@ if (argv.bn254 !== undefined && argv.bn254.toLowerCase() === 'mcl') { bn254 = new NobleBN254() } -/** - * Run-time configuration - */ const kzg = new microEthKZG(trustedSetup) const runnerArgs: { forkConfigVM: string @@ -328,101 +92,62 @@ const runnerArgs: { stateManager: argv.stateManager, } -// bloat tests to see how long it takes to run all tests -// for (let i = 0; i < 1000; i++) { -// testDataObject[`${i}`] = { -// "_info" : { -// "comment" : "BLOB001", -// "filling-rpc-server" : "evm version 1.14.4-unstable-3d8028a6-20240513", -// "filling-tool-version" : "retesteth-0.3.2-cancun+commit.cae6bc33.Linux.g++", -// "generatedTestHash" : "121104d3f52ee80ee2f762e750fba7476c87fdaa7e8d48b565e26a68f677d80c", -// "lllcversion" : "Version: 0.5.14-develop.2023.7.11+commit.c58ab2c6.mod.Linux.g++", -// "solidity" : "Version: 0.8.21+commit.d9974bed.Linux.g++", -// "source" : "src/GeneralStateTestsFiller/Cancun/stEIP4844-blobtransactions/wrongBlobhashVersionFiller.yml", -// "sourceHash" : "32cfd908b12300b9128770c6c0b944a35d546f25d3ddc2e237cd3cd3395607a5" -// }, -// "env" : { -// "currentBaseFee" : "0x07", -// "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", -// "currentDifficulty" : "0x020000", -// "currentExcessBlobGas" : "0x00", -// "currentGasLimit" : "0x1000000000", -// "currentNumber" : "0x01", -// "currentRandom" : "0x0000000000000000000000000000000000000000000000000000000000020000", -// "currentTimestamp" : "0x03e8" -// }, -// "post" : { -// "Cancun" : [ -// { -// "expectException" : "TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH", -// "hash" : "0x668817abd521eb1401e0b8e52014bf6e36346dc786bf9084f3f03ac09b2ffaa2", -// "indexes" : { -// "data" : 0, -// "gas" : 0, -// "value" : 0 -// }, -// "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", -// "txbytes" : "0x03f9010c01800285012a05f200833d090094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010af842a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8a045a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0daa1a9e47f815525ac6e11929160073fea1abf7acee286d4858fd4b1d9611fcda054d245d4a23cf599e6a8611692fdeab9be366108af5ba72554062346fa41a55a" -// } -// ] -// }, -// "pre" : { -// "0x095e7baea6a6c7c4c2dfeb977efac326af552d87" : { -// "balance" : "0x0de0b6b3a7640000", -// "code" : "0x60004960005500", -// "nonce" : "0x00", -// "storage" : { -// } -// }, -// "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { -// "balance" : "0x0de0b6b3a7640000", -// "code" : "0x", -// "nonce" : "0x00", -// "storage" : { -// } -// } -// }, -// "transaction" : { -// "accessLists" : [ -// [ -// { -// "address" : "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", -// "storageKeys" : [ -// "0x0000000000000000000000000000000000000000000000000000000000000000", -// "0x0000000000000000000000000000000000000000000000000000000000000001" -// ] -// } -// ] -// ], -// "blobVersionedHashes" : [ -// "0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", -// "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" -// ], -// "data" : [ -// "0x00" -// ], -// "gasLimit" : [ -// "0x3d0900" -// ], -// "maxFeePerBlobGas" : "0x0a", -// "maxFeePerGas" : "0x012a05f200", -// "maxPriorityFeePerGas" : "0x02", -// "nonce" : "0x00", -// "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", -// "sender" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", -// "to" : "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", -// "value" : [ -// "0x0186a0" -// ] -// } -// } -// } +/** + * Configuration for getting the tests from the ethereum/tests repository + */ +const testGetterArgs: { + skipTests: string[] + runSkipped: string[] + forkConfig: string + file?: string + test?: string + dir?: string + excludeDir?: string + testsPath?: string + customStateTest?: string + directory?: string +} = { + skipTests: getSkipTests(argv.skip, argv.runSkipped !== undefined ? 'NONE' : 'ALL'), + runSkipped: getSkipTests(argv.runSkipped, 'NONE'), + forkConfig: FORK_CONFIG_TEST_SUITE, + file: argv.file, + test: argv.test, + dir: argv.dir, + excludeDir: argv.excludeDir, + testsPath: argv.testsPath, + customStateTest: argv.customStateTest, +} -describe('TransactionTests', async () => { - for (const [testName, testDataRaw] of Object.entries(testDataObject)) { - const forkName = 'Cancun' - it(`${testName} - [${forkName}]`, async () => { - await runStateTest(runnerArgs, testDataRaw, assert) - }, 120000) +describe('GeneralStateTests', async () => { + const dirs = getTestDirs(FORK_CONFIG_VM, 'GeneralStateTests') + for (const dir of dirs) { + await new Promise((resolve, _) => { + if (argv.customTestsPath !== undefined) { + testGetterArgs.directory = argv.customTestsPath as string + } else { + const testDir = testGetterArgs.dir ?? '' + const testsPath = testGetterArgs.testsPath ?? DEFAULT_TESTS_PATH + testGetterArgs.directory = path.join(testsPath, dir, testDir) + } + getTestsFromArgs( + dir, + async (fileName: string, subDir: string, testName: string, testDataRaw: any) => { + const runSkipped = testGetterArgs.runSkipped + const inRunSkipped = runSkipped.includes(fileName) + if (runSkipped.length === 0 || inRunSkipped === true) { + it(`file: ${subDir} test: ${testName}`, async () => { + await runStateTest(runnerArgs, testDataRaw, assert) + }, 120000) + } + }, + testGetterArgs, + ) + .then(() => { + resolve() + }) + .catch((error: string) => { + assert.fail(error) + }) + }) } }) From ac7f4544f0b7feac35b691e125af6340f8c53d59 Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 00:05:10 -0700 Subject: [PATCH 06/24] Fix errors --- packages/vm/test/tester/runners/GeneralStateTestsRunner.ts | 2 +- packages/vm/test/tester/stateRunner.spec.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index cd18c8bd9b9..e4e8904da84 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -199,7 +199,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test | Chai.Asse if (isTape(t)) { t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) } else { - t.isTrue(stateRootsAreEqual, msg) + t.strictEqual(stateRootsAreEqual, true, msg) } vm.evm.events!.removeListener('step', stepHandler) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index 44d5bea0c24..f7ba8c2c064 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -30,6 +30,7 @@ import { getTestsFromArgs } from './testLoader.ts' const argv = minimist(process.argv.slice(2)) +//@ts-expect-error vitest env parameter access argv.fork = import.meta.env.VITE_FORK // use VITE_ as prefix for env arguments const RUN_PROFILER: boolean = argv.profile ?? false From 70aea767dc839d3704a37a7dc1961f904d75d76e Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 00:05:54 -0700 Subject: [PATCH 07/24] Revert "Add types for vm state test data" This reverts commit 5c066615ef29326f0132af25db601036ff6065a2. --- packages/tx/test/types.ts | 58 --------------------------------------- 1 file changed, 58 deletions(-) diff --git a/packages/tx/test/types.ts b/packages/tx/test/types.ts index 45249b46b4e..37fc111f1fa 100644 --- a/packages/tx/test/types.ts +++ b/packages/tx/test/types.ts @@ -66,61 +66,3 @@ export type OfficialTransactionTestData = { result: ForksData txbytes: string } - -export interface EnvData { - currentBaseFee: string - currentCoinbase: string - currentDifficulty: string - currentExcessBlobGas: string - currentGasLimit: string - currentNumber: string - currentRandom: string - currentTimestamp: string -} - -export interface AccountState { - balance: string - code: string - nonce: string - storage: Record -} - -export interface Indexes { - data: number - gas: number - value: number -} - -export interface PostReceipt { - hash: string - indexes: Indexes - logs: string - txbytes: string -} - -export interface BlobTransaction extends TxData { - accessLists: Array<{ address: string; storageKeys: string[] }> - blobVersionedHashes: string[] - maxFeePerBlobGas: string - maxFeePerGas: string - maxPriorityFeePerGas: string - secretKey: string - sender: string - to: string -} - -export type OfficialStateTestData = { - _info: { - comment: string - generatedTestHash: string - filledwith: string // cspell:disable-line - lllcversion: string // cspell:disable-line - solidity: string - source: string - sourceHash: string - } - env: EnvData - pre: Record - post: Partial> - transaction: BlobTransaction -} From c9e0c26dfff1eb27c29fab877210b5f34beab177 Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 15:45:14 -0700 Subject: [PATCH 08/24] Update test retrieval and execution functions --- packages/vm/test/tester/stateRunner.spec.ts | 83 +++++++++++++-------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index f7ba8c2c064..c39bb331132 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -2,7 +2,6 @@ import type { Common } from '@ethereumjs/common' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import * as mcl from 'mcl-wasm' -import minimist from 'minimist' import { assert, describe, it } from 'vitest' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' @@ -28,10 +27,13 @@ import { import { runStateTest } from './runners/GeneralStateTestsRunner.ts' import { getTestsFromArgs } from './testLoader.ts' -const argv = minimist(process.argv.slice(2)) +const argv: any = {} //@ts-expect-error vitest env parameter access argv.fork = import.meta.env.VITE_FORK // use VITE_ as prefix for env arguments +argv.file = import.meta.env.VITE_FILE +argv.test = import.meta.env.VITE_TEST +argv.dir = import.meta.env.VITE_DIR const RUN_PROFILER: boolean = argv.profile ?? false const FORK_CONFIG: string = argv.fork !== undefined ? argv.fork : DEFAULT_FORK_CONFIG @@ -119,36 +121,51 @@ const testGetterArgs: { customStateTest: argv.customStateTest, } -describe('GeneralStateTests', async () => { - const dirs = getTestDirs(FORK_CONFIG_VM, 'GeneralStateTests') - for (const dir of dirs) { - await new Promise((resolve, _) => { - if (argv.customTestsPath !== undefined) { - testGetterArgs.directory = argv.customTestsPath as string - } else { - const testDir = testGetterArgs.dir ?? '' - const testsPath = testGetterArgs.testsPath ?? DEFAULT_TESTS_PATH - testGetterArgs.directory = path.join(testsPath, dir, testDir) - } - getTestsFromArgs( - dir, - async (fileName: string, subDir: string, testName: string, testDataRaw: any) => { - const runSkipped = testGetterArgs.runSkipped - const inRunSkipped = runSkipped.includes(fileName) - if (runSkipped.length === 0 || inRunSkipped === true) { - it(`file: ${subDir} test: ${testName}`, async () => { - await runStateTest(runnerArgs, testDataRaw, assert) - }, 120000) - } - }, - testGetterArgs, - ) - .then(() => { - resolve() - }) - .catch((error: string) => { - assert.fail(error) - }) - }) +interface LoadedTest { + dir: string + fileName: string + subDir: string + testName: string + testData: any +} +const allTests: LoadedTest[] = [] + +const dirs = getTestDirs(FORK_CONFIG_VM, 'GeneralStateTests') +for (const dir of dirs) { + if (argv.customTestsPath !== undefined) { + testGetterArgs.directory = argv.customTestsPath as string + } else { + const testDir = testGetterArgs.dir ?? '' + const testsPath = testGetterArgs.testsPath ?? DEFAULT_TESTS_PATH + testGetterArgs.directory = path.join(testsPath, dir, testDir) + } + + const tests: LoadedTest[] = [] + try { + await getTestsFromArgs( + dir, + async (fileName: string, subDir: string, testName: string, testData: any) => { + console.log(`file: ${subDir} test: ${testName}`) + const runSkipped = testGetterArgs.runSkipped + const inRunSkipped = runSkipped.includes(fileName) + if (runSkipped.length === 0 || inRunSkipped === true) { + tests.push({ dir, fileName, subDir, testName, testData }) + } + }, + testGetterArgs, + ) + } catch (e) { + console.log(e) + continue + } + + allTests.push(...tests) +} + +describe('GeneralStateTests', () => { + for (const { subDir, testName, testData } of allTests) { + it(`file: ${subDir} test: ${testName}`, async () => { + await runStateTest(runnerArgs, testData, assert) + }, 120000) } }) From 9c407defeed998e6bb890a2917378157a0659b3f Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 15:45:42 -0700 Subject: [PATCH 09/24] Use vitest state runner for CI job --- .github/workflows/vm-pr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/vm-pr.yml b/.github/workflows/vm-pr.yml index 8068dfd02e4..8dbc06bcf4c 100644 --- a/.github/workflows/vm-pr.yml +++ b/.github/workflows/vm-pr.yml @@ -115,7 +115,8 @@ jobs: key: ${{ inputs.submodule-cache-key}} fail-on-cache-miss: true - - run: npm run test:state -- --fork=${{ matrix.fork }} --verify-test-amount-alltests + # - run: npm run test:state -- --fork=${{ matrix.fork }} --verify-test-amount-alltests + - run: VITE_FORK=$${{matrix.fork}} npx vitest run test/tester/stateRunner.spec.ts vm-state-extended: if: contains(join(github.event.pull_request.labels.*.name, ' '), 'Test all hardforks') From 784c14cbe3076c8dc8c02fc80512bbb4b48d73d9 Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 15:58:21 -0700 Subject: [PATCH 10/24] Fix parameter passing --- .github/workflows/vm-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/vm-pr.yml b/.github/workflows/vm-pr.yml index 8dbc06bcf4c..92ab5b5ce4f 100644 --- a/.github/workflows/vm-pr.yml +++ b/.github/workflows/vm-pr.yml @@ -116,7 +116,7 @@ jobs: fail-on-cache-miss: true # - run: npm run test:state -- --fork=${{ matrix.fork }} --verify-test-amount-alltests - - run: VITE_FORK=$${{matrix.fork}} npx vitest run test/tester/stateRunner.spec.ts + - run: VITE_FORK=${{matrix.fork}} npx vitest run test/tester/stateRunner.spec.ts vm-state-extended: if: contains(join(github.event.pull_request.labels.*.name, ' '), 'Test all hardforks') From dbf44bed64183cd4a0cde06e95a8ff2a6723b14c Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 21 May 2025 16:29:47 -0700 Subject: [PATCH 11/24] Use deepEqual --- packages/vm/test/tester/runners/GeneralStateTestsRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index e4e8904da84..f8c15652c54 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -199,7 +199,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test | Chai.Asse if (isTape(t)) { t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) } else { - t.strictEqual(stateRootsAreEqual, true, msg) + t.deepEqual(stateManagerStateRoot, testDataPostStateRoot, msg) } vm.evm.events!.removeListener('step', stepHandler) From e39ed300a652bf8e94b8b863b66ce143239677b2 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 10:20:50 -0700 Subject: [PATCH 12/24] Exclude state test runner from unit testing --- packages/vm/vitest.config.browser.mts | 2 ++ packages/vm/vitest.config.coverage.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/vm/vitest.config.browser.mts b/packages/vm/vitest.config.browser.mts index feec1b532ee..6438d80f1f8 100644 --- a/packages/vm/vitest.config.browser.mts +++ b/packages/vm/vitest.config.browser.mts @@ -13,6 +13,8 @@ export default mergeConfig( 'test/api/EIPs/eip-6800-verkle.spec.ts', // Uses NodeJS builtins and we don't need to fill tests in browser anyway 'test/api/t8ntool/t8ntool.spec.ts', + // test runners are ran only in ci + 'test/tester/stateRunner.spec.ts' ], }, }), diff --git a/packages/vm/vitest.config.coverage.ts b/packages/vm/vitest.config.coverage.ts index 37a90957435..f35caa7002d 100644 --- a/packages/vm/vitest.config.coverage.ts +++ b/packages/vm/vitest.config.coverage.ts @@ -13,5 +13,6 @@ export default defineConfig({ all: true, reporter: ['lcov'], }, + exclude: ['test/tester/stateRunner.spec.ts'], }, }) From 9c9cf3afa03db208c23e25b661ef74165ba99afb Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 12:05:44 -0700 Subject: [PATCH 13/24] Add all parameters from legacy runner --- packages/vm/test/tester/stateRunner.spec.ts | 80 ++++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index c39bb331132..b762fd4445e 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -27,16 +27,76 @@ import { import { runStateTest } from './runners/GeneralStateTestsRunner.ts' import { getTestsFromArgs } from './testLoader.ts' -const argv: any = {} - -//@ts-expect-error vitest env parameter access -argv.fork = import.meta.env.VITE_FORK // use VITE_ as prefix for env arguments -argv.file = import.meta.env.VITE_FILE -argv.test = import.meta.env.VITE_TEST -argv.dir = import.meta.env.VITE_DIR +// use VITE_ as prefix for env arguments +const argv: { + fork?: string + bls?: string + bn254?: string + stateManager?: string + forkConfig?: string + file?: string + test?: string + dir?: string + excludeDir?: string + testsPath?: string + customStateTest?: string + directory?: string + skip?: string + skipTests?: string[] + runSkipped?: string[] + data?: number + gas?: number + value?: number + reps?: number + verifyTestAmountAllTests?: number + expectedTestAmount?: number + debug?: boolean + profile?: boolean + jsontrace?: boolean + dist?: boolean +} = { + // string flags + fork: import.meta.env.VITE_FORK, + bls: import.meta.env.VITE_BLS, + bn254: import.meta.env.VITE_BN254, + stateManager: import.meta.env.VITE_STATE_MANAGER, + forkConfig: import.meta.env.VITE_FORK_CONFIG, + file: import.meta.env.VITE_FILE, + test: import.meta.env.VITE_TEST, + dir: import.meta.env.VITE_DIR, + excludeDir: import.meta.env.VITE_EXCLUDE_DIR, + testsPath: import.meta.env.VITE_TESTS_PATH, + customStateTest: import.meta.env.VITE_CUSTOM_STATE_TEST, + directory: import.meta.env.VITE_DIRECTORY, + skip: import.meta.env.VITE_SKIP, + + // boolean flags + jsontrace: import.meta.env.VITE_JSONTRACE === 'true', + dist: import.meta.env.VITE_DIST === 'true', + debug: import.meta.env.VITE_DEBUG === 'true', + profile: import.meta.env.VITE_PROFILE === 'true', + + // numeric flags + data: import.meta.env.VITE_DATA !== undefined ? Number(import.meta.env.VITE_DATA) : undefined, + gas: import.meta.env.VITE_GAS !== undefined ? Number(import.meta.env.VITE_GAS) : undefined, + value: import.meta.env.VITE_VALUE !== undefined ? Number(import.meta.env.VITE_VALUE) : undefined, + reps: import.meta.env.VITE_REPS !== undefined ? Number(import.meta.env.VITE_REPS) : undefined, + verifyTestAmountAllTests: + import.meta.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS !== undefined + ? Number(import.meta.env.VITE_VERIFYTESTAMOUNTALLTESTS) + : undefined, + expectedTestAmount: + import.meta.env.VITE_EXPECTED_TEST_AMOUNT !== undefined + ? Number(import.meta.env.VITE_EXPECTEDTESTAMOUNT) + : undefined, + + // array flags + skipTests: (import.meta.env.VITE_SKIP_TESTS as string)?.split(','), + runSkipped: (import.meta.env.VITE_RUN_SKIPPED as string)?.split(','), +} const RUN_PROFILER: boolean = argv.profile ?? false -const FORK_CONFIG: string = argv.fork !== undefined ? argv.fork : DEFAULT_FORK_CONFIG +const FORK_CONFIG: string = argv.fork ?? DEFAULT_FORK_CONFIG const FORK_CONFIG_TEST_SUITE = getRequiredForkConfigAlias(FORK_CONFIG) // Examples: Istanbul -> istanbul, MuirGlacier -> muirGlacier @@ -129,7 +189,6 @@ interface LoadedTest { testData: any } const allTests: LoadedTest[] = [] - const dirs = getTestDirs(FORK_CONFIG_VM, 'GeneralStateTests') for (const dir of dirs) { if (argv.customTestsPath !== undefined) { @@ -145,7 +204,6 @@ for (const dir of dirs) { await getTestsFromArgs( dir, async (fileName: string, subDir: string, testName: string, testData: any) => { - console.log(`file: ${subDir} test: ${testName}`) const runSkipped = testGetterArgs.runSkipped const inRunSkipped = runSkipped.includes(fileName) if (runSkipped.length === 0 || inRunSkipped === true) { @@ -155,7 +213,7 @@ for (const dir of dirs) { testGetterArgs, ) } catch (e) { - console.log(e) + console.log(e) // TODO failing to discover LegacyTests paths that are hardcoded in getTestDirs continue } From 1c660331337b60ffd748a83f60c50c4473d7d45f Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 12:14:59 -0700 Subject: [PATCH 14/24] Fix parameter typing --- packages/vm/test/tester/config.ts | 2 +- packages/vm/test/tester/stateRunner.spec.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/vm/test/tester/config.ts b/packages/vm/test/tester/config.ts index 96aee521d34..596dff6204a 100644 --- a/packages/vm/test/tester/config.ts +++ b/packages/vm/test/tester/config.ts @@ -507,7 +507,7 @@ export function getExpectedTests( * @param defaultChoice if to use `NONE` or `ALL` as default choice * @returns array with test names */ -export function getSkipTests(choices: string, defaultChoice: string): string[] { +export function getSkipTests(choices: string | undefined, defaultChoice: string): string[] { let skipTests: string[] = [] if (!choices) { choices = defaultChoice diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index b762fd4445e..b8eb14482b2 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -42,8 +42,9 @@ const argv: { customStateTest?: string directory?: string skip?: string - skipTests?: string[] - runSkipped?: string[] + skipTests?: string + runSkipped?: string + customTestsPath?: string data?: number gas?: number value?: number @@ -69,6 +70,7 @@ const argv: { customStateTest: import.meta.env.VITE_CUSTOM_STATE_TEST, directory: import.meta.env.VITE_DIRECTORY, skip: import.meta.env.VITE_SKIP, + customTestsPath: import.meta.env.VITE_CUSTOM_TESTS_PATH, // boolean flags jsontrace: import.meta.env.VITE_JSONTRACE === 'true', @@ -91,8 +93,8 @@ const argv: { : undefined, // array flags - skipTests: (import.meta.env.VITE_SKIP_TESTS as string)?.split(','), - runSkipped: (import.meta.env.VITE_RUN_SKIPPED as string)?.split(','), + skipTests: import.meta.env.VITE_SKIP_TESTS, + runSkipped: import.meta.env.VITE_RUN_SKIPPED, } const RUN_PROFILER: boolean = argv.profile ?? false @@ -137,7 +139,7 @@ const runnerArgs: { profile: boolean bls: EVMBLSInterface bn254: EVMBN254Interface - stateManager: string + stateManager?: string } = { forkConfigVM: FORK_CONFIG_VM, forkConfigTestSuite: FORK_CONFIG_TEST_SUITE, From 2cd0a46c18ecfeb86b4073bfe50aece1af89f959 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 12:42:54 -0700 Subject: [PATCH 15/24] Catch errors and fail tests that throw errors --- packages/vm/test/tester/stateRunner.spec.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index b8eb14482b2..c87a93e596d 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -225,7 +225,11 @@ for (const dir of dirs) { describe('GeneralStateTests', () => { for (const { subDir, testName, testData } of allTests) { it(`file: ${subDir} test: ${testName}`, async () => { - await runStateTest(runnerArgs, testData, assert) + try { + await runStateTest(runnerArgs, testData, assert) + } catch (e: any) { + assert.fail(e?.toString()) + } }, 120000) } }) From 93264b0143f5c9d048d2fbad446216aac34e2665 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 12:53:16 -0700 Subject: [PATCH 16/24] Add verifyTestAmountAllTests functionality to count and compare expected and actual test executions --- packages/vm/test/tester/stateRunner.spec.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index c87a93e596d..e2b5a63c0a4 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -20,6 +20,7 @@ import { DEFAULT_FORK_CONFIG, DEFAULT_TESTS_PATH, getCommon, + getExpectedTests, getRequiredForkConfigAlias, getSkipTests, getTestDirs, @@ -85,11 +86,11 @@ const argv: { reps: import.meta.env.VITE_REPS !== undefined ? Number(import.meta.env.VITE_REPS) : undefined, verifyTestAmountAllTests: import.meta.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS !== undefined - ? Number(import.meta.env.VITE_VERIFYTESTAMOUNTALLTESTS) + ? Number(import.meta.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS) : undefined, expectedTestAmount: import.meta.env.VITE_EXPECTED_TEST_AMOUNT !== undefined - ? Number(import.meta.env.VITE_EXPECTEDTESTAMOUNT) + ? Number(import.meta.env.VITE_EXPECTED_TEST_AMOUNT) : undefined, // array flags @@ -222,9 +223,17 @@ for (const dir of dirs) { allTests.push(...tests) } +const expectedTests: number | undefined = + argv.verifyTestAmountAllTests !== undefined && argv.verifyTestAmountAllTests > 0 + ? getExpectedTests(FORK_CONFIG_VM, 'GeneralStateTests') + : argv.expectedTestAmount !== undefined && argv.expectedTestAmount > 0 + ? argv.expectedTestAmount + : undefined +let testCount = 0 describe('GeneralStateTests', () => { for (const { subDir, testName, testData } of allTests) { it(`file: ${subDir} test: ${testName}`, async () => { + testCount++ try { await runStateTest(runnerArgs, testData, assert) } catch (e: any) { @@ -232,4 +241,8 @@ describe('GeneralStateTests', () => { } }, 120000) } + + if (expectedTests !== undefined) { + assert.isTrue(testCount >= expectedTests, `expected ${expectedTests} checks, got ${testCount}`) + } }) From d61a68c148df9356104d113a9852743997474ee8 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 12:53:39 -0700 Subject: [PATCH 17/24] Activate test count comparisons in CI runs --- .github/workflows/vm-pr.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/vm-pr.yml b/.github/workflows/vm-pr.yml index 92ab5b5ce4f..a2ffc4e7602 100644 --- a/.github/workflows/vm-pr.yml +++ b/.github/workflows/vm-pr.yml @@ -115,8 +115,7 @@ jobs: key: ${{ inputs.submodule-cache-key}} fail-on-cache-miss: true - # - run: npm run test:state -- --fork=${{ matrix.fork }} --verify-test-amount-alltests - - run: VITE_FORK=${{matrix.fork}} npx vitest run test/tester/stateRunner.spec.ts + - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=true npx vitest run test/tester/stateRunner.spec.ts vm-state-extended: if: contains(join(github.event.pull_request.labels.*.name, ' '), 'Test all hardforks') @@ -178,7 +177,7 @@ jobs: fail-on-cache-miss: true - - run: npm run test:state -- --fork=${{ matrix.fork }} --verify-test-amount-alltests + - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=true npx vitest run test/tester/stateRunner.spec.ts vm-blockchain: runs-on: ubuntu-latest From 7f9f199d2b5b18a91b61502d18d8693cbb70f4d4 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 13:57:07 -0700 Subject: [PATCH 18/24] Fix test count comparison --- packages/vm/test/tester/stateRunner.spec.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index e2b5a63c0a4..c0351293998 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -2,7 +2,7 @@ import type { Common } from '@ethereumjs/common' import { trustedSetup } from '@paulmillr/trusted-setups/fast.js' import * as mcl from 'mcl-wasm' -import { assert, describe, it } from 'vitest' +import { assert, afterAll, describe, it } from 'vitest' import { KZG as microEthKZG } from 'micro-eth-signer/kzg' @@ -242,7 +242,12 @@ describe('GeneralStateTests', () => { }, 120000) } - if (expectedTests !== undefined) { - assert.isTrue(testCount >= expectedTests, `expected ${expectedTests} checks, got ${testCount}`) - } + afterAll(() => { + if (expectedTests !== undefined) { + assert.isTrue( + testCount >= expectedTests, + `expected ${expectedTests} checks, got ${testCount}`, + ) + } + }) }) From db518f86ace958194996c86da448b2d6768e2c28 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 13:58:44 -0700 Subject: [PATCH 19/24] Use env variables from process --- packages/vm/test/tester/stateRunner.spec.ts | 56 ++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index c0351293998..57c70a902ca 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -58,44 +58,44 @@ const argv: { dist?: boolean } = { // string flags - fork: import.meta.env.VITE_FORK, - bls: import.meta.env.VITE_BLS, - bn254: import.meta.env.VITE_BN254, - stateManager: import.meta.env.VITE_STATE_MANAGER, - forkConfig: import.meta.env.VITE_FORK_CONFIG, - file: import.meta.env.VITE_FILE, - test: import.meta.env.VITE_TEST, - dir: import.meta.env.VITE_DIR, - excludeDir: import.meta.env.VITE_EXCLUDE_DIR, - testsPath: import.meta.env.VITE_TESTS_PATH, - customStateTest: import.meta.env.VITE_CUSTOM_STATE_TEST, - directory: import.meta.env.VITE_DIRECTORY, - skip: import.meta.env.VITE_SKIP, - customTestsPath: import.meta.env.VITE_CUSTOM_TESTS_PATH, + fork: process.env.VITE_FORK, + bls: process.env.VITE_BLS, + bn254: process.env.VITE_BN254, + stateManager: process.env.VITE_STATE_MANAGER, + forkConfig: process.env.VITE_FORK_CONFIG, + file: process.env.VITE_FILE, + test: process.env.VITE_TEST, + dir: process.env.VITE_DIR, + excludeDir: process.env.VITE_EXCLUDE_DIR, + testsPath: process.env.VITE_TESTS_PATH, + customStateTest: process.env.VITE_CUSTOM_STATE_TEST, + directory: process.env.VITE_DIRECTORY, + skip: process.env.VITE_SKIP, + customTestsPath: process.env.VITE_CUSTOM_TESTS_PATH, // boolean flags - jsontrace: import.meta.env.VITE_JSONTRACE === 'true', - dist: import.meta.env.VITE_DIST === 'true', - debug: import.meta.env.VITE_DEBUG === 'true', - profile: import.meta.env.VITE_PROFILE === 'true', + jsontrace: process.env.VITE_JSONTRACE === 'true', + dist: process.env.VITE_DIST === 'true', + debug: process.env.VITE_DEBUG === 'true', + profile: process.env.VITE_PROFILE === 'true', // numeric flags - data: import.meta.env.VITE_DATA !== undefined ? Number(import.meta.env.VITE_DATA) : undefined, - gas: import.meta.env.VITE_GAS !== undefined ? Number(import.meta.env.VITE_GAS) : undefined, - value: import.meta.env.VITE_VALUE !== undefined ? Number(import.meta.env.VITE_VALUE) : undefined, - reps: import.meta.env.VITE_REPS !== undefined ? Number(import.meta.env.VITE_REPS) : undefined, + data: process.env.VITE_DATA !== undefined ? Number(process.env.VITE_DATA) : undefined, + gas: process.env.VITE_GAS !== undefined ? Number(process.env.VITE_GAS) : undefined, + value: process.env.VITE_VALUE !== undefined ? Number(process.env.VITE_VALUE) : undefined, + reps: process.env.VITE_REPS !== undefined ? Number(process.env.VITE_REPS) : undefined, verifyTestAmountAllTests: - import.meta.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS !== undefined - ? Number(import.meta.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS) + process.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS !== undefined + ? Number(process.env.VITE_VERIFY_TEST_AMOUNT_ALL_TESTS) : undefined, expectedTestAmount: - import.meta.env.VITE_EXPECTED_TEST_AMOUNT !== undefined - ? Number(import.meta.env.VITE_EXPECTED_TEST_AMOUNT) + process.env.VITE_EXPECTED_TEST_AMOUNT !== undefined + ? Number(process.env.VITE_EXPECTED_TEST_AMOUNT) : undefined, // array flags - skipTests: import.meta.env.VITE_SKIP_TESTS, - runSkipped: import.meta.env.VITE_RUN_SKIPPED, + skipTests: process.env.VITE_SKIP_TESTS, + runSkipped: process.env.VITE_RUN_SKIPPED, } const RUN_PROFILER: boolean = argv.profile ?? false From 46a3a113f89775b7c223db35b80f720570b426af Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 22 May 2025 14:00:56 -0700 Subject: [PATCH 20/24] Fix parameter passing in ci job --- .github/workflows/vm-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/vm-pr.yml b/.github/workflows/vm-pr.yml index a2ffc4e7602..a1998eb1dd8 100644 --- a/.github/workflows/vm-pr.yml +++ b/.github/workflows/vm-pr.yml @@ -115,7 +115,7 @@ jobs: key: ${{ inputs.submodule-cache-key}} fail-on-cache-miss: true - - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=true npx vitest run test/tester/stateRunner.spec.ts + - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=1 npx vitest run test/tester/stateRunner.spec.ts vm-state-extended: if: contains(join(github.event.pull_request.labels.*.name, ' '), 'Test all hardforks') @@ -177,7 +177,7 @@ jobs: fail-on-cache-miss: true - - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=true npx vitest run test/tester/stateRunner.spec.ts + - run: VITE_FORK=${{matrix.fork}} VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=1 npx vitest run test/tester/stateRunner.spec.ts vm-blockchain: runs-on: ubuntu-latest From 586ef732f2f601d6637e29d5add70aaf37a832a7 Mon Sep 17 00:00:00 2001 From: am1r021 Date: Wed, 28 May 2025 09:13:33 -0700 Subject: [PATCH 21/24] Update packages/vm/test/tester/stateRunner.spec.ts --- packages/vm/test/tester/stateRunner.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index 57c70a902ca..69ad00c8168 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -216,7 +216,7 @@ for (const dir of dirs) { testGetterArgs, ) } catch (e) { - console.log(e) // TODO failing to discover LegacyTests paths that are hardcoded in getTestDirs + console.log(e) continue } From 8abe92057a340d0cbba2dbae22bae2fa7c536ebc Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 28 May 2025 16:48:19 -0700 Subject: [PATCH 22/24] Calculate testcount for each testcase --- .../vm/test/tester/runners/GeneralStateTestsRunner.ts | 1 + packages/vm/test/tester/stateRunner.spec.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index f8c15652c54..fb1fb86ed48 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -232,6 +232,7 @@ export async function runStateTest(options: any, testData: any, t: tape.Test | C t.comment(`Average test run: ${(totalTimeSpent / options.reps).toLocaleString()} s`) } else { await runTestCase(options, testCase, t) + options.testCount++ } } } diff --git a/packages/vm/test/tester/stateRunner.spec.ts b/packages/vm/test/tester/stateRunner.spec.ts index 57c70a902ca..5fe9aed76bc 100644 --- a/packages/vm/test/tester/stateRunner.spec.ts +++ b/packages/vm/test/tester/stateRunner.spec.ts @@ -141,6 +141,7 @@ const runnerArgs: { bls: EVMBLSInterface bn254: EVMBN254Interface stateManager?: string + testCount: number } = { forkConfigVM: FORK_CONFIG_VM, forkConfigTestSuite: FORK_CONFIG_TEST_SUITE, @@ -156,6 +157,7 @@ const runnerArgs: { profile: RUN_PROFILER, bn254, stateManager: argv.stateManager, + testCount: 0, } /** @@ -229,11 +231,9 @@ const expectedTests: number | undefined = : argv.expectedTestAmount !== undefined && argv.expectedTestAmount > 0 ? argv.expectedTestAmount : undefined -let testCount = 0 describe('GeneralStateTests', () => { for (const { subDir, testName, testData } of allTests) { it(`file: ${subDir} test: ${testName}`, async () => { - testCount++ try { await runStateTest(runnerArgs, testData, assert) } catch (e: any) { @@ -245,8 +245,8 @@ describe('GeneralStateTests', () => { afterAll(() => { if (expectedTests !== undefined) { assert.isTrue( - testCount >= expectedTests, - `expected ${expectedTests} checks, got ${testCount}`, + runnerArgs.testCount >= expectedTests, + `expected ${expectedTests} checks, got ${runnerArgs.testCount}`, ) } }) From f645c96360de963df799a55474f889cf7d24d52e Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 29 May 2025 12:01:23 -0700 Subject: [PATCH 23/24] Remove duplicate tape assert --- packages/vm/test/tester/runners/GeneralStateTestsRunner.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts index fb1fb86ed48..fcbecd766d9 100644 --- a/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/test/tester/runners/GeneralStateTestsRunner.ts @@ -193,8 +193,6 @@ async function runTestCase(options: any, testData: any, t: tape.Test | Chai.Asse const end = Date.now() const timeSpent = `${(end - begin) / 1000} secs` - isTape(t) && - t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) const msg = `error running test case for fork: ${options.forkConfigTestSuite}` if (isTape(t)) { t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`) From d5dd1a67f0caf6fc9678bdc9963e0f2687133116 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 29 May 2025 12:03:28 -0700 Subject: [PATCH 24/24] Switch state runner scripts to use new runner instead of legacy --- packages/vm/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vm/package.json b/packages/vm/package.json index efa7c2edcd7..c792be8f397 100644 --- a/packages/vm/package.json +++ b/packages/vm/package.json @@ -52,9 +52,9 @@ "test:blockchain:transitionForks": "echo 'ByzantiumToConstantinopleFixAt5 EIP158ToByzantiumAt5 FrontierToHomesteadAt5 HomesteadToDaoAt5 HomesteadToEIP150At5 BerlinToLondonAt5' | xargs -n1 | xargs -I v1 npm run tester -- --blockchain --fork=v1 --verify-test-amount-alltests", "test:buildIntegrity": "npm run test:state -- --test='stackOverflow'", "test:state": "npm run tester -- --state", - "test:state:allForks": "echo 'Chainstart Homestead dao TangerineWhistle SpuriousDragon Byzantium Constantinople Petersburg Istanbul MuirGlacier Berlin London ByzantiumToConstantinopleFixAt5 EIP158ToByzantiumAt5 FrontierToHomesteadAt5 HomesteadToDaoAt5 HomesteadToEIP150At5 BerlinToLondonAt5 Cancun' | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1 --verify-test-amount-alltests", - "test:state:selectedForks": "echo 'Homestead TangerineWhistle SpuriousDragon Petersburg Berlin London Cancun' | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1 --verify-test-amount-alltests", - "test:state:slow": "npm run test:state -- --runSkipped=slow", + "test:state:allForks": "echo 'Chainstart Homestead dao TangerineWhistle SpuriousDragon Byzantium Constantinople Petersburg Istanbul MuirGlacier Berlin London ByzantiumToConstantinopleFixAt5 EIP158ToByzantiumAt5 FrontierToHomesteadAt5 HomesteadToDaoAt5 HomesteadToEIP150At5 BerlinToLondonAt5 Cancun' | xargs -n1 | xargs -I v1 VITEST_FORK=v1 VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=1 npx vitest test/tester/stateRunner.spec.ts", + "test:state:selectedForks": "echo 'Homestead TangerineWhistle SpuriousDragon Petersburg Berlin London Cancun' | xargs -n1 | xargs -I v1 VITEST_FORK=v1 VITE_VERIFY_TEST_AMOUNT_ALL_TESTS=1 npx vitest test/tester/stateRunner.spec.ts", + "test:state:slow": "VITE_RUN_SKIPPED=slow npx vitest test/tester/stateRunner.spec.ts", "tester": "tsx --conditions=typescript ./test/tester --stack-size=1500", "tsc": "../../config/cli/ts-compile.sh" },