From 0906767b1ad97678a422e18ac82972195e4c29bd Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 5 Nov 2023 16:59:17 +0100 Subject: [PATCH 01/75] client: PreimageManager and Preimage storage in MetaDB --- packages/client/src/config.ts | 7 ++++++ packages/client/src/execution/preimage.ts | 21 ++++++++++++++++ packages/client/src/execution/vmexecution.ts | 25 ++++++++++++++------ packages/client/src/types.ts | 1 + packages/client/src/util/metaDBManager.ts | 1 + 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 packages/client/src/execution/preimage.ts diff --git a/packages/client/src/config.ts b/packages/client/src/config.ts index 3c68ea60de..65e05acf20 100644 --- a/packages/client/src/config.ts +++ b/packages/client/src/config.ts @@ -326,6 +326,11 @@ export interface ConfigOptions { pruneEngineCache?: boolean snapAvailabilityDepth?: bigint snapTransitionSafeDepth?: bigint + + /** + * Save account keys preimages in the meta db (default: false) + */ + savePreimage?: boolean } export class Config { @@ -429,6 +434,7 @@ export class Config { // Defaulting to false as experimental as of now public readonly enableSnapSync: boolean public readonly useStringValueTrieDB: boolean + public readonly savePreimages: boolean public synchronized: boolean public lastsyncronized?: boolean @@ -473,6 +479,7 @@ export class Config { this.debugCode = options.debugCode ?? Config.DEBUGCODE_DEFAULT this.mine = options.mine ?? false this.isSingleNode = options.isSingleNode ?? false + this.savePreimages = options.savePreimage ?? false if (options.vmProfileBlocks !== undefined || options.vmProfileTxs !== undefined) { this.vmProfilerOpts = { diff --git a/packages/client/src/execution/preimage.ts b/packages/client/src/execution/preimage.ts new file mode 100644 index 0000000000..e211d0a207 --- /dev/null +++ b/packages/client/src/execution/preimage.ts @@ -0,0 +1,21 @@ +import { DBKey, MetaDBManager } from '../util/metaDBManager' + +export class PreimagesManager extends MetaDBManager { + /** + * Returns the preimage for a given hashed key + * @param key the hashed key + * @returns the preimage of the hashed key + */ + async getPreimage(key: Uint8Array): Promise { + return this.get(DBKey.Preimage, key) + } + + /** + * Saves a preimage to the db for a given hashed key. + * @param key The hashed key + * @param preimage The preimage to save + */ + async savePreimage(key: Uint8Array, preimage: Uint8Array) { + await this.put(DBKey.Preimage, key, preimage) + } +} diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index 99ac115e17..20f0886a8a 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -17,6 +17,7 @@ import { debugCodeReplayBlock } from '../util/debug' import { Execution } from './execution' import { LevelDB } from './level' +import { PreimagesManager } from './preimage' import { ReceiptsManager } from './receipt' import type { ExecutionOptions } from './execution' @@ -30,6 +31,7 @@ export class VMExecution extends Execution { public hardfork: string = '' public receiptsManager?: ReceiptsManager + public preimagesManager?: PreimagesManager private pendingReceipts?: Map private vmPromise?: Promise @@ -97,13 +99,22 @@ export class VMExecution extends Execution { ;(this.vm as any).blockchain = this.chain.blockchain } - if (this.metaDB && this.config.saveReceipts) { - this.receiptsManager = new ReceiptsManager({ - chain: this.chain, - config: this.config, - metaDB: this.metaDB, - }) - this.pendingReceipts = new Map() + if (this.metaDB) { + if (this.config.saveReceipts) { + this.receiptsManager = new ReceiptsManager({ + chain: this.chain, + config: this.config, + metaDB: this.metaDB, + }) + this.pendingReceipts = new Map() + } + if (this.config.savePreimages) { + this.preimagesManager = new PreimagesManager({ + chain: this.chain, + config: this.config, + metaDB: this.metaDB, + }) + } } } diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index 9778bae90d..5060c9e2c6 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -162,4 +162,5 @@ export interface ClientOpts { vmProfileTxs?: boolean loadBlocksFromRlp?: string pruneEngineCache?: boolean + savePreimages?: boolean } diff --git a/packages/client/src/util/metaDBManager.ts b/packages/client/src/util/metaDBManager.ts index ede8a4820c..eae48c6c52 100644 --- a/packages/client/src/util/metaDBManager.ts +++ b/packages/client/src/util/metaDBManager.ts @@ -20,6 +20,7 @@ export enum DBKey { SkeletonBlockHashToNumber, SkeletonStatus, SkeletonUnfinalizedBlockByHash, + Preimage, } export interface MetaDBManagerOptions { From 5e76ea07b345168379cbb0f025db9baadc282435 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 8 Nov 2023 11:59:02 +0100 Subject: [PATCH 02/75] common: add getAppliedKey method to StateManagerInterface --- packages/common/src/interfaces.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/src/interfaces.ts b/packages/common/src/interfaces.ts index 3be20bb916..9ac15217c2 100644 --- a/packages/common/src/interfaces.ts +++ b/packages/common/src/interfaces.ts @@ -83,6 +83,7 @@ export interface StateManagerInterface { getProof?(address: Address, storageSlots: Uint8Array[]): Promise hasStateRoot(root: Uint8Array): Promise // only used in client shallowCopy(downlevelCaches?: boolean): StateManagerInterface + getAppliedKey(address: Uint8Array): Uint8Array } export interface EVMStateManagerInterface extends StateManagerInterface { From c2938eb50f674d1392ccbb29617614c6b5beb12c Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 8 Nov 2023 12:00:04 +0100 Subject: [PATCH 03/75] evm: add preimage reporting --- packages/evm/src/journal.ts | 22 +++++++++++++++++++++- packages/evm/src/types.ts | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/evm/src/journal.ts b/packages/evm/src/journal.ts index dab81ff1b7..2baa8b28b7 100644 --- a/packages/evm/src/journal.ts +++ b/packages/evm/src/journal.ts @@ -2,7 +2,9 @@ import { Hardfork } from '@ethereumjs/common' import { Address, RIPEMD160_ADDRESS_STRING, + bytesToHex, bytesToUnprefixedHex, + hexToBytes, stripHexPrefix, toBytes, } from '@ethereumjs/util' @@ -14,6 +16,7 @@ import type { Debugger } from 'debug' const { debug: createDebugLogger } = debugDefault type AddressString = string +type HashString = string type SlotString = string type WarmSlots = Set @@ -44,6 +47,7 @@ export class Journal { private journalHeight: JournalHeight public accessList?: Map> + public preimages?: Map constructor(stateManager: EVMStateManagerInterface, common: Common) { // Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables @@ -69,6 +73,14 @@ export class Journal { this.accessList = new Map() } + /** + * Clears the internal `preimages` map, and marks this journal to start reporting + * the images (hashed addresses) of the accounts that have been accessed + */ + startReportingPreimages() { + this.preimages = new Map() + } + async putAccount(address: Address, account: Account | undefined) { this.touchAddress(address) return this.stateManager.putAccount(address, account) @@ -85,6 +97,13 @@ export class Journal { } private touchAccount(address: string) { + // If preimages are being reported, add the address to the preimages map + if (this.preimages !== undefined) { + const bytesAddress = hexToBytes(address) + const hashedKey = this.stateManager.getAppliedKey(bytesAddress) + this.preimages.set(bytesToHex(hashedKey), bytesAddress) + } + if (!this.touched.has(address)) { this.touched.add(address) const diffArr = this.journalDiff[this.journalDiff.length - 1][1] @@ -164,7 +183,7 @@ export class Journal { } /** - * Removes accounts form the state trie that have been touched, + * Removes accounts from the state trie that have been touched, * as defined in EIP-161 (https://eips.ethereum.org/EIPS/eip-161). * Also cleanups any other internal fields */ @@ -183,6 +202,7 @@ export class Journal { } this.cleanJournal() delete this.accessList + delete this.preimages } addAlwaysWarmAddress(addressStr: string, addToAccessList: boolean = false) { diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index e330fb4a89..e8e574ac57 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -147,9 +147,11 @@ export interface EVMInterface { putAccount(address: Address, account: Account): Promise deleteAccount(address: Address): Promise accessList?: Map> + preimages?: Map addAlwaysWarmAddress(address: string, addToAccessList?: boolean): void addAlwaysWarmSlot(address: string, slot: string, addToAccessList?: boolean): void startReportingAccessList(): void + startReportingPreimages(): void } stateManager: EVMStateManagerInterface precompiles: Map From 3e1984ab63eac2ffff18521f503a9b4fa686871e Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 8 Nov 2023 12:00:25 +0100 Subject: [PATCH 04/75] statemanager: add getAppliedKey methods to the statemanager implementations --- packages/statemanager/src/ethersStateManager.ts | 11 +++++++++++ packages/statemanager/src/stateManager.ts | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/statemanager/src/ethersStateManager.ts b/packages/statemanager/src/ethersStateManager.ts index 6d32469eb0..355d446ede 100644 --- a/packages/statemanager/src/ethersStateManager.ts +++ b/packages/statemanager/src/ethersStateManager.ts @@ -344,6 +344,17 @@ export class EthersStateManager implements EVMStateManagerInterface { return proof } + /** + * Returns the applied key for a given address + * Used for saving preimages + * @param address - The address to return the applied key + * @returns {Uint8Array} - The applied key (e.g. hashed address) + */ + getAppliedKey(address: Uint8Array): Uint8Array { + // TODO: Consider not hardcoding keccak256 as a hashing function? + return keccak256(address) + } + /** * Checkpoints the current state of the StateManager instance. * State changes that follow can then be committed by calling diff --git a/packages/statemanager/src/stateManager.ts b/packages/statemanager/src/stateManager.ts index 0b373ce743..fd0a863402 100644 --- a/packages/statemanager/src/stateManager.ts +++ b/packages/statemanager/src/stateManager.ts @@ -1058,4 +1058,14 @@ export class DefaultStateManager implements EVMStateManagerInterface { this._storageCache?.clear() this._codeCache?.clear() } + + /** + * Returns the applied key for a given address + * Used for saving preimages + * @param address - The address to return the applied key + * @returns {Uint8Array} - The applied key (e.g. hashed address) + */ + getAppliedKey(address: Uint8Array): Uint8Array { + return this._trie['appliedKey'](address) + } } From 76a3876f245b8a6951e653fedc88ef79dccf5c0f Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 8 Nov 2023 12:00:48 +0100 Subject: [PATCH 05/75] vm: improve some types --- packages/vm/src/runBlock.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 23f51975b1..ef8c0058f2 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -30,6 +30,7 @@ import type { PreByzantiumTxReceipt, RunBlockOpts, RunBlockResult, + RunTxResult, TxReceipt, } from './types.js' import type { VM } from './vm.js' @@ -137,7 +138,14 @@ export async function runBlock(this: VM, opts: RunBlockOpts): Promise Date: Wed, 8 Nov 2023 12:01:10 +0100 Subject: [PATCH 06/75] vm: implement preimage reporting --- packages/vm/src/runTx.ts | 8 ++++++++ packages/vm/src/types.ts | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 9496939e32..7f9f6fa233 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -121,6 +121,10 @@ export async function runTx(this: VM, opts: RunTxOpts): Promise { this.evm.journal.startReportingAccessList() } + if (opts.reportPreimages === true) { + this.evm.journal.startReportingPreimages() + } + await this.evm.journal.checkpoint() if (this.DEBUG) { debug('-'.repeat(100)) @@ -614,6 +618,10 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { results.accessList = accessList } + if (opts.reportPreimages === true && this.evm.journal.preimages !== undefined) { + results.preimages = this.evm.journal.preimages + } + await this.evm.journal.cleanup() state.originalStorageCache.clear() diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 0e7c5b9258..1b85a63fff 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -357,6 +357,12 @@ export interface RunTxOpts { */ reportAccessList?: boolean + /** + * If true, adds a hashedKey -> preimages mapping of all touched accounts + * to the `RunTxResult` returned. + */ + reportPreimages?: boolean + /** * To obtain an accurate tx receipt input the block gas used up until this tx. */ @@ -399,6 +405,11 @@ export interface RunTxResult extends EVMResult { */ accessList?: AccessList + /** + * Preimages mapping of the touched accounts from the tx (see `reportPreimages` option) + */ + preimages?: Map + /** * The value that accrues to the miner by this transaction */ From 9f0bf8e3145628326f9990e044395f8b3492f82a Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 8 Nov 2023 12:01:30 +0100 Subject: [PATCH 07/75] client: add preimage saving --- packages/client/src/execution/vmexecution.ts | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index 20f0886a8a..d5f6698711 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -8,7 +8,15 @@ import { ConsensusType, Hardfork } from '@ethereumjs/common' import { getGenesis } from '@ethereumjs/genesis' import { CacheType, DefaultStateManager } from '@ethereumjs/statemanager' import { Trie } from '@ethereumjs/trie' -import { BIGINT_0, BIGINT_1, Lock, ValueEncoding, bytesToHex, equalsBytes } from '@ethereumjs/util' +import { + BIGINT_0, + BIGINT_1, + Lock, + ValueEncoding, + bytesToHex, + equalsBytes, + hexToBytes, +} from '@ethereumjs/util' import { VM } from '@ethereumjs/vm' import { Event } from '../types' @@ -438,6 +446,21 @@ export class VMExecution extends Execution { void this.receiptsManager?.saveReceipts(block, result.receipts) + if (this.preimagesManager !== undefined) { + for (const txResult of result.results) { + if (txResult.preimages === undefined) { + continue + } + + for (const preimage of txResult.preimages) { + await this.preimagesManager.savePreimage( + hexToBytes(preimage[0]), + preimage[1] + ) + } + } + } + txCounter += block.transactions.length // set as new head block headBlock = block From fe8022a6642599452d522ab4860f082d444cbd61 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 10:28:04 +0100 Subject: [PATCH 08/75] evm: update to unprefixedHexToBytes --- packages/evm/src/journal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/evm/src/journal.ts b/packages/evm/src/journal.ts index 2baa8b28b7..5ba34b296a 100644 --- a/packages/evm/src/journal.ts +++ b/packages/evm/src/journal.ts @@ -4,9 +4,9 @@ import { RIPEMD160_ADDRESS_STRING, bytesToHex, bytesToUnprefixedHex, - hexToBytes, stripHexPrefix, toBytes, + unprefixedHexToBytes, } from '@ethereumjs/util' import debugDefault from 'debug' @@ -99,7 +99,7 @@ export class Journal { private touchAccount(address: string) { // If preimages are being reported, add the address to the preimages map if (this.preimages !== undefined) { - const bytesAddress = hexToBytes(address) + const bytesAddress = unprefixedHexToBytes(address) const hashedKey = this.stateManager.getAppliedKey(bytesAddress) this.preimages.set(bytesToHex(hashedKey), bytesAddress) } From 50d85b8734e40904e6d328581d4317119326c727 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 10:41:39 +0100 Subject: [PATCH 09/75] vm: add reportPreimages test to runTx tests --- packages/vm/test/api/runTx.spec.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 6e9a40f201..716f1aa1b8 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -13,6 +13,8 @@ import { Address, KECCAK256_NULL, MAX_INTEGER, + bytesToHex, + equalsBytes, hexToBytes, initKZG, zeros, @@ -317,6 +319,24 @@ describe('runTx() -> API parameter usage/data errors', () => { assert.deepEqual(res.accessList, []) }) + it('simple run (reportPreimages option)', async () => { + const vm = await VM.create({ common }) + + const tx = getTransaction(vm.common, 0, true) + + const caller = tx.getSenderAddress() + const acc = createAccount() + await vm.stateManager.putAccount(caller, acc) + + const res = await vm.runTx({ tx, reportPreimages: true }) + + const hashedCallerKey = vm.stateManager.getAppliedKey(caller.bytes) + + const retrievedPreimage = res.preimages?.get(bytesToHex(hashedCallerKey)) + + assert.ok(retrievedPreimage !== undefined && equalsBytes(retrievedPreimage, caller.bytes)) + }) + it('run without signature', async () => { for (const txType of TRANSACTION_TYPES) { const vm = await VM.create({ common }) From 6c32301bea32dd62db853249ce3ad045f4584ac3 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 11:07:24 +0100 Subject: [PATCH 10/75] vm: pass down reportPreimages arg from block to tx --- packages/vm/src/runBlock.ts | 3 ++- packages/vm/src/types.ts | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index ef8c0058f2..fca2351fc4 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -427,7 +427,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { } // Run the tx through the VM - const { skipBalance, skipNonce, skipHardForkValidation } = opts + const { skipBalance, skipNonce, skipHardForkValidation, reportPreimages } = opts const txRes = await this.runTx({ tx, @@ -436,6 +436,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { skipNonce, skipHardForkValidation, blockGasUsed: gasUsed, + reportPreimages, }) txResults.push(txRes) if (this.DEBUG) { diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 1b85a63fff..b761683ed0 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -274,6 +274,12 @@ export interface RunBlockOpts { * Default: `false` (HF is set to whatever default HF is set by the {@link Common} instance) */ setHardfork?: boolean | BigIntLike + + /** + * If true, adds a hashedKey -> preimages mapping of all touched accounts + * to the `RunTxResult` returned. + */ + reportPreimages?: boolean } /** @@ -328,6 +334,7 @@ export interface RunTxOpts { * If true, skips the nonce check */ skipNonce?: boolean + /** * Skip balance checks if true. Adds transaction cost to balance to ensure execution doesn't fail. */ From b338b9903b42659d1c60c8cb396fe57a0c34548e Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 11:07:50 +0100 Subject: [PATCH 11/75] client: pass down reportPreimages from client to vm through runBlock --- packages/client/src/execution/vmexecution.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index d5f6698711..b9dce8d821 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -116,7 +116,7 @@ export class VMExecution extends Execution { }) this.pendingReceipts = new Map() } - if (this.config.savePreimages) { + if (this.config.savePreimages === true) { this.preimagesManager = new PreimagesManager({ chain: this.chain, config: this.config, @@ -431,6 +431,7 @@ export class VMExecution extends Execution { clearCache, skipBlockValidation, skipHeaderValidation: true, + reportPreimages: this.config.savePreimages, }) const afterTS = Date.now() const diffSec = Math.round((afterTS - beforeTS) / 1000) @@ -446,17 +447,14 @@ export class VMExecution extends Execution { void this.receiptsManager?.saveReceipts(block, result.receipts) - if (this.preimagesManager !== undefined) { + if (this.config.savePreimages === true && this.preimagesManager !== undefined) { for (const txResult of result.results) { if (txResult.preimages === undefined) { continue } - for (const preimage of txResult.preimages) { - await this.preimagesManager.savePreimage( - hexToBytes(preimage[0]), - preimage[1] - ) + for (const [key, preimage] of txResult.preimages) { + await this.preimagesManager.savePreimage(hexToBytes(key), preimage) } } } From c9ed40a357038fbdf6265e0840f4c5a779712ce9 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 13:35:42 +0100 Subject: [PATCH 12/75] client: unify config options naming --- packages/client/src/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/config.ts b/packages/client/src/config.ts index 65e05acf20..794cd0ab00 100644 --- a/packages/client/src/config.ts +++ b/packages/client/src/config.ts @@ -330,7 +330,7 @@ export interface ConfigOptions { /** * Save account keys preimages in the meta db (default: false) */ - savePreimage?: boolean + savePreimages?: boolean } export class Config { @@ -479,7 +479,7 @@ export class Config { this.debugCode = options.debugCode ?? Config.DEBUGCODE_DEFAULT this.mine = options.mine ?? false this.isSingleNode = options.isSingleNode ?? false - this.savePreimages = options.savePreimage ?? false + this.savePreimages = options.savePreimages ?? false if (options.vmProfileBlocks !== undefined || options.vmProfileTxs !== undefined) { this.vmProfilerOpts = { From e0a4bafc42402072356950b7562c2151458c3410 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 9 Nov 2023 13:45:15 +0100 Subject: [PATCH 13/75] client: preimageManager test --- packages/client/test/miner/miner.spec.ts | 69 +++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/client/test/miner/miner.spec.ts b/packages/client/test/miner/miner.spec.ts index 8d0d543f0e..fd06a83969 100644 --- a/packages/client/test/miner/miner.spec.ts +++ b/packages/client/test/miner/miner.spec.ts @@ -1,10 +1,10 @@ import { Block, BlockHeader } from '@ethereumjs/block' import { Common, Chain as CommonChain, Hardfork } from '@ethereumjs/common' +import { keccak256 } from '@ethereumjs/devp2p' import { DefaultStateManager } from '@ethereumjs/statemanager' import { FeeMarketEIP1559Transaction, LegacyTransaction } from '@ethereumjs/tx' import { Address, equalsBytes, hexToBytes } from '@ethereumjs/util' import { AbstractLevel } from 'abstract-level' -import { keccak256 } from 'ethereum-cryptography/keccak' import { assert, describe, it, vi } from 'vitest' import { Chain } from '../../src/blockchain' @@ -383,6 +383,73 @@ describe('[Miner]', async () => { await wait(500) }) + it('assembleBlocks() -> with savePreimages', async () => { + const chain = new FakeChain() as any + const config = new Config({ + accountCache: 10000, + storageCache: 1000, + accounts, + mine: true, + common: customCommon, + savePreimages: true, + }) + const service = new FullEthereumService({ + config, + chain, + metaDB: new AbstractLevel({ + encodings: { utf8: true, buffer: true }, + }), + }) + const miner = new Miner({ config, service, skipHardForkValidation: true }) + const { txPool } = service + const { vm, preimagesManager } = service.execution + txPool.start() + miner.start() + + assert.ok(preimagesManager !== undefined, 'preimagesManager should be initialized') + + await setBalance(vm, A.address, BigInt('400000000000001')) + await setBalance(vm, B.address, BigInt('400000000000001')) + + const txs = [txA01, txA02, txA03, txB01] + + // add txs + for (const tx of txs) { + await txPool.add(tx) + } + + // disable consensus to skip PoA block signer validation + ;(vm.blockchain as any)._validateConsensus = false + + chain.putBlocks = async (blocks: Block[]) => { + const msg = 'txs in block should be properly ordered by gasPrice and nonce' + const expectedOrder = [txB01, txA01, txA02, txA03] + for (const [index, tx] of expectedOrder.entries()) { + const txHash = blocks[0].transactions[index]?.hash() + assert.ok(txHash !== undefined && equalsBytes(txHash, tx.hash()), msg) + } + miner.stop() + txPool.stop() + } + + await (miner as any).queueNextAssembly(0) + + // The two accounts (`sender` and `to` accounts) touched by the transactions should be in the preimagesManager + const touchedAddresses = txs.flatMap((tx) => [tx.getSenderAddress().bytes, tx.to!.bytes]) + const touchedAddressesHashedKeys = touchedAddresses.map((address) => keccak256(address)) + + for (const [index, hashedKey] of touchedAddressesHashedKeys.entries()) { + const preimage = await preimagesManager!.getPreimage(hashedKey) + assert.ok(preimage !== null, 'preimage should be saved') + assert.ok( + equalsBytes(preimage!, touchedAddresses[index]), + 'preimage should match touched address' + ) + } + + await wait(500) + }) + it('assembleBlocks() -> should not include tx under the baseFee', async () => { const customChainParams = { hardforks: [{ name: 'london', block: 0 }] } const common = Common.custom(customChainParams, { From 8787ac53731e814d8c58d8fa1130ecfe882b3768 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 12 Nov 2023 18:08:49 +0300 Subject: [PATCH 14/75] client: test preimage, wip --- .../client/test/execution/vmexecution.spec.ts | 189 +++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/packages/client/test/execution/vmexecution.spec.ts b/packages/client/test/execution/vmexecution.spec.ts index c3b774db88..691c8faf2b 100644 --- a/packages/client/test/execution/vmexecution.spec.ts +++ b/packages/client/test/execution/vmexecution.spec.ts @@ -1,8 +1,11 @@ import { Block } from '@ethereumjs/block' import { Blockchain } from '@ethereumjs/blockchain' import { Chain as ChainEnum, Common, Hardfork } from '@ethereumjs/common' -import { bytesToHex } from '@ethereumjs/util' +import { keccak256 } from '@ethereumjs/devp2p' +import { LegacyTransaction } from '@ethereumjs/tx' +import { bytesToHex, equalsBytes, hexToBytes } from '@ethereumjs/util' import { VM } from '@ethereumjs/vm' +import { MemoryLevel } from 'memory-level' import { assert, describe, it } from 'vitest' import { Chain } from '../../src/blockchain' @@ -14,6 +17,138 @@ import blocksDataMainnet from '../testdata/blocks/mainnet.json' import testnet from '../testdata/common/testnet.json' import shanghaiJSON from '../testdata/geth-genesis/withdrawals.json' +import type { Address } from '@ethereumjs/util' + +const testGenesisBlock = { + header: { + bloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + coinbase: '0x8888f1f195afa192cfee860698584c030f4c9db1', + difficulty: '0x020000', + extraData: '0x42', + gasLimit: '0x023e38', + gasUsed: '0x00', + hash: '0xce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae', + mixHash: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + nonce: '0x0102030405060708', + number: '0x00', + parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + stateRoot: '0xaf81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0', + timestamp: '0x54c98c81', + transactionsTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + uncleHash: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + }, +} +const testBlock = { + header: { + bloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + coinbase: '0x8888f1f195afa192cfee860698584c030f4c9db1', + difficulty: '0x020000', + extraData: '0x', + gasLimit: '0x023ec6', + gasUsed: '0x021536', + hash: '0xf53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3', + mixHash: '0x29f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3', + nonce: '0x8957e6d004a31802', + number: '0x1', + parentHash: '0xce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae', + receiptTrie: '0x5c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7', + stateRoot: '0xa65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4', + timestamp: '0x56851097', + transactionsTrie: '0x70616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2', + uncleHash: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + }, + // rlp: '0xf904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0', + transactions: [ + { + data: '0x', + gasLimit: '0x55f0', + gasPrice: '0x0a', + nonce: '0x', + r: '0x575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecd', + s: '0x6baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188', + to: '0xaaaf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1c', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x01', + r: '0x4fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5b', + s: '0x17bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192e', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1b', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x02', + r: '0x04377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458ada', + s: '0x53a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1c', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x03', + r: '0x4fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615', + s: '0x651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1c', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x04', + r: '0x78e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567d', + s: '0x13254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198dd', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1b', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x05', + r: '0xa7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54', + s: '0x534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1b', + value: '0x0a', + }, + { + data: '0x', + gasLimit: '0x5208', + gasPrice: '0x0a', + nonce: '0x06', + r: '0x34bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59', + s: '0x78807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616', + to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', + v: '0x1b', + value: '0x0a', + }, + ], + uncleHeaders: [], +} + +const setBalance = async (vm: VM, address: Address, balance: bigint) => { + await vm.stateManager.checkpoint() + await vm.stateManager.modifyAccountFields(address, { balance }) + await vm.stateManager.commit() +} + describe('[VMExecution]', async () => { it('Initialization', async () => { const vm = await VM.create() @@ -78,6 +213,58 @@ describe('[VMExecution]', async () => { ) }) + it.only( + 'Test block execution with savePreimages enabled', + async () => { + const testSetupWithPreimages = async (blockchain: Blockchain) => { + const config = new Config({ + accountCache: 10000, + storageCache: 1000, + savePreimages: true, + }) + const chain = await Chain.create({ config, blockchain }) + const exec = new VMExecution({ config, chain, metaDB: new MemoryLevel() }) + await chain.open() + await exec.open() + return exec + } + + const blockchain = await Blockchain.create({ + validateBlocks: false, + validateConsensus: false, + }) + + const block = Block.fromBlockData(testBlock, { common: blockchain.common }) + await blockchain.putBlock(block) + + const exec = await testSetupWithPreimages(blockchain) + + await exec.run() + + const touchedAccounts = block.transactions.flatMap((transcation) => [ + transcation.to!.bytes, + transcation.getSenderAddress().bytes, + ]) + const touchedAccountsHashedKeys = touchedAccounts.map((address) => keccak256(address)) + + // The preimagesManager should be instantiated + assert.ok(exec.preimagesManager !== undefined, 'preimagesManager should be instantiated') + + console.log('before for of loop') + for (const [index, touchedAccount] of touchedAccounts.entries()) { + console.log('inside loop') + console.log('index: ', index) + console.log('touchedAccount', bytesToHex(touchedAccount)) + const preimage = await exec.preimagesManager!.getPreimage(touchedAccountsHashedKeys[index]) + assert.ok( + preimage !== null && equalsBytes(preimage, touchedAccount), + 'preimage should be recovered' + ) + } + }, + { timeout: 50000 } + ) + it('Should fail opening if vmPromise already assigned', async () => { const blockchain = await Blockchain.create({ validateBlocks: true, From 157debee9a34ad6de5c3077cf5dc22ab2ba0108f Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Wed, 6 Dec 2023 11:42:31 -0500 Subject: [PATCH 15/75] common: add todo to gasPrices from 6800 --- packages/common/src/eips.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/src/eips.ts b/packages/common/src/eips.ts index 97c0262452..4fb94f0afe 100644 --- a/packages/common/src/eips.ts +++ b/packages/common/src/eips.ts @@ -478,6 +478,7 @@ export const EIPs: EIPsDict = { minimumHardfork: Hardfork.London, requiredEIPs: [], gasConfig: {}, + /* TODO: Replace with correct implementation */ gasPrices: { tx: { v: 34300, From 5b2cf25cd574a363059da943f15b1eca1ebf2336 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 10 Dec 2023 10:45:47 -0500 Subject: [PATCH 16/75] statemanager: fix type issues --- packages/statemanager/src/statelessVerkleStateManager.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 10e79478f2..a0b029f487 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -642,4 +642,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { generateCanonicalGenesis(_initState: any): Promise { return Promise.resolve() } + + getAppliedKey(_: Uint8Array): Uint8Array { + throw Error('not implemented') + } } From 3c639022a08cf9377581af0948769fec9a8d0b80 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 13 Dec 2023 17:54:28 +0530 Subject: [PATCH 17/75] dev accessWitness class on the lines of geth impl --- packages/statemanager/src/accessWitness.ts | 241 ++++++++++++++++++ .../src/statelessVerkleStateManager.ts | 25 +- 2 files changed, 252 insertions(+), 14 deletions(-) create mode 100644 packages/statemanager/src/accessWitness.ts diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts new file mode 100644 index 0000000000..af8600538d --- /dev/null +++ b/packages/statemanager/src/accessWitness.ts @@ -0,0 +1,241 @@ +import { bytesToHex, toBytes } from '@ethereumjs/util' +import { getKey, getStem } from '@ethereumjs/verkle' + +import type { Address, PrefixedHexString } from '@ethereumjs/util' + +/** + * Tree key constants. + */ +export const VERSION_LEAF_KEY = toBytes(0) +export const BALANCE_LEAF_KEY = toBytes(1) +export const NONCE_LEAF_KEY = toBytes(2) +export const CODE_KECCAK_LEAF_KEY = toBytes(3) +export const CODE_SIZE_LEAF_KEY = toBytes(4) + +export const HEADER_STORAGE_OFFSET = 64 +export const CODE_OFFSET = 128 +export const VERKLE_NODE_WIDTH = 256 +export const MAIN_STORAGE_OFFSET = 256 ** 31 + +const WitnessBranchReadCost = 1900 +const WitnessChunkReadCost = 200 +const WitnessBranchWriteCost = 3000 +const WitnessChunkWriteCost = 500 +const WitnessChunkFillCost = 6200 + +// read is a default access event if stem or chunk is present +type StemAccessEvent = { write?: boolean } +// chunk fill access event is not being charged right now in kaustinen2 but will be rectified +// in upcoming iterations +type ChunkAccessEvent = StemAccessEvent & { fill?: boolean } + +type AccessEventFlags = { + stemRead: boolean + stemWrite: boolean + chunkRead: boolean + chunkWrite: boolean + chunkFill: boolean +} + +export class AccessWitness { + stems: Map + + chunks: Map + + constructor( + opts: { + stems?: Map + chunks?: Map + } = {} + ) { + this.stems = opts.stems ?? new Map() + this.chunks = opts.chunks ?? new Map() + } + + touchAndChargeProofOfAbsence(address: Address): number { + let gas = 0 + + gas += this.touchAddressOnReadAndComputeGas(address, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(address, 0, BALANCE_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(address, 0, CODE_SIZE_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(address, 0, CODE_KECCAK_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(address, 0, NONCE_LEAF_KEY) + + return gas + } + + touchAndChargeMessageCall(address: Address): number { + let gas = 0 + + gas += this.touchAddressOnReadAndComputeGas(address, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(address, 0, CODE_SIZE_LEAF_KEY) + + return gas + } + + touchAndChargeValueTransfer(caller: Address, target: Address): number { + let gas = 0 + + gas += this.touchAddressOnWriteAndComputeGas(caller, 0, BALANCE_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(target, 0, BALANCE_LEAF_KEY) + + return gas + } + + touchAndChargeContractCreateInit( + address: Address, + { createSendsValue }: { createSendsValue?: boolean } = {} + ): number { + let gas = 0 + + gas += this.touchAddressOnWriteAndComputeGas(address, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, NONCE_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, CODE_KECCAK_LEAF_KEY) + if (createSendsValue === true) { + gas += this.touchAddressOnWriteAndComputeGas(address, 0, BALANCE_LEAF_KEY) + } + + return gas + } + + touchAndChargeContractCreateCompleted(address: Address): number { + let gas = 0 + + gas += this.touchAddressOnWriteAndComputeGas(address, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, BALANCE_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, CODE_SIZE_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, CODE_KECCAK_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(address, 0, NONCE_LEAF_KEY) + + return gas + } + + touchTxOriginAndComputeGas(origin: Address): number { + let gas = 0 + + gas += this.touchAddressOnReadAndComputeGas(origin, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(origin, 0, CODE_SIZE_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(origin, 0, CODE_KECCAK_LEAF_KEY) + + gas += this.touchAddressOnWriteAndComputeGas(origin, 0, NONCE_LEAF_KEY) + gas += this.touchAddressOnWriteAndComputeGas(origin, 0, BALANCE_LEAF_KEY) + + return gas + } + + touchTxExistingAndComputeGas(target: Address, { sendsValue }: { sendsValue?: boolean } = {}) { + let gas = 0 + + gas += this.touchAddressOnReadAndComputeGas(target, 0, VERSION_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(target, 0, CODE_SIZE_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(target, 0, CODE_KECCAK_LEAF_KEY) + gas += this.touchAddressOnReadAndComputeGas(target, 0, NONCE_LEAF_KEY) + + if (sendsValue === true) { + gas += this.touchAddressOnWriteAndComputeGas(target, 0, BALANCE_LEAF_KEY) + } else { + gas += this.touchAddressOnReadAndComputeGas(target, 0, BALANCE_LEAF_KEY) + } + + return gas + } + + touchAddressOnWriteAndComputeGas( + address: Address, + treeIndex: number, + subIndex: number | Uint8Array + ): number { + return this.touchAddressAndChargeGas(address, treeIndex, subIndex, { isWrite: true }) + } + + touchAddressOnReadAndComputeGas( + address: Address, + treeIndex: number, + subIndex: number | Uint8Array + ): number { + return this.touchAddressAndChargeGas(address, treeIndex, subIndex, { isWrite: false }) + } + + touchAddressAndChargeGas( + address: Address, + treeIndex: number, + subIndex: number | Uint8Array, + { isWrite }: { isWrite?: boolean } + ): number { + let gas = 0 + const { stemRead, stemWrite, chunkRead, chunkWrite, chunkFill } = this.touchAddress( + address, + treeIndex, + subIndex, + { isWrite } + ) + + if (stemRead) { + gas += WitnessBranchReadCost + } + if (stemWrite) { + gas += WitnessBranchWriteCost + } + + if (chunkRead) { + gas += WitnessChunkReadCost + } + if (chunkWrite) { + gas += WitnessChunkWriteCost + } + if (chunkFill) { + gas += WitnessChunkFillCost + } + + return gas + } + + touchAddress( + address: Address, + treeIndex: number, + subIndex: number | Uint8Array, + { isWrite }: { isWrite?: boolean } = {} + ): AccessEventFlags { + let stemRead = false, + stemWrite = false, + chunkRead = false, + chunkWrite = false + // currently there are no gas charges for setting the chunk for the first time + // i.e. no fill cost is charged right now + const chunkFill = false + + const accessedStemKey = getStem(address, treeIndex) + const accessedStemHex = bytesToHex(accessedStemKey) + let accessedStem = this.stems.get(accessedStemHex) + if (accessedStem === undefined) { + stemRead = true + accessedStem = {} + this.stems.set(accessedStemHex, accessedStem) + } + + const accessedChunkKey = getKey(accessedStemKey, toBytes(subIndex)) + const accessedChunkKeyHex = bytesToHex(accessedChunkKey) + let accessedChunk = this.chunks.get(accessedChunkKeyHex) + if (accessedChunk === undefined) { + chunkRead = true + accessedChunk = {} + this.chunks.set(accessedChunkKeyHex, accessedChunk) + } + + if (isWrite === true) { + if (accessedStem.write !== true) { + stemWrite = true + // this would also directly modify in the map + accessedStem.write = true + } + + if (accessedChunk.write !== true) { + chunkWrite = true + // this would also directly modify in the map + accessedChunk.write = true + } + } + + return { stemRead, stemWrite, chunkRead, chunkWrite, chunkFill } + } +} diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 10e79478f2..742648ad99 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -17,6 +17,17 @@ import debugDefault from 'debug' import { keccak256 } from 'ethereum-cryptography/keccak.js' import { concatBytes, equalsBytes } from 'ethereum-cryptography/utils' +import { + BALANCE_LEAF_KEY, + CODE_KECCAK_LEAF_KEY, + CODE_OFFSET, + CODE_SIZE_LEAF_KEY, + HEADER_STORAGE_OFFSET, + MAIN_STORAGE_OFFSET, + NONCE_LEAF_KEY, + VERKLE_NODE_WIDTH, + VERSION_LEAF_KEY, +} from './accessWitness.js' import { AccountCache, CacheType, StorageCache } from './cache/index.js' import { OriginalStorageCache } from './cache/originalStorageCache.js' @@ -99,20 +110,6 @@ export interface StatelessVerkleStateManagerOpts { storageCacheOpts?: CacheOptions } -/** - * Tree key constants. - */ -const VERSION_LEAF_KEY = toBytes(0) -const BALANCE_LEAF_KEY = toBytes(1) -const NONCE_LEAF_KEY = toBytes(2) -const CODE_KECCAK_LEAF_KEY = toBytes(3) -const CODE_SIZE_LEAF_KEY = toBytes(4) - -const HEADER_STORAGE_OFFSET = 64 -const CODE_OFFSET = 128 -const VERKLE_NODE_WIDTH = 256 -const MAIN_STORAGE_OFFSET = 256 ** 31 - const PUSH_OFFSET = 95 // eslint-disable-next-line @typescript-eslint/no-unused-vars const PUSH1 = PUSH_OFFSET + 1 From 7954bb61e590c53b4884e9b7c0ccd82e1e3929fa Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 15 Dec 2023 16:06:09 +0530 Subject: [PATCH 18/75] integrate accesswitness in evm/vm/runtx flow --- packages/common/src/eips.ts | 10 ---------- packages/evm/src/evm.ts | 2 ++ packages/evm/src/interpreter.ts | 2 ++ packages/evm/src/message.ts | 4 ++++ packages/evm/src/types.ts | 3 +++ packages/statemanager/src/accessWitness.ts | 10 ++++++++++ packages/statemanager/src/index.ts | 1 + .../src/statelessVerkleStateManager.ts | 10 +++++++++- packages/vm/src/runTx.ts | 20 +++++++++++++++++++ 9 files changed, 51 insertions(+), 11 deletions(-) diff --git a/packages/common/src/eips.ts b/packages/common/src/eips.ts index 4fb94f0afe..cc16f42686 100644 --- a/packages/common/src/eips.ts +++ b/packages/common/src/eips.ts @@ -477,16 +477,6 @@ export const EIPs: EIPsDict = { status: Status.Draft, minimumHardfork: Hardfork.London, requiredEIPs: [], - gasConfig: {}, - /* TODO: Replace with correct implementation */ - gasPrices: { - tx: { - v: 34300, - d: 'Per transaction. NOTE: Not payable on data of calls between transactions', - }, - }, - vm: {}, - pow: {}, }, 7516: { comment: 'BLOBBASEFEE opcode', diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 11d64d5a06..7e57c8f21b 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -575,6 +575,7 @@ export class EVM implements EVMInterface { gasRefund: message.gasRefund, containerCode: message.containerCode, blobVersionedHashes: message.blobVersionedHashes ?? [], + accessWitness: message.accessWitness, createdAddresses: message.createdAddresses, } @@ -675,6 +676,7 @@ export class EVM implements EVMInterface { createdAddresses: opts.createdAddresses ?? new Set(), delegatecall: opts.delegatecall, blobVersionedHashes: opts.blobVersionedHashes, + accessWitness: opts.accessWitness, }) } diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index fb4ce1b428..8869804de6 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -24,6 +24,7 @@ import type { EVMPerformanceLogger, Timer } from './logger.js' import type { AsyncOpHandler, Opcode, OpcodeMapEntry } from './opcodes/index.js' import type { Block, Blockchain, EVMProfilerOpts, EVMResult, Log } from './types.js' import type { Common, EVMStateManagerInterface } from '@ethereumjs/common' +import type { AccessWitness } from '@ethereumjs/statemanager' import type { Address } from '@ethereumjs/util' const { debug: createDebugLogger } = debugDefault @@ -67,6 +68,7 @@ export interface Env { containerCode?: Uint8Array /** Full container code for EOF1 contracts */ blobVersionedHashes: Uint8Array[] /** Versioned hashes for blob transactions */ createdAddresses?: Set + accessWitness?: AccessWitness } export interface RunState { diff --git a/packages/evm/src/message.ts b/packages/evm/src/message.ts index 68931a9c0b..f1eeee0a92 100644 --- a/packages/evm/src/message.ts +++ b/packages/evm/src/message.ts @@ -1,6 +1,7 @@ import { Address, BIGINT_0 } from '@ethereumjs/util' import type { PrecompileFunc } from './precompiles/index.js' +import type { AccessWitness } from '@ethereumjs/statemanager' const defaults = { value: BIGINT_0, @@ -37,6 +38,7 @@ interface MessageOpts { authcallOrigin?: Address gasRefund?: bigint blobVersionedHashes?: Uint8Array[] + accessWitness?: AccessWitness } export class Message { @@ -71,6 +73,7 @@ export class Message { * List of versioned hashes if message is a blob transaction in the outer VM */ blobVersionedHashes?: Uint8Array[] + accessWitness?: AccessWitness constructor(opts: MessageOpts) { this.to = opts.to @@ -90,6 +93,7 @@ export class Message { this.authcallOrigin = opts.authcallOrigin this.gasRefund = opts.gasRefund ?? defaults.gasRefund this.blobVersionedHashes = opts.blobVersionedHashes + this.accessWitness = opts.accessWitness if (this.value < 0) { throw new Error(`value field cannot be negative, received ${this.value}`) } diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index e330fb4a89..6254ef94a2 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -8,6 +8,7 @@ import type { OpHandler } from './opcodes/index.js' import type { CustomPrecompile } from './precompiles/index.js' import type { PrecompileFunc } from './precompiles/types.js' import type { Common, EVMStateManagerInterface } from '@ethereumjs/common' +import type { AccessWitness } from '@ethereumjs/statemanager' import type { Account, Address, AsyncEventEmitter } from '@ethereumjs/util' export type DeleteOpcode = { @@ -122,6 +123,8 @@ export interface EVMRunCallOpts extends EVMRunOpts { * Optionally pass in an already-built message. */ message?: Message + + accessWitness?: AccessWitness } interface NewContractEvent { diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index af8600538d..fc946f531a 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -238,4 +238,14 @@ export class AccessWitness { return { stemRead, stemWrite, chunkRead, chunkWrite, chunkFill } } + + /**Create a shallow copy, could clone some caches in future for optimizations */ + shallowCopy(): AccessWitness { + return new AccessWitness() + } + + merge(_accessWitness: AccessWitness): void { + // TODO - add merging accessWitnesses into the current one + return + } } diff --git a/packages/statemanager/src/index.ts b/packages/statemanager/src/index.ts index fad219d75a..099da76970 100644 --- a/packages/statemanager/src/index.ts +++ b/packages/statemanager/src/index.ts @@ -1,3 +1,4 @@ +export * from './accessWitness.js' export * from './cache/index.js' export * from './rpcStateManager.js' export * from './statelessVerkleStateManager.js' diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 742648ad99..ee0b689728 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -18,6 +18,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js' import { concatBytes, equalsBytes } from 'ethereum-cryptography/utils' import { + AccessWitness, BALANCE_LEAF_KEY, CODE_KECCAK_LEAF_KEY, CODE_OFFSET, @@ -108,6 +109,7 @@ export interface StatelessVerkleStateManagerOpts { */ common?: Common storageCacheOpts?: CacheOptions + accesses?: AccessWitness } const PUSH_OFFSET = 95 @@ -160,6 +162,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // Checkpointing private _checkpoints: VerkleState[] = [] + accessWitness?: AccessWitness /** * Instantiate the StateManager interface. @@ -218,12 +221,17 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { throw Error('not implemented') } - public initVerkleExecutionWitness(executionWitness?: VerkleExecutionWitness | null) { + public initVerkleExecutionWitness( + executionWitness?: VerkleExecutionWitness | null, + accessWitness?: AccessWitness + ) { if (executionWitness === null || executionWitness === undefined) { throw Error(`Invalid executionWitness=${executionWitness} for initVerkleExecutionWitness`) } this._executionWitness = executionWitness + this.accessWitness = accessWitness ?? new AccessWitness() + this._proof = executionWitness.verkleProof as unknown as Uint8Array // Populate the pre-state and post-state from the executionWitness diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 9496939e32..0a02869e7e 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,5 +1,6 @@ import { Block } from '@ethereumjs/block' import { ConsensusType, Hardfork } from '@ethereumjs/common' +import { AccessWitness, StatelessVerkleStateManager } from '@ethereumjs/statemanager' import { BlobEIP4844Transaction, Capability, isBlobEIP4844Tx } from '@ethereumjs/tx' import { Account, @@ -203,6 +204,20 @@ export async function runTx(this: VM, opts: RunTxOpts): Promise { async function _runTx(this: VM, opts: RunTxOpts): Promise { const state = this.stateManager + let stateAccesses + if (this.common.isActivatedEIP(6800)) { + if (!(this.stateManager instanceof StatelessVerkleStateManager)) { + throw Error(`StatelessVerkleStateManager needed for execution of verkle blocks`) + } + stateAccesses = (this.stateManager as StatelessVerkleStateManager).accessWitness + } else { + // assign an empty witness to prevent unnecessary code spagetti of null/undefined checks while usage + // but its totally possible that merkle can also accumulate witnesses if such feature was to be made + // available there + stateAccesses = new AccessWitness() + } + const txAccesses = stateAccesses?.shallowCopy() + const { tx, block } = opts if (!block) { @@ -468,8 +483,13 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { value, data, blobVersionedHashes, + accessWitness: txAccesses, })) as RunTxResult + if (this.common.isActivatedEIP(6800)) { + stateAccesses?.merge(txAccesses!) + } + if (enableProfiler) { // eslint-disable-next-line no-console console.time(logsGasBalanceLabel) From a6036359752cd148609a09f662beb3a099d42a37 Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 15 Dec 2023 22:14:26 +0530 Subject: [PATCH 19/75] plugin the gas schedule for tx origin and destination accesses --- packages/evm/src/evm.ts | 57 +++++++++++++++++++++- packages/statemanager/src/accessWitness.ts | 51 +++++++++---------- packages/vm/src/runTx.ts | 27 +++++++++- 3 files changed, 106 insertions(+), 29 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 7e57c8f21b..8e5fd41b95 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -222,6 +222,18 @@ export class EVM implements EVMInterface { } protected async _executeCall(message: MessageWithTo): Promise { + let accessGasUsed = BIGINT_0 + if (this.common.isActivatedEIP(6800)) { + const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas( + message.authcallOrigin ?? message.caller + ) + accessGasUsed += originAccessGas + message.gasLimit -= originAccessGas + if (this.DEBUG) { + debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + } + } + let account = await this.stateManager.getAccount(message.authcallOrigin ?? message.caller) if (!account) { account = new Account() @@ -235,6 +247,19 @@ export class EVM implements EVMInterface { errorMessage = e } } + + if (this.common.isActivatedEIP(6800)) { + const sendsValue = message.value !== BIGINT_0 + const destAccessGas = message.accessWitness!.touchTxExistingAndComputeGas(message.to, { + sendsValue, + }) + accessGasUsed += destAccessGas + message.gasLimit -= destAccessGas + if (this.DEBUG) { + debugGas(`Destination access used (${destAccessGas} gas (-> ${message.gasLimit}))`) + } + } + // Load `to` account let toAccount = await this.stateManager.getAccount(message.to) if (!toAccount) { @@ -268,7 +293,7 @@ export class EVM implements EVMInterface { return { execResult: { gasRefund: message.gasRefund, - executionGasUsed: BIGINT_0, + executionGasUsed: accessGasUsed, exceptionError: errorMessage, // Only defined if addToBalance failed returnValue: new Uint8Array(0), }, @@ -306,12 +331,24 @@ export class EVM implements EVMInterface { this.postMessageCleanup() } + result.executionGasUsed += accessGasUsed + return { execResult: result, } } protected async _executeCreate(message: Message): Promise { + let accessGasUsed = BIGINT_0 + if (this.common.isActivatedEIP(6800)) { + const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas(message.caller) + accessGasUsed += originAccessGas + message.gasLimit -= originAccessGas + if (this.DEBUG) { + debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + } + } + let account = await this.stateManager.getAccount(message.caller) if (!account) { account = new Account() @@ -339,6 +376,21 @@ export class EVM implements EVMInterface { message.data = new Uint8Array(0) message.to = await this._generateAddress(message) + if (this.common.isActivatedEIP(6800)) { + const sendsValue = message.value !== BIGINT_0 + const contractCreateAccessGas = message.accessWitness!.touchAndChargeContractCreateInit( + message.to, + { sendsValue } + ) + accessGasUsed += contractCreateAccessGas + message.gasLimit -= contractCreateAccessGas + if (this.DEBUG) { + debugGas( + `Contract creation access used (${contractCreateAccessGas} gas (-> ${message.gasLimit}))` + ) + } + } + if (this.common.isActivatedEIP(6780)) { message.createdAddresses!.add(message.to.toString()) } @@ -416,7 +468,7 @@ export class EVM implements EVMInterface { return { createdAddress: message.to, execResult: { - executionGasUsed: BIGINT_0, + executionGasUsed: accessGasUsed, gasRefund: message.gasRefund, exceptionError: errorMessage, // only defined if addToBalance failed returnValue: new Uint8Array(0), @@ -429,6 +481,7 @@ export class EVM implements EVMInterface { } let result = await this.runInterpreter(message) + result.executionGasUsed += accessGasUsed // fee for size of the return value let totalGas = result.executionGasUsed let returnFee = BIGINT_0 diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index fc946f531a..12fd12e0c8 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -1,4 +1,4 @@ -import { bytesToHex, toBytes } from '@ethereumjs/util' +import { bytesToHex, toBytes, BIGINT_0 } from '@ethereumjs/util' import { getKey, getStem } from '@ethereumjs/verkle' import type { Address, PrefixedHexString } from '@ethereumjs/util' @@ -17,11 +17,11 @@ export const CODE_OFFSET = 128 export const VERKLE_NODE_WIDTH = 256 export const MAIN_STORAGE_OFFSET = 256 ** 31 -const WitnessBranchReadCost = 1900 -const WitnessChunkReadCost = 200 -const WitnessBranchWriteCost = 3000 -const WitnessChunkWriteCost = 500 -const WitnessChunkFillCost = 6200 +const WitnessBranchReadCost = BigInt(1900) +const WitnessChunkReadCost = BigInt(200) +const WitnessBranchWriteCost = BigInt(3000) +const WitnessChunkWriteCost = BigInt(500) +const WitnessChunkFillCost = BigInt(6200) // read is a default access event if stem or chunk is present type StemAccessEvent = { write?: boolean } @@ -52,8 +52,8 @@ export class AccessWitness { this.chunks = opts.chunks ?? new Map() } - touchAndChargeProofOfAbsence(address: Address): number { - let gas = 0 + touchAndChargeProofOfAbsence(address: Address): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnReadAndComputeGas(address, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnReadAndComputeGas(address, 0, BALANCE_LEAF_KEY) @@ -64,8 +64,8 @@ export class AccessWitness { return gas } - touchAndChargeMessageCall(address: Address): number { - let gas = 0 + touchAndChargeMessageCall(address: Address): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnReadAndComputeGas(address, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnReadAndComputeGas(address, 0, CODE_SIZE_LEAF_KEY) @@ -73,8 +73,8 @@ export class AccessWitness { return gas } - touchAndChargeValueTransfer(caller: Address, target: Address): number { - let gas = 0 + touchAndChargeValueTransfer(caller: Address, target: Address): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnWriteAndComputeGas(caller, 0, BALANCE_LEAF_KEY) gas += this.touchAddressOnWriteAndComputeGas(target, 0, BALANCE_LEAF_KEY) @@ -84,22 +84,22 @@ export class AccessWitness { touchAndChargeContractCreateInit( address: Address, - { createSendsValue }: { createSendsValue?: boolean } = {} - ): number { - let gas = 0 + { sendsValue }: { sendsValue?: boolean } = {} + ): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnWriteAndComputeGas(address, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnWriteAndComputeGas(address, 0, NONCE_LEAF_KEY) gas += this.touchAddressOnWriteAndComputeGas(address, 0, CODE_KECCAK_LEAF_KEY) - if (createSendsValue === true) { + if (sendsValue === true) { gas += this.touchAddressOnWriteAndComputeGas(address, 0, BALANCE_LEAF_KEY) } return gas } - touchAndChargeContractCreateCompleted(address: Address): number { - let gas = 0 + touchAndChargeContractCreateCompleted(address: Address): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnWriteAndComputeGas(address, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnWriteAndComputeGas(address, 0, BALANCE_LEAF_KEY) @@ -110,8 +110,8 @@ export class AccessWitness { return gas } - touchTxOriginAndComputeGas(origin: Address): number { - let gas = 0 + touchTxOriginAndComputeGas(origin: Address): bigint { + let gas = BIGINT_0 gas += this.touchAddressOnReadAndComputeGas(origin, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnReadAndComputeGas(origin, 0, CODE_SIZE_LEAF_KEY) @@ -124,7 +124,7 @@ export class AccessWitness { } touchTxExistingAndComputeGas(target: Address, { sendsValue }: { sendsValue?: boolean } = {}) { - let gas = 0 + let gas = BIGINT_0 gas += this.touchAddressOnReadAndComputeGas(target, 0, VERSION_LEAF_KEY) gas += this.touchAddressOnReadAndComputeGas(target, 0, CODE_SIZE_LEAF_KEY) @@ -144,7 +144,7 @@ export class AccessWitness { address: Address, treeIndex: number, subIndex: number | Uint8Array - ): number { + ): bigint { return this.touchAddressAndChargeGas(address, treeIndex, subIndex, { isWrite: true }) } @@ -152,7 +152,7 @@ export class AccessWitness { address: Address, treeIndex: number, subIndex: number | Uint8Array - ): number { + ): bigint { return this.touchAddressAndChargeGas(address, treeIndex, subIndex, { isWrite: false }) } @@ -161,8 +161,9 @@ export class AccessWitness { treeIndex: number, subIndex: number | Uint8Array, { isWrite }: { isWrite?: boolean } - ): number { - let gas = 0 + ): bigint { + let gas = BIGINT_0 + const { stemRead, stemWrite, chunkRead, chunkWrite, chunkFill } = this.touchAddress( address, treeIndex, diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 0a02869e7e..a40c7633ea 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -7,9 +7,11 @@ import { Address, BIGINT_0, KECCAK256_NULL, + bigIntToBytes, bytesToHex, bytesToUnprefixedHex, equalsBytes, + generateAddress, hexToBytes, short, } from '@ethereumjs/util' @@ -216,7 +218,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // available there stateAccesses = new AccessWitness() } - const txAccesses = stateAccesses?.shallowCopy() + let txAccesses = stateAccesses?.shallowCopy() const { tx, block } = opts @@ -320,8 +322,29 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { throw new Error(msg) } + let upfrontAwGas = BIGINT_0 + if (this.common.isActivatedEIP(6800)) { + upfrontAwGas += txAccesses!.touchTxOriginAndComputeGas(caller) + const sendsValue = tx.value !== BIGINT_0 + if (tx.to !== undefined) { + upfrontAwGas += txAccesses!.touchTxExistingAndComputeGas(tx.to, { sendsValue }) + debug(`Sender upfront awGas requirement for non contract creation tx is ${upfrontAwGas}`) + } else { + const contractTo = new Address(generateAddress(caller.bytes, bigIntToBytes(nonce))) + upfrontAwGas += txAccesses!.touchAndChargeContractCreateInit(contractTo, { sendsValue }) + debug( + `Sender upfront awGas requirement is contract creation at=${short( + contractTo.bytes + )} is ${upfrontAwGas}` + ) + } + + // reset txAccesses to remove the caches so that access gas can be correctly consumed inside the evm run + txAccesses = stateAccesses?.shallowCopy() + } + // Check balance against upfront tx cost - const upFrontCost = tx.getUpfrontCost(block.header.baseFeePerGas) + const upFrontCost = tx.getUpfrontCost(block.header.baseFeePerGas) + upfrontAwGas if (balance < upFrontCost) { if (opts.skipBalance === true && fromAccount.balance < upFrontCost) { if (tx.supports(Capability.EIP1559FeeMarket) === false) { From 53af5f2e2da422d70f7d15ac987fcbfc6657982e Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 17 Dec 2023 16:26:21 +0530 Subject: [PATCH 20/75] complete, debug and fix the call and create access charges --- packages/evm/src/evm.ts | 151 ++++++++++++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 28 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 8e5fd41b95..9a20d306ec 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -224,13 +224,28 @@ export class EVM implements EVMInterface { protected async _executeCall(message: MessageWithTo): Promise { let accessGasUsed = BIGINT_0 if (this.common.isActivatedEIP(6800)) { - const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas( - message.authcallOrigin ?? message.caller - ) - accessGasUsed += originAccessGas - message.gasLimit -= originAccessGas - if (this.DEBUG) { - debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + if (message.depth === 0) { + const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas( + message.authcallOrigin ?? message.caller + ) + accessGasUsed += originAccessGas + message.gasLimit -= originAccessGas + if (message.gasLimit < BIGINT_0) { + // remove this negative amount from accessGasUsed to get the real gas used and set + // gasLimit back to zero and throw OOG + accessGasUsed += message.gasLimit + message.gasLimit = BIGINT_0 + if (this.DEBUG) { + debugGas( + `Origin access charged(${originAccessGas}) caused OOG (-> ${message.gasLimit})` + ) + } + return { execResult: OOGResult(accessGasUsed) } + } else { + if (this.DEBUG) { + debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + } + } } } @@ -249,20 +264,60 @@ export class EVM implements EVMInterface { } if (this.common.isActivatedEIP(6800)) { - const sendsValue = message.value !== BIGINT_0 - const destAccessGas = message.accessWitness!.touchTxExistingAndComputeGas(message.to, { - sendsValue, - }) - accessGasUsed += destAccessGas - message.gasLimit -= destAccessGas - if (this.DEBUG) { - debugGas(`Destination access used (${destAccessGas} gas (-> ${message.gasLimit}))`) + if (message.depth === 0) { + const sendsValue = message.value !== BIGINT_0 + const destAccessGas = message.accessWitness!.touchTxExistingAndComputeGas(message.to, { + sendsValue, + }) + accessGasUsed += destAccessGas + message.gasLimit -= destAccessGas + if (message.gasLimit < BIGINT_0) { + // remove this negative amount from accessGasUsed to get the real gas used and set + // gasLimit back to zero and throw OOG + accessGasUsed += message.gasLimit + message.gasLimit = BIGINT_0 + if (this.DEBUG) { + debugGas( + `Destination access charged(${destAccessGas}) caused OOG (-> ${message.gasLimit})` + ) + } + return { execResult: OOGResult(accessGasUsed) } + } else { + if (this.DEBUG) { + debugGas(`Destination access used (${destAccessGas} gas (-> ${message.gasLimit}))`) + } + } } } // Load `to` account let toAccount = await this.stateManager.getAccount(message.to) if (!toAccount) { + if (this.common.isActivatedEIP(6800)) { + const absenceProofAccessGas = message.accessWitness!.touchAndChargeProofOfAbsence( + message.to + ) + accessGasUsed += absenceProofAccessGas + message.gasLimit -= accessGasUsed + if (message.gasLimit < BIGINT_0) { + // remove this negative amount from accessGasUsed to get the real gas used and set + // gasLimit back to zero and throw OOG + accessGasUsed += message.gasLimit + message.gasLimit = BIGINT_0 + if (this.DEBUG) { + debugGas( + `Proof of absense access charged(${absenceProofAccessGas}) caused OOG (-> ${message.gasLimit})` + ) + } + return { execResult: OOGResult(accessGasUsed) } + } else { + if (this.DEBUG) { + debugGas( + `Proof of absense access used (${absenceProofAccessGas} gas (-> ${message.gasLimit}))` + ) + } + } + } toAccount = new Account() } // Add tx value to the `to` account @@ -340,12 +395,25 @@ export class EVM implements EVMInterface { protected async _executeCreate(message: Message): Promise { let accessGasUsed = BIGINT_0 + let gasLimit = message.gasLimit + if (this.common.isActivatedEIP(6800)) { const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas(message.caller) accessGasUsed += originAccessGas - message.gasLimit -= originAccessGas - if (this.DEBUG) { - debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + gasLimit -= originAccessGas + if (gasLimit < BIGINT_0) { + // remove this negative amount from accessGasUsed to get the real gas used and set + // gasLimit back to zero and throw OOG + accessGasUsed += message.gasLimit + gasLimit = BIGINT_0 + if (this.DEBUG) { + debugGas(`Origin access charged(${originAccessGas}) caused OOG (-> ${gasLimit})`) + } + return { execResult: OOGResult(accessGasUsed) } + } else { + if (this.DEBUG) { + debugGas(`Origin access used (${originAccessGas} gas (-> ${gasLimit}))`) + } } } @@ -383,11 +451,20 @@ export class EVM implements EVMInterface { { sendsValue } ) accessGasUsed += contractCreateAccessGas - message.gasLimit -= contractCreateAccessGas - if (this.DEBUG) { - debugGas( - `Contract creation access used (${contractCreateAccessGas} gas (-> ${message.gasLimit}))` - ) + gasLimit -= contractCreateAccessGas + if (gasLimit < BIGINT_0) { + // remove this negative amount from accessGasUsed to get the real gas used and set + // gasLimit back to zero and throw OOG + accessGasUsed += message.gasLimit + gasLimit = BIGINT_0 + if (this.DEBUG) { + debugGas(`Origin access charged(${contractCreateAccessGas}) caused OOG (-> ${gasLimit})`) + } + return { execResult: OOGResult(message.gasLimit) } + } else { + if (this.DEBUG) { + debugGas(`Origin access used (${contractCreateAccessGas} gas (-> ${gasLimit}))`) + } } } @@ -409,6 +486,7 @@ export class EVM implements EVMInterface { !(equalsBytes(toAccount.codeHash, KECCAK256_NULL) === true) ) { if (this.DEBUG) { + accessGasUsed debug(`Returning on address collision`) } return { @@ -468,7 +546,8 @@ export class EVM implements EVMInterface { return { createdAddress: message.to, execResult: { - executionGasUsed: accessGasUsed, + // Query? is there any gas used here i.e. accessGasUsed ? + executionGasUsed: BIGINT_0, gasRefund: message.gasRefund, exceptionError: errorMessage, // only defined if addToBalance failed returnValue: new Uint8Array(0), @@ -480,8 +559,10 @@ export class EVM implements EVMInterface { debug(`Start bytecode processing...`) } - let result = await this.runInterpreter(message) + // run the message with the updated gas limit and add accessed gas used to the result + let result = await this.runInterpreter({ ...message, gasLimit } as Message) result.executionGasUsed += accessGasUsed + // fee for size of the return value let totalGas = result.executionGasUsed let returnFee = BIGINT_0 @@ -493,6 +574,7 @@ export class EVM implements EVMInterface { debugGas(`Add return value size fee (${returnFee} to gas used (-> ${totalGas}))`) } } + gasLimit = message.gasLimit - totalGas // Check for SpuriousDragon EIP-170 code size limit let allowedCodeSize = true @@ -578,9 +660,22 @@ export class EVM implements EVMInterface { result.returnValue !== undefined && result.returnValue.length !== 0 ) { - await this.stateManager.putContractCode(message.to, result.returnValue) - if (this.DEBUG) { - debug(`Code saved on new contract creation`) + const createCompleteAccessGas = message.accessWitness!.touchAndChargeContractCreateCompleted( + message.to + ) + gasLimit -= createCompleteAccessGas + if (gasLimit < BIGINT_0) { + if (this.DEBUG) { + debug(`Contract create access (${createCompleteAccessGas}) caused OOG (-> ${gasLimit})`) + } + result = { ...result, ...OOGResult(message.gasLimit) } + } else { + debug(`Contract create access used (${createCompleteAccessGas}) gas (-> ${gasLimit})`) + result.executionGasUsed += createCompleteAccessGas + await this.stateManager.putContractCode(message.to, result.returnValue) + if (this.DEBUG) { + debug(`Code saved on new contract creation`) + } } } else if (CodestoreOOG) { // This only happens at Frontier. But, let's do a sanity check; From 1a34e71f09ae0c94621bf2b09289e7096fe165f8 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 26 Dec 2023 16:38:31 +0530 Subject: [PATCH 21/75] plug the access gas usage on the evm opcode runs --- packages/evm/src/interpreter.ts | 11 +++ packages/evm/src/opcodes/functions.ts | 12 +++ packages/evm/src/opcodes/gas.ts | 92 +++++++++++++++++++ packages/statemanager/src/accessWitness.ts | 34 ++++++- .../src/statelessVerkleStateManager.ts | 24 ++--- 5 files changed, 154 insertions(+), 19 deletions(-) diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index 8869804de6..b7644d1683 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -310,8 +310,19 @@ export class Interpreter { throw new EvmError(ERROR.INVALID_OPCODE) } + if (this.common.isActivatedEIP(6800)) { + const contract = this._runState.interpreter.getAddress() + const statelessGas = + this._runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( + contract, + this._runState.programCounter, + this._runState.programCounter + ) + gas += statelessGas + } // Reduce opcode's base fee this.useGas(gas, opInfo) + // Advance program counter this._runState.programCounter++ diff --git a/packages/evm/src/opcodes/functions.ts b/packages/evm/src/opcodes/functions.ts index e0c4a061a0..d100d8d65c 100644 --- a/packages/evm/src/opcodes/functions.ts +++ b/packages/evm/src/opcodes/functions.ts @@ -911,6 +911,18 @@ export const handlers: Map = new Map([ trap(ERROR.OUT_OF_RANGE) } + if (common.isActivatedEIP(6800)) { + const contract = runState.interpreter.getAddress() + const startOffset = Math.min(runState.code.length, runState.programCounter - numToPush + 1) + const endOffset = Math.min(runState.code.length, startOffset + numToPush) + const statelessGas = runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( + contract, + startOffset, + endOffset + ) + runState.interpreter.useGas(statelessGas, `PUSH`) + } + if (!runState.shouldDoJumpAnalysis) { runState.stack.push(runState.cachedPushes[runState.programCounter]) runState.programCounter += numToPush diff --git a/packages/evm/src/opcodes/gas.ts b/packages/evm/src/opcodes/gas.ts index c1dab51c78..0109908cd0 100644 --- a/packages/evm/src/opcodes/gas.ts +++ b/packages/evm/src/opcodes/gas.ts @@ -1,4 +1,5 @@ import { Hardfork } from '@ethereumjs/common' +import { CODE_SIZE_LEAF_KEY, getTreeIndexesForStorageSlot } from '@ethereumjs/statemanager' import { Address, BIGINT_0, @@ -110,6 +111,21 @@ export const dynamicGasHandlers: Map codeSize) { + codeEnd = codeSize + } + + gas += runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( + contract, + Number(_codeOffset), + Number(codeEnd) + ) + } } return gas }, @@ -122,6 +138,16 @@ export const dynamicGasHandlers: Map codeSize) { + codeEnd = codeSize + } + + gas += runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( + contract, + Number(_codeOffset), + Number(codeEnd) + ) + } } return gas }, @@ -209,6 +250,16 @@ export const dynamicGasHandlers: Map Date: Tue, 26 Dec 2023 18:17:50 +0530 Subject: [PATCH 22/75] debug and fix the code chunk accesses and the poststate setting --- packages/statemanager/src/accessWitness.ts | 2 +- packages/statemanager/src/statelessVerkleStateManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 8c837f2891..1690733844 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -142,7 +142,7 @@ export class AccessWitness { touchCodeChunksRangeOnReadAndChargeGas(contact: Address, startPc: number, endPc: number) { let gas = BIGINT_0 - for (let chunkNum = startPc / 31; chunkNum <= endPc / 31; chunkNum++) { + for (let chunkNum = Math.floor(startPc / 31); chunkNum <= Math.floor(endPc / 31); chunkNum++) { const { treeIndex, subIndex } = getTreeIndicesForCodeChunk(chunkNum) gas += this.touchAddressOnReadAndComputeGas(contact, treeIndex, subIndex) } diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index fa458872c7..eadd475393 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -421,7 +421,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { */ async putContractStorage(address: Address, key: Uint8Array, value: Uint8Array): Promise { const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) - this._state[bytesToHex(storageKey)] = bytesToHex(value) + this._state[bytesToHex(storageKey)] = bytesToHex(setLengthRight(value, 32)) } /** From 351960557c97b4695caa0eb3bb5dbc1116b34208 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 27 Dec 2023 14:10:16 +0530 Subject: [PATCH 23/75] implement access merging and accessed state tracking and traversing --- packages/statemanager/src/accessWitness.ts | 53 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 1690733844..77f7f1b38a 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -37,18 +37,22 @@ type AccessEventFlags = { chunkFill: boolean } +// Since stem is predersen hashed, it is useful to maintain the reverse relationship +type StemMeta = { address: Address; treeIndex: number } +type AccessedState = { address: Address; treeIndex: number; chunkIndex: number } + export class AccessWitness { - stems: Map + stems: Map chunks: Map constructor( opts: { - stems?: Map + stems?: Map chunks?: Map } = {} ) { - this.stems = opts.stems ?? new Map() + this.stems = opts.stems ?? new Map() this.chunks = opts.chunks ?? new Map() } @@ -219,7 +223,7 @@ export class AccessWitness { let accessedStem = this.stems.get(accessedStemHex) if (accessedStem === undefined) { stemRead = true - accessedStem = {} + accessedStem = { address, treeIndex } this.stems.set(accessedStemHex, accessedStem) } @@ -254,9 +258,44 @@ export class AccessWitness { return new AccessWitness() } - merge(_accessWitness: AccessWitness): void { - // TODO - add merging accessWitnesses into the current one - return + merge(accessWitness: AccessWitness): void { + for (const [chunkKey, chunkValue] of accessWitness.chunks.entries()) { + const stemKey = chunkKey.slice(0, chunkKey.length - 2) + const stem = accessWitness.stems.get(stemKey) + if (stem === undefined) { + throw Error(`Internal error: missing stem for the chunkKey=${chunkKey}`) + } + + const thisStem = this.stems.get(stemKey) + if (thisStem === undefined) { + this.stems.set(stemKey, stem) + } else { + thisStem.write = thisStem.write !== true ? stem.write : true + } + + const thisChunk = this.chunks.get(chunkKey) + if (thisChunk === undefined) { + this.chunks.set(chunkKey, chunkValue) + } else { + thisChunk.write = thisChunk.write !== true ? chunkValue.write : true + thisChunk.fill = thisChunk.fill !== true ? thisChunk.fill : true + } + } + } + + *accesses(): Generator { + for (const chunkKey of this.chunks.keys()) { + // drop the last byte + const stemKey = chunkKey.slice(0, chunkKey.length - 2) + const stem = this.stems.get(stemKey) + if (stem === undefined) { + throw Error(`Internal error: missing stem for the chunkKey=${chunkKey}`) + } + const { address, treeIndex } = stem + const chunkIndex = Number(`0x${chunkKey.slice(chunkKey.length - 2)}`) + const accessedState = { address, treeIndex, chunkIndex } + yield accessedState + } } } From 1ac77fa63f3b9264089428800417c41f2f65b3b3 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 27 Dec 2023 14:24:35 +0530 Subject: [PATCH 24/75] also provide chunkKey for easy reference --- packages/statemanager/src/accessWitness.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 77f7f1b38a..70b5e9b184 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -39,7 +39,12 @@ type AccessEventFlags = { // Since stem is predersen hashed, it is useful to maintain the reverse relationship type StemMeta = { address: Address; treeIndex: number } -type AccessedState = { address: Address; treeIndex: number; chunkIndex: number } +type AccessedState = { + address: Address + treeIndex: number + chunkIndex: number + chunkKey: PrefixedHexString +} export class AccessWitness { stems: Map @@ -293,7 +298,7 @@ export class AccessWitness { } const { address, treeIndex } = stem const chunkIndex = Number(`0x${chunkKey.slice(chunkKey.length - 2)}`) - const accessedState = { address, treeIndex, chunkIndex } + const accessedState = { address, treeIndex, chunkIndex, chunkKey } yield accessedState } } From e2af8de6138de7f8f704ae123ea639d7e61705ab Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 31 Dec 2023 00:16:01 +0530 Subject: [PATCH 25/75] decode raw accesses to structured ones and debug log them --- packages/statemanager/src/accessWitness.ts | 63 ++++++++++++++++++- .../src/statelessVerkleStateManager.ts | 12 ++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 70b5e9b184..e389db8901 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -39,13 +39,29 @@ type AccessEventFlags = { // Since stem is predersen hashed, it is useful to maintain the reverse relationship type StemMeta = { address: Address; treeIndex: number } -type AccessedState = { +type RawAccessedState = { address: Address treeIndex: number chunkIndex: number chunkKey: PrefixedHexString } +export enum AccessedStateType { + Version = 'version', + Balance = 'balance', + Nonce = 'nonce', + CodeHash = 'codeHash', + CodeSize = 'codeSize', + Code = 'code', + Storage = 'storage', +} + +type AccessedState = + | { type: Exclude } + | { type: AccessedStateType.Code; codeOffset: number } + | { type: AccessedStateType.Storage; slot: bigint } +type AccessedStateWithAddress = AccessedState & { address: Address } + export class AccessWitness { stems: Map @@ -288,7 +304,7 @@ export class AccessWitness { } } - *accesses(): Generator { + *rawAccesses(): Generator { for (const chunkKey of this.chunks.keys()) { // drop the last byte const stemKey = chunkKey.slice(0, chunkKey.length - 2) @@ -302,6 +318,14 @@ export class AccessWitness { yield accessedState } } + + *accesses(): Generator { + for (const rawAccess of this.rawAccesses()) { + const { address, treeIndex, chunkIndex } = rawAccess + const accessedState = decodeAccessedState(treeIndex, chunkIndex) + yield { ...accessedState, address } + } + } } export function getTreeIndexesForStorageSlot(storageKey: number): { @@ -326,3 +350,38 @@ export function getTreeIndicesForCodeChunk(chunkId: number) { const subIndex = (CODE_OFFSET + chunkId) % VERKLE_NODE_WIDTH return { treeIndex, subIndex } } + +export function decodeAccessedState(treeIndex: number, chunkIndex: number): AccessedState { + const position = treeIndex * VERKLE_NODE_WIDTH + chunkIndex + switch (position) { + case 0: + return { type: AccessedStateType.Version } + case 1: + return { type: AccessedStateType.Balance } + case 2: + return { type: AccessedStateType.Nonce } + case 3: + return { type: AccessedStateType.CodeHash } + case 4: + return { type: AccessedStateType.CodeSize } + default: + if (position < HEADER_STORAGE_OFFSET) { + throw Error(`No attribute yet stored >=5 and <${HEADER_STORAGE_OFFSET}`) + } + + if (position >= HEADER_STORAGE_OFFSET && position < CODE_OFFSET) { + const slot = BigInt(position - HEADER_STORAGE_OFFSET) + return { type: AccessedStateType.Storage, slot } + } else if (position >= CODE_OFFSET && position < MAIN_STORAGE_OFFSET) { + const codeChunkIdx = position - CODE_OFFSET + return { type: AccessedStateType.Code, codeOffset: codeChunkIdx * 31 } + } else if (position >= MAIN_STORAGE_OFFSET) { + const slot = BigInt(position - MAIN_STORAGE_OFFSET) + return { type: AccessedStateType.Storage, slot } + } else { + throw Error( + `Invalid treeIndex=${treeIndex} chunkIndex=${chunkIndex} for verkle tree access` + ) + } + } +} diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index eadd475393..549aee1815 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -19,6 +19,7 @@ import { concatBytes, equalsBytes } from 'ethereum-cryptography/utils' import { AccessWitness, + AccessedStateType, BALANCE_LEAF_KEY, CODE_KECCAK_LEAF_KEY, CODE_SIZE_LEAF_KEY, @@ -539,6 +540,17 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // Verifies that the witness post-state matches the computed post-state verifyPostState(): boolean { + for (const accessedState of this.accessWitness!.accesses()) { + const { address, type } = accessedState + let extraMeta = '' + if (accessedState.type === AccessedStateType.Code) { + extraMeta = `codeOffset=${accessedState.codeOffset}` + } else if (accessedState.type === AccessedStateType.Storage) { + extraMeta = `slot=${accessedState.slot}` + } + debug(`block accesses: address=${address} type=${type} ${extraMeta}`) + } + for (const [key, canonicalValue] of Object.entries(this._postState)) { const computedValue = this._state[key] if (canonicalValue !== computedValue) { From ba47683ea34f972d9f0ad2e9b41b9cd645c1b549 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 31 Dec 2023 00:16:56 +0530 Subject: [PATCH 26/75] debug and add the missing accesses for coinbase, withdrawals --- packages/vm/src/buildBlock.ts | 4 ++-- packages/vm/src/runBlock.ts | 21 ++++++++++++++++++--- packages/vm/src/runTx.ts | 10 ++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 23f897554f..1eae1f7e80 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -173,7 +173,7 @@ export class BlockBuilder { this.headerData.coinbase !== undefined ? new Address(toBytes(this.headerData.coinbase)) : Address.zero() - await rewardAccount(this.vm.evm, coinbase, reward) + await rewardAccount(this.vm.common, this.vm.evm, coinbase, reward) } /** @@ -189,7 +189,7 @@ export class BlockBuilder { if (amount === 0n) continue // Withdrawal amount is represented in Gwei so needs to be // converted to wei - await rewardAccount(this.vm.evm, address, amount * GWEI_TO_WEI) + await rewardAccount(this.vm.common, this.vm.evm, address, amount * GWEI_TO_WEI) } } diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 19c40e4078..d4f0623c28 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -34,6 +34,7 @@ import type { TxReceipt, } from './types.js' import type { VM } from './vm.js' +import type { Common } from '@ethereumjs/common' import type { EVM, EVMInterface } from '@ethereumjs/evm' const { debug: createDebugLogger } = debugDefault @@ -506,7 +507,7 @@ async function assignWithdrawals(this: VM, block: Block): Promise { // converted to wei // Note: event if amount is 0, still reward the account // such that the account is touched and marked for cleanup if it is empty - await rewardAccount(this.evm, address, amount * GWEI_TO_WEI) + await rewardAccount(this.common, this.evm, address, amount * GWEI_TO_WEI) } } @@ -523,14 +524,14 @@ async function assignBlockRewards(this: VM, block: Block): Promise { // Reward ommers for (const ommer of ommers) { const reward = calculateOmmerReward(ommer.number, block.header.number, minerReward) - const account = await rewardAccount(this.evm, ommer.coinbase, reward) + const account = await rewardAccount(this.common, this.evm, ommer.coinbase, reward) if (this.DEBUG) { debug(`Add uncle reward ${reward} to account ${ommer.coinbase} (-> ${account.balance})`) } } // Reward miner const reward = calculateMinerReward(minerReward, ommers.length) - const account = await rewardAccount(this.evm, block.header.coinbase, reward) + const account = await rewardAccount(this.common, this.evm, block.header.coinbase, reward) if (this.DEBUG) { debug(`Add miner reward ${reward} to account ${block.header.coinbase} (-> ${account.balance})`) } @@ -558,16 +559,30 @@ export function calculateMinerReward(minerReward: bigint, ommersNum: number): bi } export async function rewardAccount( + common: Common, evm: EVMInterface, address: Address, reward: bigint ): Promise { let account = await evm.stateManager.getAccount(address) if (account === undefined) { + if (common.isActivatedEIP(6800)) { + ;( + evm.stateManager as StatelessVerkleStateManager + ).accessWitness!.touchAndChargeProofOfAbsence(address) + } account = new Account() } account.balance += reward await evm.journal.putAccount(address, account) + + if (common.isActivatedEIP(6800)) { + // use this utility to build access but the computed gas is not charged and hence free + ;(evm.stateManager as StatelessVerkleStateManager).accessWitness!.touchTxExistingAndComputeGas( + address, + { sendsValue: true } + ) + } return account } diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index a40c7633ea..71a768ca11 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -595,6 +595,9 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { let minerAccount = await state.getAccount(miner) if (minerAccount === undefined) { + if (this.common.isActivatedEIP(6800)) { + ;(state as StatelessVerkleStateManager).accessWitness!.touchAndChargeProofOfAbsence(miner) + } minerAccount = new Account() } // add the amount spent on gas to the miner's account @@ -604,6 +607,13 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { : results.amountSpent minerAccount.balance += results.minerValue + if (this.common.isActivatedEIP(6800)) { + // use this utility to build access but the computed gas is not charged and hence free + ;(state as StatelessVerkleStateManager).accessWitness!.touchTxExistingAndComputeGas(miner, { + sendsValue: true, + }) + } + // Put the miner account into the state. If the balance of the miner account remains zero, note that // the state.putAccount function puts this into the "touched" accounts. This will thus be removed when // we clean the touched accounts below in case we are in a fork >= SpuriousDragon From 252175503eef51c6cf4a07c05d84c96936d92f19 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sat, 30 Dec 2023 14:09:54 -0500 Subject: [PATCH 27/75] stateManager: implement cache handling in the context of statelessness --- .../src/statelessVerkleStateManager.ts | 150 +++++++++++++----- 1 file changed, 110 insertions(+), 40 deletions(-) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index eadd475393..b30effbd45 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -1,5 +1,7 @@ +import { RLP } from '@ethereumjs/rlp' import { Account, + KECCAK256_NULL, KECCAK256_NULL_S, bigIntToBytes, bytesToBigInt, @@ -27,7 +29,7 @@ import { getTreeIndexesForStorageSlot, getTreeIndicesForCodeChunk, } from './accessWitness.js' -import { AccountCache, CacheType, StorageCache } from './cache/index.js' +import { AccountCache, CacheType, CodeCache, StorageCache } from './cache/index.js' import { OriginalStorageCache } from './cache/originalStorageCache.js' import type { DefaultStateManager } from './stateManager.js' @@ -101,12 +103,13 @@ type CacheSettings = { * Options dictionary. */ export interface StatelessVerkleStateManagerOpts { - accountCacheOpts?: CacheOptions /** * The common to use */ common?: Common + accountCacheOpts?: CacheOptions storageCacheOpts?: CacheOptions + codeCacheOpts?: CacheOptions accesses?: AccessWitness } @@ -130,12 +133,13 @@ const PUSH32 = PUSH_OFFSET + 32 export class StatelessVerkleStateManager implements EVMStateManagerInterface { _accountCache?: AccountCache _storageCache?: StorageCache - _codeCache: { [key: string]: Uint8Array } + _codeCache?: CodeCache originalStorageCache: OriginalStorageCache protected readonly _accountCacheSettings: CacheSettings protected readonly _storageCacheSettings: CacheSettings + protected readonly _codeCacheSettings: CacheSettings /** * StateManager is run in DEBUG mode (default: false) @@ -166,6 +170,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { * Instantiate the StateManager interface. */ constructor(opts: StatelessVerkleStateManagerOpts = {}) { + this.originalStorageCache = new OriginalStorageCache(this.getContractStorage.bind(this)) + this._accountCacheSettings = { deactivate: opts.accountCacheOpts?.deactivate ?? false, type: opts.accountCacheOpts?.type ?? CacheType.ORDERED_MAP, @@ -192,9 +198,19 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { }) } - this.originalStorageCache = new OriginalStorageCache(this.getContractStorage.bind(this)) + this._codeCacheSettings = { + deactivate: + (opts.codeCacheOpts?.deactivate === true || opts.codeCacheOpts?.size === 0) ?? false, + type: opts.codeCacheOpts?.type ?? CacheType.ORDERED_MAP, + size: opts.codeCacheOpts?.size ?? 20000, + } - this._codeCache = {} + if (!this._codeCacheSettings.deactivate) { + this._codeCache = new CodeCache({ + size: this._codeCacheSettings.size, + type: this._codeCacheSettings.type, + }) + } // Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables // Additional window check is to prevent vite browser bundling (and potentially other) to break @@ -344,24 +360,21 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { * @param value - The value of the `code` */ async putContractCode(address: Address, value: Uint8Array): Promise { - const stem = getStem(address, 0) - const codeHashKey = this.getTreeKeyForCodeHash(stem) - - const codeHash = bytesToHex(keccak256(value)) - - this._state[bytesToHex(codeHashKey)] = codeHash - if (this.DEBUG) { debug(`putContractCode address=${address.toString()} value=${short(value)}`) } + this._codeCache?.put(address, value) - if (KECCAK256_NULL_S === codeHash) { + const codeHash = keccak256(value) + if (KECCAK256_NULL === codeHash) { // If the code hash is the null hash, no code has to be stored return } - // TODO: Slice the code into chunks and add them to the state - throw new Error('Not implemented') + if ((await this.getAccount(address)) === undefined) { + await this.putAccount(address, new Account()) + } + await this.modifyAccountFields(address, { codeHash }) } /** @@ -374,9 +387,24 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { if (this.DEBUG) { debug(`getContractCode address=${address.toString()}`) } + + if (!this._codeCacheSettings.deactivate) { + const elem = this._codeCache?.get(address) + if (elem !== undefined) { + return elem.code ?? new Uint8Array(0) + } + } + + const account = await this.getAccount(address) + if (!account) { + return new Uint8Array(0) + } + if (!account.isContract()) { + return new Uint8Array(0) + } + // Get the contract code size const codeSizeKey = this.getTreeKeyForCodeSize(getStem(address, 0)) - const codeSizeLE = hexToBytes(this._state[bytesToHex(codeSizeKey)] ?? '0x') // Calculate number of chunks @@ -406,10 +434,21 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { * If this does not exist an empty `Uint8Array` is returned. */ async getContractStorage(address: Address, key: Uint8Array): Promise { + if (!this._storageCacheSettings.deactivate) { + const value = this._storageCache!.get(address, key) + if (value !== undefined) { + return value + } + } + const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) - const storage = toBytes(this._state[bytesToHex(storageKey)]) + const storageValue = toBytes(this._state[bytesToHex(storageKey)]) + + if (!this._storageCacheSettings.deactivate) { + this._storageCache?.put(address, key, storageValue ?? hexToBytes('0x80')) + } - return storage + return storageValue } /** @@ -420,8 +459,14 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { * @param value - Value to set at `key` for account corresponding to `address`. Cannot be more than 32 bytes. Leading zeros are stripped. If it is a empty or filled with zeros, deletes the value. */ async putContractStorage(address: Address, key: Uint8Array, value: Uint8Array): Promise { - const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) - this._state[bytesToHex(storageKey)] = bytesToHex(setLengthRight(value, 32)) + if (!this._storageCacheSettings.deactivate) { + const encodedValue = RLP.encode(value) + this._storageCache!.put(address, key, encodedValue) + } else { + // TODO: Consider refactoring this in a writeContractStorage function? Like in stateManager.ts + const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) + this._state[bytesToHex(storageKey)] = bytesToHex(setLengthRight(value, 32)) + } } /** @@ -431,13 +476,23 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { async clearContractStorage(address: Address): Promise { const stem = getStem(address, 0) const codeHashKey = this.getTreeKeyForCodeHash(stem) + this._storageCache?.clearContractStorage(address) // Update codeHash to `c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` this._state[bytesToHex(codeHashKey)] = KECCAK256_NULL_S // TODO: Clear all storage slots (how?) } - async getAccount(address: Address): Promise { + async getAccount(address: Address): Promise { + if (!this._accountCacheSettings.deactivate) { + const elem = this._accountCache!.get(address) + if (elem !== undefined) { + return elem.accountRLP !== undefined + ? Account.fromRlpSerializedAccount(elem.accountRLP) + : undefined + } + } + const stem = getStem(address, 0) const balanceKey = this.getTreeKeyForBalance(stem) const nonceKey = this.getTreeKeyForNonce(stem) @@ -462,31 +517,42 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { )}` ) } + + if (!this._accountCacheSettings.deactivate) { + this._accountCache?.put(address, account) + } + return account } async putAccount(address: Address, account: Account): Promise { - const stem = getStem(address, 0) - const balanceKey = this.getTreeKeyForBalance(stem) - const nonceKey = this.getTreeKeyForNonce(stem) - const codeHashKey = this.getTreeKeyForCodeHash(stem) - - const balanceBuf = setLengthRight(bigIntToBytes(account.balance, true), 32) - const nonceBuf = setLengthRight(bigIntToBytes(account.nonce, true), 32) - - this._state[bytesToHex(balanceKey)] = bytesToHex(balanceBuf) - this._state[bytesToHex(nonceKey)] = bytesToHex(nonceBuf) - this._state[bytesToHex(codeHashKey)] = bytesToHex(account.codeHash) - if (this.DEBUG) { debug( - `putAccount address=${address.toString()} stem=${short(stem)} balance=${ - account.balance - } nonce=${account.nonce} codeHash=${short(account.codeHash)} storageHash=${short( - account.storageRoot - )}` + `putAccount address=${address.toString()} balance=${account.balance} nonce=${ + account.nonce + } codeHash=${short(account.codeHash)} storageHash=${short(account.storageRoot)}` ) } + + if (this._accountCacheSettings.deactivate) { + const stem = getStem(address, 0) + const balanceKey = this.getTreeKeyForBalance(stem) + const nonceKey = this.getTreeKeyForNonce(stem) + const codeHashKey = this.getTreeKeyForCodeHash(stem) + + const balanceBuf = setLengthRight(bigIntToBytes(account.balance, true), 32) + const nonceBuf = setLengthRight(bigIntToBytes(account.nonce, true), 32) + + this._state[bytesToHex(balanceKey)] = bytesToHex(balanceBuf) + this._state[bytesToHex(nonceKey)] = bytesToHex(nonceBuf) + this._state[bytesToHex(codeHashKey)] = bytesToHex(account.codeHash) + } else { + if (account !== undefined) { + this._accountCache!.put(address, account) + } else { + this._accountCache!.del(address) + } + } } /** @@ -502,7 +568,10 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } async modifyAccountFields(address: Address, accountFields: AccountFields): Promise { - const account = await this.getAccount(address) + let account = await this.getAccount(address) + if (!account) { + account = new Account() + } account.nonce = accountFields.nonce ?? account.nonce account.balance = accountFields.balance ?? account.balance @@ -584,7 +653,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // setup trie checkpointing this._accountCache?.revert() this._storageCache?.revert() - this._codeCache = {} + this._codeCache?.revert() } /** @@ -629,6 +698,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { */ clearCaches() { this._accountCache?.clear() + this._codeCache?.clear() this._storageCache?.clear() } From 0a3ae52c4b20b50c80b7e3cec40deced576ebe14 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 31 Dec 2023 01:02:56 +0530 Subject: [PATCH 28/75] modify poststate to use accesses from the accesswitness to compare and fix mising chunkKey in returned accesses --- packages/statemanager/src/accessWitness.ts | 9 ++++++--- .../src/statelessVerkleStateManager.ts | 19 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index e389db8901..48d607494f 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -60,7 +60,10 @@ type AccessedState = | { type: Exclude } | { type: AccessedStateType.Code; codeOffset: number } | { type: AccessedStateType.Storage; slot: bigint } -type AccessedStateWithAddress = AccessedState & { address: Address } +export type AccessedStateWithAddress = AccessedState & { + address: Address + chunkKey: PrefixedHexString +} export class AccessWitness { stems: Map @@ -321,9 +324,9 @@ export class AccessWitness { *accesses(): Generator { for (const rawAccess of this.rawAccesses()) { - const { address, treeIndex, chunkIndex } = rawAccess + const { address, treeIndex, chunkIndex, chunkKey } = rawAccess const accessedState = decodeAccessedState(treeIndex, chunkIndex) - yield { ...accessedState, address } + yield { ...accessedState, address, chunkKey } } } } diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 5e9d21c91a..99f3a4ddc1 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -33,6 +33,7 @@ import { import { AccountCache, CacheType, CodeCache, StorageCache } from './cache/index.js' import { OriginalStorageCache } from './cache/originalStorageCache.js' +import type { AccessedStateWithAddress } from './accessWitness.js' import type { DefaultStateManager } from './stateManager.js' import type { VerkleExecutionWitness } from '@ethereumjs/block' import type { @@ -617,21 +618,23 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } else if (accessedState.type === AccessedStateType.Storage) { extraMeta = `slot=${accessedState.slot}` } - debug(`block accesses: address=${address} type=${type} ${extraMeta}`) - } - for (const [key, canonicalValue] of Object.entries(this._postState)) { - const computedValue = this._state[key] - if (canonicalValue !== computedValue) { - debug( - `verifyPostState failed for key ${key}. Canonical value: ${canonicalValue}, computed value: ${computedValue}` - ) + const { chunkKey } = accessedState + const computedValue = this.getComputedValue(accessedState) + const canonicalValue = this._postState[chunkKey] + if (computedValue !== canonicalValue) { + debug(`block accesses: address=${address} type=${type} ${extraMeta}`) return false } } return true } + getComputedValue(accessedState: AccessedStateWithAddress): PrefixedHexString { + // dummy hack, ignore chunkKey and fetch actual value based on accessedState.type + return this._postState[accessedState.chunkKey] + } + /** * Checkpoints the current state of the StateManager instance. * State changes that follow can then be committed by calling From 79792867941821d2d48bc66624405648fac25173 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sat, 30 Dec 2023 17:36:45 -0500 Subject: [PATCH 29/75] stateManager: getComputedValue --- packages/statemanager/src/accessWitness.ts | 3 +- .../src/statelessVerkleStateManager.ts | 68 ++++++++++++++++++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 48d607494f..29382ff20b 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -37,7 +37,7 @@ type AccessEventFlags = { chunkFill: boolean } -// Since stem is predersen hashed, it is useful to maintain the reverse relationship +// Since stem is pedersen hashed, it is useful to maintain the reverse relationship type StemMeta = { address: Address; treeIndex: number } type RawAccessedState = { address: Address @@ -67,7 +67,6 @@ export type AccessedStateWithAddress = AccessedState & { export class AccessWitness { stems: Map - chunks: Map constructor( diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 99f3a4ddc1..5e953b3d08 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -365,8 +365,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { if (this.DEBUG) { debug(`putContractCode address=${address.toString()} value=${short(value)}`) } - this._codeCache?.put(address, value) + this._codeCache?.put(address, value) const codeHash = keccak256(value) if (KECCAK256_NULL === codeHash) { // If the code hash is the null hash, no code has to be stored @@ -631,8 +631,70 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } getComputedValue(accessedState: AccessedStateWithAddress): PrefixedHexString { - // dummy hack, ignore chunkKey and fetch actual value based on accessedState.type - return this._postState[accessedState.chunkKey] + const { address, type } = accessedState + switch (type) { + case AccessedStateType.Version: { + // Version is always 0 + // TODO: Update this when versioning is added to accounts + return '0x0000000000000000000000000000000000000000000000000000000000000000' + } + case AccessedStateType.Balance: { + const encodedAccount = this._accountCache?.get(address)?.accountRLP + if (encodedAccount === undefined) { + throw Error(`Account not found for address=${address.toString()}`) + } + const balanceBigint = Account.fromRlpSerializedAccount(encodedAccount).balance + return bytesToHex(setLengthRight(bigIntToBytes(balanceBigint, true), 32)) + } + + case AccessedStateType.Nonce: { + const encodedAccount = this._accountCache?.get(address)?.accountRLP + if (encodedAccount === undefined) { + throw Error(`Account not found for address=${address.toString()}`) + } + const nonceBigint = Account.fromRlpSerializedAccount(encodedAccount).nonce + return bytesToHex(setLengthRight(bigIntToBytes(nonceBigint, true), 32)) + } + + case AccessedStateType.CodeHash: { + const encodedAccount = this._accountCache?.get(address)?.accountRLP + if (encodedAccount === undefined) { + throw Error(`Account not found for address=${address.toString()}`) + } + return bytesToHex(Account.fromRlpSerializedAccount(encodedAccount).codeHash) + } + + case AccessedStateType.CodeSize: { + const codeSize = this._codeCache?.get(address)?.code?.length + if (codeSize === undefined) { + throw Error(`Code cache not found for address=${address.toString()}`) + } + + return bytesToHex(setLengthRight(bigIntToBytes(BigInt(codeSize), true), 32)) + } + + case AccessedStateType.Code: { + const { codeOffset } = accessedState + const code = this._codeCache?.get(address)?.code + if (code === undefined) { + throw Error(`Code cache not found for address=${address.toString()}`) + } + + const chunkSize = 32 + const codeChunkStart = codeOffset * chunkSize + + return bytesToHex(code.slice(codeChunkStart, codeChunkStart + chunkSize)) + } + + case AccessedStateType.Storage: { + const { slot } = accessedState + const storage = this._storageCache?.get(address, bigIntToBytes(slot)) + if (storage === undefined) { + throw Error(`Code cache not found for address=${address.toString()}`) + } + return bytesToHex(storage) + } + } } /** From 6b107525a1ddabbf3bed0d20e313ec63fd591978 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 2 Jan 2024 18:53:56 +0530 Subject: [PATCH 30/75] fixes for the getcomputedval fn helper for the code --- .../src/statelessVerkleStateManager.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 5e953b3d08..b4c64cf083 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -1,6 +1,7 @@ import { RLP } from '@ethereumjs/rlp' import { Account, + BIGINT_0, KECCAK256_NULL, KECCAK256_NULL_S, bigIntToBytes, @@ -667,7 +668,18 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { case AccessedStateType.CodeSize: { const codeSize = this._codeCache?.get(address)?.code?.length if (codeSize === undefined) { - throw Error(`Code cache not found for address=${address.toString()}`) + // it could be an EOA lets check for that + const encodedAccount = this._accountCache?.get(address)?.accountRLP + if (encodedAccount === undefined) { + throw Error(`Account not found for address=${address.toString()}`) + } + + const account = Account.fromRlpSerializedAccount(encodedAccount) + if (account.isContract()) { + throw Error(`Code cache not found for address=${address.toString()}`) + } else { + return bytesToHex(setLengthRight(bigIntToBytes(BIGINT_0, true), 32)) + } } return bytesToHex(setLengthRight(bigIntToBytes(BigInt(codeSize), true), 32)) @@ -681,9 +693,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } const chunkSize = 32 - const codeChunkStart = codeOffset * chunkSize - - return bytesToHex(code.slice(codeChunkStart, codeChunkStart + chunkSize)) + return bytesToHex(code.slice(codeOffset, codeOffset + chunkSize)) } case AccessedStateType.Storage: { From 626644e84dde60615f5f7bd829eee415f2bfa646 Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 4 Jan 2024 22:32:56 +0530 Subject: [PATCH 31/75] correctly implement the getcontractcode with partial accessed segments available and corresponding error handling in evm run --- packages/evm/src/interpreter.ts | 25 ++++++++++- .../src/statelessVerkleStateManager.ts | 44 ++++++++++++------- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index b7644d1683..c001d803a2 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -1,4 +1,5 @@ import { ConsensusAlgorithm } from '@ethereumjs/common' +import { StatelessVerkleStateManager } from '@ethereumjs/statemanager' import { Account, BIGINT_0, @@ -236,10 +237,30 @@ export class Interpreter { let doJumpAnalysis = true // Iterate through the given ops until something breaks or we hit STOP while (this._runState.programCounter < this._runState.code.length) { + const programCounter = this._runState.programCounter let opCode: number let opCodeObj: OpcodeMapEntry if (doJumpAnalysis) { - opCode = this._runState.code[this._runState.programCounter] + opCode = this._runState.code[programCounter] + + // if its an invalid opcode with verkle activated, then check if its because of a missing code + // chunk in the witness, and throw appropriate error to distinguish from an actual invalid opcod + if ( + opCode === 0xfe && + this.common.isActivatedEIP(6800) && + this._runState.stateManager instanceof StatelessVerkleStateManager + ) { + const contract = this._runState.interpreter.getAddress() + if ( + !(this._runState.stateManager as StatelessVerkleStateManager).checkChunkWitnessPresent( + contract, + programCounter + ) + ) { + throw Error(`Invalid witness with missing codeChunk for pc=${programCounter}`) + } + } + // Only run the jump destination analysis if `code` actually contains a JUMP/JUMPI/JUMPSUB opcode if (opCode === 0x56 || opCode === 0x57 || opCode === 0x5e) { const { jumps, pushes, opcodesCached } = this._getValidJumpDests(this._runState.code) @@ -250,7 +271,7 @@ export class Interpreter { doJumpAnalysis = false } } else { - opCodeObj = cachedOpcodes![this._runState.programCounter] + opCodeObj = cachedOpcodes![programCounter] opCode = opCodeObj.opcodeInfo.code } this._runState.opCode = opCode! diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index b4c64cf083..9084d5a3e9 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -18,7 +18,7 @@ import { import { getKey, getStem, verifyUpdate } from '@ethereumjs/verkle' import debugDefault from 'debug' import { keccak256 } from 'ethereum-cryptography/keccak.js' -import { concatBytes, equalsBytes } from 'ethereum-cryptography/utils' +import { equalsBytes } from 'ethereum-cryptography/utils' import { AccessWitness, @@ -345,6 +345,12 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { return getKey(getStem(address, treeIndex), toBytes(subIndex)) } + checkChunkWitnessPresent(address: Address, codeOffset: number) { + const chunkId = codeOffset / 31 + const chunkKey = bytesToHex(this.getTreeKeyForCodeChunk(address, chunkId)) + return this._state[chunkKey] !== undefined + } + /** * Copies the current instance of the `StateManager` * at the last fully committed point, i.e. as if all current @@ -409,22 +415,30 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // Get the contract code size const codeSizeKey = this.getTreeKeyForCodeSize(getStem(address, 0)) const codeSizeLE = hexToBytes(this._state[bytesToHex(codeSizeKey)] ?? '0x') - - // Calculate number of chunks - const chunks = Math.ceil(bytesToInt32(codeSizeLE, true) / 32) - - const retrievedChunks: Uint8Array[] = [] - - // Retrieve all code chunks - for (let chunkId = 0; chunkId < chunks; chunkId++) { - retrievedChunks.push(this.getTreeKeyForCodeChunk(address, chunkId)) + const codeSize = bytesToInt32(codeSizeLE, true) + // allocate the code and copy onto it from the available witness chunks + const accessedCode = new Uint8Array(codeSize) + + const chunks = Math.floor(bytesToInt32(codeSizeLE, true) / 31) + for (let chunkId = 0; chunkId <= chunks; chunkId++) { + const chunkKey = bytesToHex(this.getTreeKeyForCodeChunk(address, chunkId)) + const codeChunk = this._state[chunkKey] + const codeOffset = chunkId * 31 + + // if code chunk was accessed as per the provided witnesses copy it over + if (codeChunk !== undefined) { + // actual code starts from index 1 in chunk, 0th index is if there are any push data bytes + const actualChunk = hexToBytes(codeChunk).slice(1) + accessedCode.set(actualChunk, codeOffset) + } else { + // else fill this unaccessed segment with invalid opcode since the evm execution shouldn't + // end up here + accessedCode.fill(0xfe, codeOffset, 31) + } } - // Aggregate code chunks - const code = concatBytes(...retrievedChunks) - - // Return code chunks - return code + // Return accessedCode where only accessed code has been copied + return accessedCode } /** From 6c8b3f4a6c1c96d142b4e690b240bab7ba91bb4c Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Fri, 5 Jan 2024 15:40:17 -0500 Subject: [PATCH 32/75] statemanager: tentative fixes & improvements to code cache handling --- packages/statemanager/src/statelessVerkleStateManager.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 9084d5a3e9..01ae3226bd 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -577,6 +577,11 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { * @param address - Address of the account which should be deleted */ async deleteAccount(address: Address) { + if (this.DEBUG) { + debug(`Delete account ${address}`) + } + + this._codeCache?.del(address) this._accountCache!.del(address) if (!this._storageCacheSettings.deactivate) { @@ -739,6 +744,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { async commit(): Promise { this._checkpoints.pop() this._accountCache!.commit() + this._storageCache?.commit() + this._codeCache?.commit() } // TODO @@ -752,6 +759,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { */ async revert(): Promise { // setup trie checkpointing + this._checkpoints.pop() this._accountCache?.revert() this._storageCache?.revert() this._codeCache?.revert() From fabfba45ab285a002ae3ad78c931fbc24ce1f437 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Fri, 5 Jan 2024 15:44:35 -0500 Subject: [PATCH 33/75] statemanager: checkpoint code cache --- packages/statemanager/src/statelessVerkleStateManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 01ae3226bd..e620d950e8 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -735,6 +735,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { this._checkpoints.push(this._state) this._accountCache?.checkpoint() this._storageCache?.checkpoint() + this._codeCache?.checkpoint() } /** From 939cf9bc1a8f0ae0b1717c7b42fa5d6dac1512ff Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 13 Jan 2024 14:49:01 +0530 Subject: [PATCH 34/75] fix the code chunk comparision in post state verification --- .../src/statelessVerkleStateManager.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index e620d950e8..e30ba7ff90 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -640,8 +640,15 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } const { chunkKey } = accessedState - const computedValue = this.getComputedValue(accessedState) - const canonicalValue = this._postState[chunkKey] + let computedValue = this.getComputedValue(accessedState) + let canonicalValue = this._postState[chunkKey] + // if the access type is code, then we can't match the first byte because since the computed value + // doesn't has the first byte for push data since previous chunk code itself might not be available + if (accessedState.type === AccessedStateType.Code) { + computedValue = `0x${computedValue.slice(4)}` + canonicalValue = `0x${canonicalValue.slice(4)}` + } + if (computedValue !== canonicalValue) { debug(`block accesses: address=${address} type=${type} ${extraMeta}`) return false @@ -711,7 +718,10 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { throw Error(`Code cache not found for address=${address.toString()}`) } - const chunkSize = 32 + // we can only compare the actual code because to compare the first byte would + // be very tricky and impossible in certain scenarios like when the previous code chunk + // was not accessed and hence not even provided in the witness + const chunkSize = 31 return bytesToHex(code.slice(codeOffset, codeOffset + chunkSize)) } From 760822faef1baa5c187e1bf6dac0fb8199cec6cd Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 13 Jan 2024 15:08:06 +0530 Subject: [PATCH 35/75] rename kaustinen2 local testnet data for --- .../engine/{kaustinen2.spec.ts => kaustinen2-test.spec.ts} | 4 ++-- .../testdata/blocks/{kaustinen2.json => kaustinen2-test.json} | 0 .../geth-genesis/{kaustinen2.json => kaustinen2-test.json} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/client/test/rpc/engine/{kaustinen2.spec.ts => kaustinen2-test.spec.ts} (97%) rename packages/client/test/testdata/blocks/{kaustinen2.json => kaustinen2-test.json} (100%) rename packages/client/test/testdata/geth-genesis/{kaustinen2.json => kaustinen2-test.json} (100%) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2-test.spec.ts similarity index 97% rename from packages/client/test/rpc/engine/kaustinen2.spec.ts rename to packages/client/test/rpc/engine/kaustinen2-test.spec.ts index c488cf7585..ae68ded97d 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2-test.spec.ts @@ -4,8 +4,8 @@ import { bytesToHex } from '@ethereumjs/util' import * as td from 'testdouble' import { assert, describe, it } from 'vitest' -import blocks from '../../testdata/blocks/kaustinen2.json' -import genesisJSON from '../../testdata/geth-genesis/kaustinen2.json' +import blocks from '../../testdata/blocks/kaustinen2-test.json' +import genesisJSON from '../../testdata/geth-genesis/kaustinen2-test.json' import { baseRequest, params, setupChain } from '../helpers' import type { HttpServer } from 'jayson' diff --git a/packages/client/test/testdata/blocks/kaustinen2.json b/packages/client/test/testdata/blocks/kaustinen2-test.json similarity index 100% rename from packages/client/test/testdata/blocks/kaustinen2.json rename to packages/client/test/testdata/blocks/kaustinen2-test.json diff --git a/packages/client/test/testdata/geth-genesis/kaustinen2.json b/packages/client/test/testdata/geth-genesis/kaustinen2-test.json similarity index 100% rename from packages/client/test/testdata/geth-genesis/kaustinen2.json rename to packages/client/test/testdata/geth-genesis/kaustinen2-test.json From 4bf589ef035b3694d06f7c32ca387ef0489624a0 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 14 Jan 2024 01:09:30 +0530 Subject: [PATCH 36/75] fix pre and post state null chunks handling and corresponding get computed fixes --- packages/statemanager/src/accessWitness.ts | 8 +++ .../src/statelessVerkleStateManager.ts | 72 +++++++++++-------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 29382ff20b..e95eb9bc16 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -1,8 +1,12 @@ import { BIGINT_0, bytesToHex, toBytes } from '@ethereumjs/util' import { getKey, getStem } from '@ethereumjs/verkle' +import debugDefault from 'debug' import type { Address, PrefixedHexString } from '@ethereumjs/util' +const { debug: createDebugLogger } = debugDefault +const debug = createDebugLogger('statemanager:aw') + /** * Tree key constants. */ @@ -224,6 +228,10 @@ export class AccessWitness { gas += WitnessChunkFillCost } + debug( + `touchAddressAndChargeGas address=${address} treeIndex=${treeIndex} subIndex=${subIndex} isWrite=${isWrite} charges gas=${gas} for steamRead=${stemRead} stemWrite=${stemWrite} chunkRead=${chunkRead} chunkWrite=${chunkWrite} chunkFill=${chunkFill}` + ) + return gas } diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index e30ba7ff90..f76e43c6c2 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -1,7 +1,6 @@ import { RLP } from '@ethereumjs/rlp' import { Account, - BIGINT_0, KECCAK256_NULL, KECCAK256_NULL_S, bigIntToBytes, @@ -13,7 +12,6 @@ import { setLengthRight, short, toBytes, - zeros, } from '@ethereumjs/util' import { getKey, getStem, verifyUpdate } from '@ethereumjs/verkle' import debugDefault from 'debug' @@ -52,7 +50,7 @@ const { debug: createDebugLogger } = debugDefault const debug = createDebugLogger('statemanager:verkle') export interface VerkleState { - [key: PrefixedHexString]: PrefixedHexString + [key: PrefixedHexString]: PrefixedHexString | null } export interface EncodedVerkleProof { @@ -122,6 +120,8 @@ const PUSH1 = PUSH_OFFSET + 1 // eslint-disable-next-line @typescript-eslint/no-unused-vars const PUSH32 = PUSH_OFFSET + 32 +const ZEROVALUE = '0x0000000000000000000000000000000000000000000000000000000000000000' + /** * Stateless Verkle StateManager implementation for the VM. * @@ -255,17 +255,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const preStateRaw = executionWitness.stateDiff.flatMap(({ stem, suffixDiffs }) => { const suffixDiffPairs = suffixDiffs.map(({ currentValue, suffix }) => { const key = `${stem}${padToEven(suffix.toString(16))}` - - // TODO: Evaluate if we should store and handle null in a special way - // Currently we are replacing `null` with 0x00..00 (32 bytes) [expect for codeHash, suffix 3, where we use the empty codeHash] for simplifying handling and comparisons - // Also, test data has been inconsistent in this regard, so this simplifies things while things get more standardized - - if (Number(suffix) === 3) { - return { [key]: currentValue ?? KECCAK256_NULL_S } - } - return { - [key]: currentValue ?? bytesToHex(zeros(32)), + [key]: currentValue, } }) @@ -423,8 +414,14 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { for (let chunkId = 0; chunkId <= chunks; chunkId++) { const chunkKey = bytesToHex(this.getTreeKeyForCodeChunk(address, chunkId)) const codeChunk = this._state[chunkKey] - const codeOffset = chunkId * 31 + if (codeChunk === undefined) { + throw Error(`Invalid access to a missing code chunk with chunkKey=${chunkKey}`) + } + if (codeChunk === null) { + throw Error(`Invalid access to a non existent code chunk with chunkKey=${chunkKey}`) + } + const codeOffset = chunkId * 31 // if code chunk was accessed as per the provided witnesses copy it over if (codeChunk !== undefined) { // actual code starts from index 1 in chunk, 0th index is if there are any push data bytes @@ -511,13 +508,24 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } const stem = getStem(address, 0) + const versionKey = this.getTreeKeyForVersion(stem) + const versionChunk = this._state[bytesToHex(versionKey)] + if (versionChunk === undefined) { + throw Error(`Missing execution withness for address=${address} versionKey=${versionKey}`) + } + + // if the versionChunk is null it means the account doesn't exist in pre state + if (versionChunk === null) { + return undefined + } + const balanceKey = this.getTreeKeyForBalance(stem) const nonceKey = this.getTreeKeyForNonce(stem) const codeHashKey = this.getTreeKeyForCodeHash(stem) const balanceRaw = this._state[bytesToHex(balanceKey)] const nonceRaw = this._state[bytesToHex(nonceKey)] - const codeHash = this._state[bytesToHex(codeHashKey)] + const codeHash = this._state[bytesToHex(codeHashKey)] ?? KECCAK256_NULL_S const account = Account.fromAccountData({ balance: @@ -641,35 +649,43 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const { chunkKey } = accessedState let computedValue = this.getComputedValue(accessedState) - let canonicalValue = this._postState[chunkKey] + let canonicalValue: string | null = this._postState[chunkKey] ?? null // if the access type is code, then we can't match the first byte because since the computed value // doesn't has the first byte for push data since previous chunk code itself might not be available if (accessedState.type === AccessedStateType.Code) { - computedValue = `0x${computedValue.slice(4)}` - canonicalValue = `0x${canonicalValue.slice(4)}` + computedValue = computedValue !== null ? `0x${computedValue.slice(4)}` : null + canonicalValue = canonicalValue !== null ? `0x${canonicalValue.slice(4)}` : null } if (computedValue !== canonicalValue) { - debug(`block accesses: address=${address} type=${type} ${extraMeta}`) + debug( + `Block accesses mismatch: expected=${canonicalValue} computed=${computedValue} address=${address} type=${type} ${extraMeta} chunkKey=${chunkKey}` + ) + debug(`verifyPostState=false`) return false } } return true } - getComputedValue(accessedState: AccessedStateWithAddress): PrefixedHexString { + getComputedValue(accessedState: AccessedStateWithAddress): PrefixedHexString | null { const { address, type } = accessedState switch (type) { case AccessedStateType.Version: { + const encodedAccount = this._accountCache?.get(address)?.accountRLP + if (encodedAccount === undefined) { + return null + } // Version is always 0 // TODO: Update this when versioning is added to accounts - return '0x0000000000000000000000000000000000000000000000000000000000000000' + return ZEROVALUE } case AccessedStateType.Balance: { const encodedAccount = this._accountCache?.get(address)?.accountRLP if (encodedAccount === undefined) { - throw Error(`Account not found for address=${address.toString()}`) + return null } + const balanceBigint = Account.fromRlpSerializedAccount(encodedAccount).balance return bytesToHex(setLengthRight(bigIntToBytes(balanceBigint, true), 32)) } @@ -677,7 +693,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { case AccessedStateType.Nonce: { const encodedAccount = this._accountCache?.get(address)?.accountRLP if (encodedAccount === undefined) { - throw Error(`Account not found for address=${address.toString()}`) + return null } const nonceBigint = Account.fromRlpSerializedAccount(encodedAccount).nonce return bytesToHex(setLengthRight(bigIntToBytes(nonceBigint, true), 32)) @@ -686,7 +702,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { case AccessedStateType.CodeHash: { const encodedAccount = this._accountCache?.get(address)?.accountRLP if (encodedAccount === undefined) { - throw Error(`Account not found for address=${address.toString()}`) + return null } return bytesToHex(Account.fromRlpSerializedAccount(encodedAccount).codeHash) } @@ -697,14 +713,14 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // it could be an EOA lets check for that const encodedAccount = this._accountCache?.get(address)?.accountRLP if (encodedAccount === undefined) { - throw Error(`Account not found for address=${address.toString()}`) + return null } const account = Account.fromRlpSerializedAccount(encodedAccount) if (account.isContract()) { throw Error(`Code cache not found for address=${address.toString()}`) } else { - return bytesToHex(setLengthRight(bigIntToBytes(BIGINT_0, true), 32)) + return null } } @@ -715,7 +731,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const { codeOffset } = accessedState const code = this._codeCache?.get(address)?.code if (code === undefined) { - throw Error(`Code cache not found for address=${address.toString()}`) + return null } // we can only compare the actual code because to compare the first byte would @@ -729,7 +745,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const { slot } = accessedState const storage = this._storageCache?.get(address, bigIntToBytes(slot)) if (storage === undefined) { - throw Error(`Code cache not found for address=${address.toString()}`) + return null } return bytesToHex(storage) } From 7d001e6d0a2a497c99a2d9786b57750fed5aedd0 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 14 Jan 2024 18:48:42 +0530 Subject: [PATCH 37/75] setup the client to statelessly execute the verkle blocks randomly from anywhere the chain --- packages/client/src/blockchain/chain.ts | 12 ++++++ packages/client/src/execution/vmexecution.ts | 41 ++++++++++++++++--- packages/client/src/rpc/index.ts | 2 + packages/client/src/rpc/modules/engine.ts | 42 ++++++++++++++------ packages/client/test/rpc/helpers.ts | 3 +- 5 files changed, 81 insertions(+), 19 deletions(-) diff --git a/packages/client/src/blockchain/chain.ts b/packages/client/src/blockchain/chain.ts index b7119f70b6..f2b8c1a9ea 100644 --- a/packages/client/src/blockchain/chain.ts +++ b/packages/client/src/blockchain/chain.ts @@ -110,6 +110,12 @@ export interface ChainHeaders { height: bigint } +type BlockCache = { + remoteBlocks: Map + executedBlocks: Map + invalidBlocks: Map +} + /** * Blockchain * @memberof module:blockchain @@ -118,6 +124,7 @@ export class Chain { public config: Config public chainDB: DB public blockchain: Blockchain + public blockCache: BlockCache public _customGenesisState?: GenesisState public _customGenesisStateRoot?: Uint8Array @@ -177,6 +184,11 @@ export class Chain { protected constructor(options: ChainOptions) { this.config = options.config this.blockchain = options.blockchain! + this.blockCache = { + remoteBlocks: new Map(), + executedBlocks: new Map(), + invalidBlocks: new Map(), + } this.chainDB = this.blockchain.db this._customGenesisState = options.genesisState diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index ff7b6ff549..30bde0011b 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -328,7 +328,7 @@ export class VMExecution extends Execution { * @returns if the block was executed or not, throws on block execution failure */ async runWithoutSetHead( - opts: RunBlockOpts, + opts: RunBlockOpts & { parentBlock?: Block }, receipts?: TxReceipt[], blocking: boolean = false, skipBlockchain: boolean = false @@ -346,14 +346,24 @@ export class VMExecution extends Execution { this.running = true const { block, root } = opts - let vm = this.vm if (receipts === undefined) { // Check if we need to pass flag to clear statemanager cache or not const prevVMStateRoot = await this.vm.stateManager.getStateRoot() // If root is not provided its mean to be run on the same set state const parentState = root ?? prevVMStateRoot const clearCache = !equalsBytes(prevVMStateRoot, parentState) - const td = await this.chain.getTd(block.header.parentHash, block.header.number - BIGINT_1) + + // merge TTD might not give correct td, but its sufficient for purposes of determining HF and allows + // stateless execution where blockchain mightnot have all the blocks filling upto the block + let td + if (block.common.gteHardfork(Hardfork.Paris)) { + td = this.config.chainCommon.hardforkTTD(Hardfork.Paris) + if (td === null) { + throw Error(`Invalid null paris TTD for the chain`) + } + } else { + td = await this.chain.getTd(block.header.parentHash, block.header.number - BIGINT_1) + } const hardfork = this.config.execCommon.getHardforkBy({ blockNumber: block.header.number, @@ -361,12 +371,14 @@ export class VMExecution extends Execution { timestamp: block.header.timestamp, }) + let vm = this.vm if ( !this.config.execCommon.gteHardfork(Hardfork.Prague) && this.config.execCommon.hardforkGteHardfork(hardfork, Hardfork.Prague) ) { // see if this is a transition block - const parentBlock = await this.chain.getBlock(block.header.parentHash) + const parentBlock = + opts?.parentBlock ?? (await this.chain.getBlock(block.header.parentHash)) const parentTd = td - parentBlock.header.difficulty const parentHf = this.config.execCommon.getHardforkBy({ blockNumber: parentBlock.header.number, @@ -383,7 +395,26 @@ export class VMExecution extends Execution { vm = this.verkleVM } - const result = await vm.runBlock({ clearCache, ...opts }) + const needsStatelessExecution = vm.stateManager instanceof StatelessVerkleStateManager + if (needsStatelessExecution && block.executionWitness === undefined) { + throw Error(`Verkle blocks need executionWitness for stateless execution`) + } else { + const hasParentStateRoot = await vm.stateManager.hasStateRoot(parentState) + // we can also return false to say that the block wasn't executed but we should throw + // because we shouldn't have entered this function if this block wasn't executable + if (!hasParentStateRoot) { + throw Error(`Missing parent stateRoot for execution`) + } + } + + const skipHeaderValidation = + needsStatelessExecution && this.chain.headers.height < block.header.number - BIGINT_1 + // Also skip adding this block into blockchain for now + if (skipHeaderValidation) { + skipBlockchain = true + } + + const result = await vm.runBlock({ clearCache, ...opts, skipHeaderValidation }) receipts = result.receipts } if (receipts !== undefined) { diff --git a/packages/client/src/rpc/index.ts b/packages/client/src/rpc/index.ts index c3b4eeb068..3f226313f9 100644 --- a/packages/client/src/rpc/index.ts +++ b/packages/client/src/rpc/index.ts @@ -17,6 +17,7 @@ export const saveReceiptsMethods = ['getLogs', 'getTransactionReceipt', 'getTran export class RPCManager { private _config: Config private _client: EthereumClient + private _modules: Record = {} constructor(client: EthereumClient, config: Config) { this._config = config @@ -34,6 +35,7 @@ export class RPCManager { ) for (const modName of mods) { const mod = new (modules as any)[modName](this._client, rpcDebug) + this._modules[modName] = mod const rpcMethods = RPCManager.getMethodNames((modules as any)[modName]) for (const methodName of rpcMethods) { if (!this._config.saveReceipts && saveReceiptsMethods.includes(methodName)) { diff --git a/packages/client/src/rpc/modules/engine.ts b/packages/client/src/rpc/modules/engine.ts index 3cb31d1ad9..bb575fefe7 100644 --- a/packages/client/src/rpc/modules/engine.ts +++ b/packages/client/src/rpc/modules/engine.ts @@ -528,9 +528,10 @@ export class Engine { }) this.pendingBlock = new PendingBlock({ config: this.config, txPool: this.service.txPool }) - this.remoteBlocks = new Map() - this.executedBlocks = new Map() - this.invalidBlocks = new Map() + // refactor to move entire chainCache to chain itself including skeleton + this.remoteBlocks = this.chain.blockCache.remoteBlocks + this.executedBlocks = this.chain.blockCache.executedBlocks + this.invalidBlocks = this.chain.blockCache.invalidBlocks this.chainCache = { remoteBlocks: this.remoteBlocks, executedBlocks: this.executedBlocks, @@ -699,7 +700,6 @@ export class Engine { // we remove this block from invalidBlocks for it to be evaluated again against the // new data/corrections the CL might be calling newPayload with this.invalidBlocks.delete(blockHash.slice(2)) - // newpayloadv3 comes with parentBeaconBlockRoot out of the payload const { block: headBlock, error } = await assembleBlock( { @@ -959,7 +959,9 @@ export class Engine { } } - const vmHead = await this.chain.blockchain.getIteratorHead() + const vmHead = + this.chainCache.executedBlocks.get(parentHash.slice(2)) ?? + (await this.chain.blockchain.getIteratorHead()) let blocks: Block[] try { // find parents till vmHead but limit lookups till engineParentLookupMaxDepth @@ -976,6 +978,7 @@ export class Engine { for (const [i, block] of blocks.entries()) { lastBlock = block const bHash = block.hash() + const isBlockExecuted = (this.executedBlocks.get(bytesToUnprefixedHex(bHash)) ?? (await validExecutedChainBlock(bHash, this.chain))) !== null @@ -985,16 +988,29 @@ export class Engine { // i) if number of blocks pending to be executed are within limit // ii) Txs to execute in blocking call is within the supported limit // else return SYNCING/ACCEPTED and let skeleton led chain execution catch up - const executed = + const shouldExecuteBlock = blocks.length - i <= this.chain.config.engineNewpayloadMaxExecute && block.transactions.length <= this.chain.config.engineNewpayloadMaxTxsExecute - ? await this.execution.runWithoutSetHead({ - block, - root: (i > 0 ? blocks[i - 1] : await this.chain.getBlock(block.header.parentHash)) - .header.stateRoot, - setHardfork: this.chain.headers.td, - }) - : false + + const executed = + shouldExecuteBlock && + (await (async () => { + // just keeping its name different from the parentBlock to not confuse the context even + // though scope rules will not let it conflict with the parent of the new payload block + const blockParent = + i > 0 + ? blocks[i - 1] + : this.chainCache.remoteBlocks.get( + bytesToHex(block.header.parentHash).slice(2) + ) ?? (await this.chain.getBlock(block.header.parentHash)) + const blockExecuted = await this.execution.runWithoutSetHead({ + block, + root: blockParent.header.stateRoot, + setHardfork: this.chain.headers.td, + parentBlock: blockParent, + }) + return blockExecuted + })()) // if can't be executed then return syncing/accepted if (!executed) { diff --git a/packages/client/test/rpc/helpers.ts b/packages/client/test/rpc/helpers.ts index 088d9fae83..d77ff269b5 100644 --- a/packages/client/test/rpc/helpers.ts +++ b/packages/client/test/rpc/helpers.ts @@ -276,6 +276,7 @@ export async function setupChain(genesisFile: any, chainName = 'dev', clientOpts }) const manager = createManager(client) const engineMethods = clientOpts.engine === true ? manager.getMethods(true) : {} + const modules = manager['_modules'] const server = startRPC({ ...manager.getMethods(), ...engineMethods }) server.once('close', () => { client.config.events.emit(Event.CLIENT_SHUTDOWN) @@ -289,7 +290,7 @@ export async function setupChain(genesisFile: any, chainName = 'dev', clientOpts await skeleton?.open() await execution?.open() await chain.update() - return { chain, common, execution: execution!, server, service, blockchain } + return { chain, common, execution: execution!, server, service, blockchain, modules } } /** From cba04482ea31e83cee956a7c750704f61789472e Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 14 Jan 2024 18:55:09 +0530 Subject: [PATCH 38/75] setup to statelessly run block13 of kaustinen2 in client test spec for easy debugging --- .../client/test/rpc/engine/kaustinen2.spec.ts | 65 ++ .../test/testdata/blocks/kaustinen2.json | 464 ++++++++++ .../testdata/geth-genesis/kaustinen2.json | 856 ++++++++++++++++++ 3 files changed, 1385 insertions(+) create mode 100644 packages/client/test/rpc/engine/kaustinen2.spec.ts create mode 100644 packages/client/test/testdata/blocks/kaustinen2.json create mode 100644 packages/client/test/testdata/geth-genesis/kaustinen2.json diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts new file mode 100644 index 0000000000..8aae2f7a0f --- /dev/null +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -0,0 +1,65 @@ +import { Block, BlockHeader, executionPayloadFromBeaconPayload } from '@ethereumjs/block' +import { Hardfork } from '@ethereumjs/common' +import { bytesToHex } from '@ethereumjs/util' +import * as td from 'testdouble' +import { assert, describe, it } from 'vitest' + +import { Engine } from '../../../src/rpc/modules' +import blocks from '../../testdata/blocks/kaustinen2.json' +import genesisJSON from '../../testdata/geth-genesis/kaustinen2.json' +import { baseRequest, params, setupChain } from '../helpers' + +import type { Chain } from '../../../src/blockchain' +import type { Common } from '@ethereumjs/common' +import type { HttpServer } from 'jayson' +const genesisVerkleStateRoot = '0x5e8519756841faf0b2c28951c451b61a4b407b70a5ce5b57992f4bec973173ff' +const genesisVerkleBlockHash = '0x0884fa3d670543463f7e1d9ea007332e1f8a3564ecf891de95a76e751cde45d7' + +const originalValidate = (BlockHeader as any).prototype._consensusFormatValidation + +async function runBlock( + { chain, server, common }: { chain: Chain; server: HttpServer; common: Common }, + { execute, parent }: { execute: any; parent: any } +) { + const blockCache = chain.blockCache + + const parentPayload = executionPayloadFromBeaconPayload(parent as any) + const parentBlock = await Block.fromExecutionPayload(parentPayload, { common }) + blockCache.remoteBlocks.set(parentPayload.blockHash.slice(2), parentBlock) + blockCache.executedBlocks.set(parentPayload.blockHash.slice(2), parentBlock) + + const executePayload = executionPayloadFromBeaconPayload(execute as any) + const req = params('engine_newPayloadV2', [executePayload]) + const expectRes = (res: any) => { + console.log(res.body) + assert.equal(res.body.result.status, 'VALID') + } + + await baseRequest(server, req, 200, expectRes, false, false) +} + +describe(`valid verkle network setup`, async () => { + const { server, chain, common } = await setupChain(genesisJSON, 'post-merge', { + engine: true, + genesisStateRoot: genesisVerkleStateRoot, + }) + + it('genesis should be correctly setup', async () => { + const req = params('eth_getBlockByNumber', ['0x0', false]) + const expectRes = (res: any) => { + const block0 = res.body.result + assert.equal(block0.hash, genesisVerkleBlockHash) + assert.equal(block0.stateRoot, genesisVerkleStateRoot) + } + await baseRequest(server, req, 200, expectRes, false, false) + }) + + it('run block 13', async () => { + await runBlock({ common, chain, server }, blocks['block13']) + }) + + it(`reset TD`, () => { + BlockHeader.prototype['_consensusFormatValidation'] = originalValidate + td.reset() + }) +}) diff --git a/packages/client/test/testdata/blocks/kaustinen2.json b/packages/client/test/testdata/blocks/kaustinen2.json new file mode 100644 index 0000000000..2eeed68bce --- /dev/null +++ b/packages/client/test/testdata/blocks/kaustinen2.json @@ -0,0 +1,464 @@ +{ + "block13":{ + "parent": { + "parent_hash": "0xb3b593ec721b3210f1d95938e52b231d22520250f7a1df018559171e843eadf4", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x606482e583d5b8349862a43df0b2e0994d2c434b3099bb01fca5fe7a4f568dc6", + "receipts_root": "0x01838704d6c1bf710ca326f911dff2ea2c834eeba929a8a40c204f9458e85e9b", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0x46e5593823385005b51a99dc72f4c6d39a02c7d37c9430b2b671933d42624e8c", + "block_number": "12", + "gas_limit": "25294529", + "gas_used": "68600", + "timestamp": "1700826744", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "201417240", + "block_hash": "0x6386c5d6fdbdc1ea5a13c58816a75c4171c5fb7ccd9bdb4bc47efadf4b4572ef", + "transactions": [ + "0xf86d80847735940082f618946177843db3138ae69679a54b95cf345ed759450d870aa87bee5380008083021e7ca06f30db0d28ee7c5f6699558c034c5de92c005853979eb087b62c05fa3ba53674a043664c0bfa955aefdc495116e2b3a85c36d0572a8824e6f5a404b0103db57c84", + "0xf86d01847735940082f61894687704db07e902e9a8b3754031d168d46e3d586e870aa87bee5380008083021e7ca0919b9a7bd0f13fcb13bdb96e593d1428a9c18bdd45754f52bed87c5d05f0bc56a078c06c36bf82ef688b685217d60a49a1330c0a22937367823f4e2dc633a0dcbf" + ], + "withdrawals": [], + "execution_witness": { + "stateDiff": [ + { + "stem": "0x0e88cc6bf033a3ff779335e720d5a7edf907cc70ab7ff31375cd485db779fc", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x714a8e6f30f0dd821d0eb4064e1b3f96721f60a7fb8c369e36af3299259343", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x000000e83c80d09f3c2e3b030000000000000000000000000000000000000000", + "newValue": "0x00a015ae7cb2ba9f3c2e3b030000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0200000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0xc0509d4a37700000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xc484e43d783cf4f4eded1a8cee57e046e1ac2aaf6937ca4821263f0dbc759e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + } + ], + "verkleProof": { + "otherStems": [ + "0x8d1ed2380e53baf4d77bdb0adaeec334d72569de8e12d371ab2e4d6b131a37" + ], + "depthExtensionPresent": "0x080a0910", + "commitmentsByPath": [ + "0x00f2c2af75fb32d073540aa153d5dd3a87f7e24b62b3b266b0fcca7bbae77a56", + "0x0ef3fcb96d17a16ee996440fc5bedcb6a82b4ccf7b8b9243228b7bb422f5715b", + "0x12823635f1b4863990e04f17b699b018c8909455710ec2aed425d49d4af58db3", + "0x3c9781a5cc339c771889e698db5baa0766ec750ce7984b329d22b31e62c73bc8" + ], + "d": "0x713fedbc7b55ed57cd3e00407c58de3693106f5d5cd063d5d93284f85d5295c5", + "ipaProof": { + "cl": [ + "0x0e795ba5a3eb31ee1a46d6ef5add90393b7878ef6e13f8d55c52d739d7647315", + "0x47d7b0bec64833a49d2adcfe8f1eeb7ce72cf43d47698c1daf152c9f8ceea351", + "0x523b1ae8c1d9a661aa21280774c9328840487e0ba37594195369002ea1605616", + "0x513e2c28f6378762ec749cbf1efc5af8c9fcefcd2818549801a570d00d44b028", + "0x374317e49ec858921ac6d3330292abe29f149be850253a2e3054b13aeff3da72", + "0x3b14946677a76ae2c90612e597113d65651c4bebc0293a2b169a6139650ef0ca", + "0x59482b573a0dc417b7c820741624b39d9ed7b997656a8dedda08d6d27f86a31a", + "0x0de25f5cff572030d233a52bcb522084ecc4cc9e920ced2127f376ff43d8d5de" + ], + "cr": [ + "0x25096b5fe2377a1ab1184b96e6d15f76459df429e2126af404a35ac31f2a9f48", + "0x019c920847135329ee17ac5607282436b2acc28662d65739ef9c154c01f73db2", + "0x59dc47135eb2f4f8b92773098f1748ad292afbaa9773cc388c75bf1254604603", + "0x6c35d81dbc4c9d3d5fae567b89c2ffc97e19cb9150428a1148d86c1f2d71e5bb", + "0x19a1bb43a76fb302046d425e8505132ddb811fa1bc35c09afd120731badb8bec", + "0x4b4422ae2d34dba19305902d310e78c91a53c7a97f65a070fc3815c3b643cddd", + "0x0e0c25701c0bfb127869a899eff265b7a714fc74d8cb2c3c2fe4b1cf97fc7a4a", + "0x2895fa54cdf38af4fdfc8039776a80c3b41aa1c5e91664bed2fcbcfa8048ba74" + ], + "finalEvaluation": "0x110d669af3542b0a757b612ee6a83b6dd062b20579966fc7219986123753d259" + } + } + } + }, + "execute": { + "parent_hash": "0x6386c5d6fdbdc1ea5a13c58816a75c4171c5fb7ccd9bdb4bc47efadf4b4572ef", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x210abc6f9dcff7a2ec62a6fa2db8535f29f568808bd7524bd8c44e2d2974e2dc", + "receipts_root": "0x700c7a1c2e40e2db5fe254f6569a7c552550a409acd03d1cc01edeaf43af5d33", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0x2d7d94eeff14f06f999f789f6aa0df46702b59819d9ac235d12c51e83f3bb14c", + "block_number": "13", + "gas_limit": "25319229", + "gas_used": "265672", + "timestamp": "1700826756", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "176376649", + "block_hash": "0xa78a91c88cd47907df43c0ddb9918537fe4d5813ca512a1a64e84c086929fa7b", + "transactions": [ + "0xf8d48084479c2c18830186a08080b8806000602955bda3f9600060ca55600060695523b360006039551983576000601255b0620c2fde2c592ac2600060bc55e0ac6000606455a63e22600060e655eb607e605c5360a2605d5360c7605e53601d605f5360eb606053606b606153608e60625360816063536079606453601e60655360fc60665360b7606753608b60685383021e7ca0cc20c65a97d2e526b8ec0f4266e8b01bdcde43b9aeb59d8bfb44e8eb8119c109a07a8e751813ae1b2ce734960dbc39a4f954917d7822a2c5d1dca18b06c584131f", + "0xf8e80184479c2c18830186a094bbbbde4ca27f83fc18aa108170547ff57675936a80b8807ff71f7c15faadb969a76a5f54a81a0117e1e743cb7f24e378eda28442ea4c6eb6604a527fb5409e5718d44e23bfffac926e5ea726067f772772e7e19446acba0c853f62f5606a526020608a536088608b536039608c536004608d5360af608e537f7f7675d9f210e0a61564e6d11e7cd75f5bc9009ac9f6b94a0fc63035441a83021e7ba04a4a172d81ebb02847829b76a387ac09749c8b65668083699abe20c887fb9efca07c5b1a990702ec7b31a5e8e3935cd9a77649f8c25a84131229e24ab61aec6093", + "0xf8e88084479c2c18830186a0942971704d406f9efef2f4a36ea2a40aa994922fb980b88060006085557f27294f5823d67f9289e0ea8095a5e7b485dfeb4133b135289bbe8af566a7487e60bf527fafd2da24c3db7bda4a401ef7d082d1fa4838aa5e5bc75210c9f72ed3bb2b4cad60df527f1faf65fb727390a06a787d5ef5b133ce820f1c03ad92b0f0aeaa94e87a9040a060ff527fea706cb525a689beaa7e7a373cd383021e7ca05c739f5af4c9bfb267d90224315037decf8ab46495a5a7c87520b6251e5af145a0210ea5531840dad9add33043a25bf7deee741a5d8e8d7f8c3e75f4234bdaa6b4", + "0x02f8db83010f2c01843b9aca0084479c2c18830186a08080b88060006085553fad6000600a55600060565555600060b55506600060cf557f1b8b38183e7bd1bdfaa7123c5a4976e54cce0e42049d841411978fd3595e25c66019527f0538943712953cf08900aae40222a40b2d5a4ac8075ad8cf0870e2be307edbb96039527f9f3174ff85024747041ae7a611acffb987c513c088d90ab288aec080a0cd6ac65ce2cb0a912371f6b5a551ba8caffc22ec55ad4d3cb53de41d05eb77b6a02e0dfe8513dfa6ec7bfd7eda6f5c0dac21b39b982436045e128cec46cfd3f960" + ], + "withdrawals": [], + "execution_witness": { + "stateDiff": [ + { + "stem": "0x0e88cc6bf033a3ff779335e720d5a7edf907cc70ab7ff31375cd485db779fc", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000", + "newValue": "0xa0aa032656170a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0200000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x23bd889e5a78ce2fb3d29ceb3a36d69497bcf7b3c216e7125ca5d5ce294790", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x79db2ba96c1c76284c6de7df8726120ce5843d02512933d35433d9fe679f29", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "1", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0xc0509d4a37700000000000000000000000000000000000000000000000000000", + "newValue": "0x18da25c79d650100000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x90e0ff5f83020e6f64fa3e9db19a97ca99373f8204553fe7d8051c9c35cd20", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "1", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xb24fa84f214459af17d6e3f604811f252cac93146f02d67d7811bbcdfa448b", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + }, + { + "suffix": "105", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xbc322959718d4700b3027308591028d4243484689a34592a05e97f3846bdb2", + "suffixDiffs": [ + { + "suffix": "133", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xc484e43d783cf4f4eded1a8cee57e046e1ac2aaf6937ca4821263f0dbc759e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000", + "newValue": "0x0046912b9d190a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0200000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + } + ], + "verkleProof": { + "otherStems": [ + "0x23471509d9d1251c1973e2eedbc7d26993e60e1dd572f6249e64d8e5f7d745", + "0x79be86a6da481c33c8ef43775023d95adad9a6d4c09ed6f2d20872d5f0322f", + "0x904bf0eb393de0c997338bcbf0a0f3fc5122ab3da82578a82c99ca7c3f6134", + "0xb2a54bab47cec001dab58dfda9379489917383dbe713d291c21f2752e9cee9", + "0xbcf8664697bbd6ee5478fba5943c621670e34d0a62a33bab4f4c72e5b8cc40" + ], + "depthExtensionPresent": "0x0a09091209090912", + "commitmentsByPath": [ + "0x0d47eafd5ae38de78a583182e6f1d30a8477a9a15ca6a428e8a037c132f7edf8", + "0x53ad003f1bc1ee79305585df184aa0cf24fe37709265d1bb79f6446d664e3500", + "0x6b712b902561b52e411dd1d32903f0a2d48531f7b10a50efc122c94c480cd203", + "0x36bb4452636ef4e69f795b63676f614436f83562402828012d4a5206b752e348", + "0x0c661de2abfcdde2cfd4bac8a46de187be696a3655dd708311f1118a0b512039", + "0x405ddf0d482fd76ad47464681e7fc1f49a83f3bee9329bfec62e5a27842dbe72", + "0x2ff437900faf0b74dfc5a0efa2c7087980a768a9e5f71dd268ff0e5bfa8b4179", + "0x6c5d5f7c4c499c2769a1f5678ed3948d42c0d808d6699810b10f4c3d7bcc1011", + "0x24659128b664d9432ebfd4262709ac4d842da92ddd72517078096ef727e96cf0", + "0x49ad693fb3143cd565752634eeba317d11fb54399c682540d07adc945dda86c8", + "0x06aa19e28e6663a21c95f7f96574f59848d771436282068656866a79dcb18d30", + "0x1a1ade58c60a9b0dfb3f8eb3deb523bdbcd02d9a09b644dea611b8d3bc475201", + "0x53ad003f1bc1ee79305585df184aa0cf24fe37709265d1bb79f6446d664e3500" + ], + "d": "0x20bc4299bd9325f3b848b293fa66a5d077f12f514e5c207af54793821cf3c63f", + "ipaProof": { + "cl": [ + "0x32e6ff06fcd0c19e9272f4403aeb01b23a2415c140afe6228d67d3ec717d44ce", + "0x3d615b73f9a9848942e750a6caadfb3d8447601cec0e461cbc4c8be787f5ae9f", + "0x58ce67fa6b777db6bad66b0ad0312a9fcf5293a0225a5122e534ec09b78d27f9", + "0x12ce14a9e103f66fe9711f42fadeb2e5183c0585f90b758f7d17848f720c4c6f", + "0x2f7235fab59548e092f8f51bf5fe3120d7bc0e4053085077db220cb58e92145f", + "0x72adcd82a4a0dd17ad9dd7c71b55a4072e494ee66f62f70a5d3623bdfb5d0c76", + "0x00dfbffbbf2667c809405f2d83e64db68c55f9ecb15ccd462ed0958fd1a1bdb8", + "0x3095214ead498111168b106698c0e1ab2b7c74f7666c86b8fa1c129628d54559" + ], + "cr": [ + "0x190c9bf77b08fbcde51b9cccf76947103cb3370607ad3e171ab05f9f34077704", + "0x6966f8a08ea96ba1e90c8a670804a3417c2fbbd205dfd90b4d39fc3201389e53", + "0x0aa9502c13d73254d5a87f4460f8c7e759f1fd440921d048d861ed94e9f538a3", + "0x171c1cb6acc0f310f71c2b90b69872f88105c6e3dba0733296da9e21c387c0ed", + "0x58d3b516c7a0a7707f4dd10697f14d1b697c5cda1f6caadef1cd1131b0fd9d0a", + "0x5d84dc687446c694be2daab016f65c003aa2b40b541322d1fe37b81a306d913b", + "0x655959f19f6deccf6af6496b688988780480fdc82c6b43c3b2d0e7dd9d4894ee", + "0x52b7b7c301519634e5ffeb5f0f03011466b26bf0da716036e756b8566c66c984" + ], + "finalEvaluation": "0x010a5283b4c5db2caddd5517145452590a96ad3dcf8609cb8a213e19890fadba" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/client/test/testdata/geth-genesis/kaustinen2.json b/packages/client/test/testdata/geth-genesis/kaustinen2.json new file mode 100644 index 0000000000..26e17f1ea7 --- /dev/null +++ b/packages/client/test/testdata/geth-genesis/kaustinen2.json @@ -0,0 +1,856 @@ +{ + "config": { + "chainId": 69420, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeNetsplitBlock": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "shanghaiTime": 0, + "pragueTime": 0, + "proofInBlocks": true + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "0", + "nonce": "1", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b42620180004206555f3562018000420662018000015500" + }, + "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0x454b0EA7d8aD3C56D0CF2e44Ed97b2Feab4D7AF2": { + "balance": "1000000000000000000000000000" + }, + "0xd3248BA3E5492D767F8e427Cb9C7B9D5C3972D7B": { + "balance": "1000000000000000000000000000" + }, + "0xAD01b55d7c3448B8899862eb335FBb17075d8DE2": { + "balance": "1000000000000000000000000000" + }, + "0x7e454a14B8e7528465eeF86f0DC1da4f235d9D79": { + "balance": "1000000000000000000000000000" + }, + "0x7a40026A3b9A41754a95EeC8c92C6B99886f440C": { + "balance": "1000000000000000000000000000" + }, + "0x8c4D8CDD1f474510Dd70D66F2785a3a38a29AC1A": { + "balance": "1000000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x17D7840", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "1700825700" +} From f299ad6eeecbc5a5b6272467735c360b2c3ab133 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 14 Jan 2024 19:40:57 +0530 Subject: [PATCH 39/75] setup the client kaustinen2 stateless test to test and debug block 16 --- .../client/test/rpc/engine/kaustinen2.spec.ts | 14 +- .../test/testdata/blocks/kaustinen2.json | 474 ++++++++++++++++++ 2 files changed, 481 insertions(+), 7 deletions(-) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index 8aae2f7a0f..e21365a44e 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -1,10 +1,7 @@ import { Block, BlockHeader, executionPayloadFromBeaconPayload } from '@ethereumjs/block' -import { Hardfork } from '@ethereumjs/common' -import { bytesToHex } from '@ethereumjs/util' import * as td from 'testdouble' import { assert, describe, it } from 'vitest' -import { Engine } from '../../../src/rpc/modules' import blocks from '../../testdata/blocks/kaustinen2.json' import genesisJSON from '../../testdata/geth-genesis/kaustinen2.json' import { baseRequest, params, setupChain } from '../helpers' @@ -31,7 +28,6 @@ async function runBlock( const executePayload = executionPayloadFromBeaconPayload(execute as any) const req = params('engine_newPayloadV2', [executePayload]) const expectRes = (res: any) => { - console.log(res.body) assert.equal(res.body.result.status, 'VALID') } @@ -54,11 +50,15 @@ describe(`valid verkle network setup`, async () => { await baseRequest(server, req, 200, expectRes, false, false) }) - it('run block 13', async () => { - await runBlock({ common, chain, server }, blocks['block13']) - }) + const testCases = ['block13', 'block16'] + for (const testCase of testCases) { + it(`run ${testCase}`, async () => { + await runBlock({ common, chain, server }, blocks[testCase]) + }) + } it(`reset TD`, () => { + server.close() BlockHeader.prototype['_consensusFormatValidation'] = originalValidate td.reset() }) diff --git a/packages/client/test/testdata/blocks/kaustinen2.json b/packages/client/test/testdata/blocks/kaustinen2.json index 2eeed68bce..6ae73d837c 100644 --- a/packages/client/test/testdata/blocks/kaustinen2.json +++ b/packages/client/test/testdata/blocks/kaustinen2.json @@ -460,5 +460,479 @@ } } } + }, + "block16":{ + "parent":{ + "parent_hash": "0x47a219fe29fe617f09db8b1286ebe8b08dabf478d794d3b6785f30bad6b8b034", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x2c33cf556c7f8ce18be8cea11451e52c8b343a229a4ad2587cb68a29b072946e", + "receipts_root": "0x01838704d6c1bf710ca326f911dff2ea2c834eeba929a8a40c204f9458e85e9b", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0x873d5c1ac0b7d0642f5c58ed18fb608dfb715f8cf751a800d82ee25938332207", + "block_number": "15", + "gas_limit": "25368701", + "gas_used": "68600", + "timestamp": "1700826780", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "135443214", + "block_hash": "0xec63025d318947bb19e62592700bff413774f5f4221fdf5f43483d2d4f7282e2", + "transactions": [ + "0xf86d028444d4bb3482f618946177843db3138ae69679a54b95cf345ed759450d870aa87bee5380008083021e7ba0e64330f36313b81163b8bc48c840e43d3a774cd46775d45c04424a29e1f78a50a02d39e1b8265ea62723690c5e7a9015c63e7709afd4245ddc1788882f043d43ca", + "0xf86d038444d4bb3482f61894687704db07e902e9a8b3754031d168d46e3d586e870aa87bee5380008083021e7ca09dea07f682de2fc61184e4e0bf0fd891c9e3ddec2725bf08477dcfdb94e7cd63a078f9e003f043a648622a00e0afa5a7936e4122fe1525db918b21a93311f8aabf" + ], + "withdrawals": [], + "execution_witness": { + "stateDiff": [ + { + "stem": "0x0e88cc6bf033a3ff779335e720d5a7edf907cc70ab7ff31375cd485db779fc", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0xa0aa032656170a00000000000000000000000000000000000000000000000000", + "newValue": "0xa02a5714d2bf1400000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0200000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x714a8e6f30f0dd821d0eb4064e1b3f96721f60a7fb8c369e36af3299259343", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x00a015ae7cb2ba9f3c2e3b030000000000000000000000000000000000000000", + "newValue": "0xa0091a447819a59f3c2e3b030000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0200000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0400000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x18da25c79d650100000000000000000000000000000000000000000000000000", + "newValue": "0xe8609d0137a50100000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xc484e43d783cf4f4eded1a8cee57e046e1ac2aaf6937ca4821263f0dbc759e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x0046912b9d190a00000000000000000000000000000000000000000000000000", + "newValue": "0x00c6e41919c21400000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0200000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + } + ], + "verkleProof": { + "otherStems": [], + "depthExtensionPresent": "0x0a0a1212", + "commitmentsByPath": [ + "0x5603a57368e20f844ba39c07f248f107311813f5c7d784ca1b8c6f1707a807e1", + "0x03b3950d00ddf8f1a7afe8020d0d36ad603c07e3e2f4a8dd52d122e4aaf97b0e", + "0x24bdcae89e2acb2600fc2f1c30446b5c35708a77185630cd57db1dddf8f0ddd1", + "0x23e225ae7ff1a8091e2bd6539115804cf2927e6c7436209b08500cb95dd11f97", + "0x0ed1be7d2c75d2f20c1c9ee786c061a88e4139b12ad567e7f534582442f4cd8d", + "0x478be8a594d782203b23f6f3df41bbfba386b6ef9c2e13068c492b34494da982", + "0x2eb439eac25dd825ed1c635911169f55814bbe114aa637707202936657efd9e2", + "0x62c688201c059d8dc0a1116dd8c45fd7f913e2916b04f8ab8bf2d6dccf9e11c1", + "0x20fa6b9abaa5495f93f73663eb0b0e6cde904cf7cba9805d5897a8fcd32feca8", + "0x3f77671099e4fc77b876a9efd70702322a78e383f7be7f5a3a0070bee7f82215" + ], + "d": "0x10a9521c74405a2a1349b91bbced62ac4ecaf9ea2aa22890e617033885aa5263", + "ipaProof": { + "cl": [ + "0x427d7847c6894cba934a1fdbe532ca1889c5bf63c5b24f8bd5b7823715860208", + "0x0bddbf3506325b98b49e20b4ffea5cfd473368db16ae75adf164b756fb8de074", + "0x6eb0a722ee99549be2bc97fc7b680fb9b3d3b5b43b0dd5fb5c6f1029f78970fa", + "0x00cdad16ec490caf84640f2ef28ba041347c892d91b443e7071c74db2de65616", + "0x1f3c285aa1499fb1311ae15aa251e8dc361ce463608ae40f503f7c85a0f0dca6", + "0x01df1c7956959e6bdf7b3aa9a3c1ed426243550b37a69f03e14a91d6d93306c5", + "0x060f63e3876ae051950bfd3b8e8aba27e1281bdd42a79d2d6cbf8f33677ec58d", + "0x5a066a1398507ed53a3a5a0eee762c036a11077eceab59dedb2ea7b5c00e853b" + ], + "cr": [ + "0x10ae504fed413daeeb9ee4e6146a97d16dd94aba446469ed48e15dda1a2f2d19", + "0x17e44b5b892e26f704da8dac3711b718cbc32bb2a3c94f4cd008d3bf572afc1e", + "0x0feada5bba4c4bb94377c98b0efdc92610670f5dfd583b8ee6159c08e07c84bb", + "0x115da42bb0bcc3ad240236ef2b21d946aef9c021d8cea79837d4ef33438b0753", + "0x02c9c6027fd57ed07c156e5aaef14319ab24a288be9a5176c66d7faabb452292", + "0x335f361ce3a09fb7e6e0825793213f6408ca0730a7fd21c5b736af730f80c9c3", + "0x521413d784ceaa57e9501f3e7b9333cd9753488922f85840e81eb450b4e6496b", + "0x71486494610e4ea5bdf73f2c31afb3cb7f204f9157fa712545488a662afc620a" + ], + "finalEvaluation": "0x1c956765b64cabd68cff50dbced479c1e2cac9375f24295b6cdcd6faa821052c" + } + } + } + }, + "execute":{ + "parent_hash": "0xec63025d318947bb19e62592700bff413774f5f4221fdf5f43483d2d4f7282e2", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x23da55eeb85eb25e41ef77cf90f48cc233ca61dbd358ea4eb18e948f1a1eb8aa", + "receipts_root": "0xe0fe1a45471cde0fc7fe7dc68dcf471c7ef1e2bc8830a1af447ed482dfdb8496", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0x64cb9d0e90916a35257e03799e8fe7b2fe9c57728c588a8c5c5f450a38108610", + "block_number": "16", + "gas_limit": "25393474", + "gas_used": "304213", + "timestamp": "1700826792", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "118604376", + "block_hash": "0x6b23fe9fdac2e5567300399465a3c865d99d1b776e0021544f87fd55c3102206", + "transactions": [ + "0xf8d4028443ad7d0e830186a08080b880637f6712f26b46d9af33fcbf777792e5fb8b4720632885c4cb6fa8e6672d075ccb06600d527f674a29362187f210c8cbe74d8b8e66305f2bf71c8712135ede6758c0c3c3173b602d527fe512799a5ce5d25b806c4bc17c11e4cf4af5e337c995baf62ca27ecccdca3457604d527fd00c13c9c1275fd3e9c3e275f59b9ae87c4983021e7ba009c22644a7771a0cfb7985a16d65a131b95ab30892b95d94766ac3f2166de19ba04e0b8189fcfd77d7b0bfbffeefe7c276d6a74008b8ea5d214e322df248e842ea", + "0x01f8d683010f2c028443ad7d0e830186a08080b880b00e7fa3c849dce891cce5fae8a4c46cbb313d6aec0c0ffe7863e05fb7b22d4807674c6055527ffbfcb0938f3e18f7937aa8fa95d880afebd5c4cec0d85186095832d03c85cf8a60755260ab60955360cf6096536066609753606e60985360fa609953609e609a53608e609b536024609c5360f6609d536072609e5360a4609fc080a08fc6f7101f292ff1fb0de8ac69c2d320fbb23bfe61cf327173786ea5daee6e37a044c42d91838ef06646294bf4f9835588aee66243b16a66a2da37641fae4c045f", + "0xf8e8038443ad7d0e830186a0947d6d36747b8ea52262e49b74bb9f87caa8daca6280b8806000603755246000601455600060f1553c366000605b557f75ef0f16a0868b2c405a9362ef681bfc366b9dd99b958e51d577ecca0a76721c60b6527f3d5d33647b161dc9e71615d1998c9a3af9766f97713c94d164df2c2b696c202760d6527fe95abb8c9fc1c1fd326c3449dc470e13c098d5fe60a4cc120c72c9d41873a95c83021e7ca0bf6aa963791f11ef2129d722ab5bf0d00a85f25531ed9ec426b933b10978a1faa039651aaf90292ca0635f599f72ac7a073dc65645a2cdea7f0b0c34e91291243a", + "0x02f8db83010f2c03843b9aca008443ad7d0e830186a08080b8807faaf3e276bfe110e442190ef16d739b8055e9e211cee47504dabfb7d7663914c160af527f4b7418198af143733d1893086fd71782d8ae52f9bc7c7dfa8e8cedef9d4470b160cf527fb193983dea2a9d3fafdfd40d8e21a3876a136835585ed2ad36ac31ffce7c1eef60ef527fa7490cdb9efb515f429a3872e7c9b22b9eb6e6c001a0cd82cec9c75f3ece7920fb2f03bd6b52cbc0283906cb821d594f6db0d8c0e4efa0629894b5f4c8bb657939b9be2e503a866e9ae04559d4601ea2b85aa9f1d45001" + ], + "withdrawals": [], + "execution_witness": { + "stateDiff": [ + { + "stem": "0x0e88cc6bf033a3ff779335e720d5a7edf907cc70ab7ff31375cd485db779fc", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0xa02a5714d2bf1400000000000000000000000000000000000000000000000000", + "newValue": "0xa8cddb4be60f1400000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0200000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0400000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x538469dc3579eaab593b006fd639cc3e684d89d72c47e146af14de3bc1d8d6", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + }, + { + "suffix": "128", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0xe8609d0137a50100000000000000000000000000000000000000000000000000", + "newValue": "0x28f57ad475bd0200000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x944dd4f046fcf7d15be20d96506c27132625d36427c461925c3fcdde266f1e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "1", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xc484e43d783cf4f4eded1a8cee57e046e1ac2aaf6937ca4821263f0dbc759e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x00c6e41919c21400000000000000000000000000000000000000000000000000", + "newValue": "0x80a7bc4cf5381400000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0200000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0400000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xe6dcb23b706bef86b024138db380c183135ec13b256b3c5df2ef89f502ef74", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": null + }, + { + "suffix": "2", + "currentValue": null, + "newValue": null + }, + { + "suffix": "3", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xe9ae7df7c4873b986de83662c728236fb51a4b65a17c2cff179417305f30cb", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + }, + { + "suffix": "128", + "currentValue": null, + "newValue": null + }, + { + "suffix": "129", + "currentValue": null, + "newValue": null + }, + { + "suffix": "130", + "currentValue": null, + "newValue": null + }, + { + "suffix": "131", + "currentValue": null, + "newValue": null + }, + { + "suffix": "132", + "currentValue": null, + "newValue": null + } + ] + } + ], + "verkleProof": { + "otherStems": [ + "0x9444524c2261a7086dd332bb05d79b1c63e74913a97b7b85c680368b19db0e" + ], + "depthExtensionPresent": "0x0a101209120808", + "commitmentsByPath": [ + "0x1ba24c38c9aff43cf2793ed22a2fdd04282d558bcfad33589b5e4697c0662e45", + "0x0de9b2e4fb439b894823a068a74e69d51b53163df509614239b95efd1c8251df", + "0x5788aad2dc6a6395d1850740f0cf2c566d31dddc6a1c168113a242d5d380e1ac", + "0x0fa21597f7807a78df4d0025d94afa9d544fad74bae7e9fabe9a5dd96eae7905", + "0x1473a7ba8fa6c910e3a59fb1746484cf0f3eef394567c57b68cfefd75e0a4628", + "0x402c1868e1aaba747dc0e00c3cb1cf39340d9cc90a34429da67fa1702fe48604", + "0x1334eccc70ec78c896cbe5c99aa5dc90ab230bc02586512fbf7459ef54346821", + "0x0574898a568127f92d0a5f8a2ca4fbf0a3db39e060d41b490049840e60666a9b", + "0x708fb101a8e1323a8dbe02501a54ed40ab78ca37f3c018f793d853126f159d86", + "0x6480d4463d8547240aac907548e430a939d5ad90ee44ae5f968ddb4037e8a578" + ], + "d": "0x4b7e78004d063f6418f4ea02498b0ea211eedc482a4fd49f05735403be907a6e", + "ipaProof": { + "cl": [ + "0x39e9dc9695f1534fb6e883de9e4a1e8e1ec3bef91ad51ffcfb72e41898010558", + "0x099be66677ffd008a86e3ba05ffb70fe1535886424303b1ed1324180fe41f12a", + "0x6cabb149cdc43240b2398dad37febf662329f9af953e463f9662a72f6971adf1", + "0x2cea63f2b132ed167454aa229d726399edab0263b90370a9d149b2f3220c2833", + "0x08dd76bfdaec231d4732af246e4ae4b656fbf92b032d3471729e11328b6d1a08", + "0x09e5f57d3e792c63d4800bbdf8ab0a102845cab98db81cfd0e79c8dce3747f3e", + "0x4dfe893891819830dec0fb7eea2cb783fd9210607c886fa16d0484c68b45e1c7", + "0x07e212a298f21a9adcc9b42925351f76260ec60166c413802369128bc6d9b8d2" + ], + "cr": [ + "0x5aba75dd90c208635d6fbbd003fc7766a04ff7410095012d71be2105df3b958a", + "0x6bf90b634ef36282fcab11c69c0e805cbb229bdde70374da3a2bdc90c9dfb777", + "0x2959f7dc3e707358b348a6500711f8d4982ba7045bbbb98f683280459828665b", + "0x6a6a545af490bc817f05991c5bf3baf68e6e57f15c941cac1b9d830ab7494871", + "0x315ad7dd1ea1739a0449a7c55ea9d03ffa63b42983475e66b77bc911587a7605", + "0x2442064885b7b419109d3acc55959ff71e28ca5f4964311cbc84d4a1fd150310", + "0x67c63669a994760c4184050b8e4782b988c1387865fa09a60000e1ab35a13caa", + "0x61ae59caee9d1365905b30486ac582c93a8e21d94477fe684bb0aeeaeb691bec" + ], + "finalEvaluation": "0x02a346441c5cc6ae6e5c1300494434b0d4f20ab0a8179971631be9e4147589fc" + } + } + } + } } } \ No newline at end of file From 5d24fa82be06ac0fd4482f5db74a60dcddc39a8d Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 14 Jan 2024 21:21:01 +0530 Subject: [PATCH 40/75] improve the post state witness mismatch logging to be more comprehensible for debugging --- .../client/test/rpc/engine/kaustinen2.spec.ts | 8 ++++++- packages/statemanager/src/accessWitness.ts | 24 ++++++++++++++++++- .../src/statelessVerkleStateManager.ts | 17 ++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index e21365a44e..e358e70da2 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -50,7 +50,13 @@ describe(`valid verkle network setup`, async () => { await baseRequest(server, req, 200, expectRes, false, false) }) - const testCases = ['block13', 'block16'] + // currently it seems the the blocks can't be played one after another as it seems + // to not do clean init of the statemanager. this isn't a problem in sequential + // execution, but need to be fixed up in the stateless random execution + const testCases = [ + // 'block13', + 'block16', + ] for (const testCase of testCases) { it(`run ${testCase}`, async () => { await runBlock({ common, chain, server }, blocks[testCase]) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index e95eb9bc16..c24f98cd23 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -1,4 +1,4 @@ -import { BIGINT_0, bytesToHex, toBytes } from '@ethereumjs/util' +import { BIGINT_0, bytesToBigInt, bytesToHex, hexToBytes, toBytes } from '@ethereumjs/util' import { getKey, getStem } from '@ethereumjs/verkle' import debugDefault from 'debug' @@ -395,3 +395,25 @@ export function decodeAccessedState(treeIndex: number, chunkIndex: number): Acce } } } + +export function decodeValue(type: AccessedStateType, value: string | null): string { + if (value === null) { + return '' + } + + switch (type) { + case AccessedStateType.Version: + case AccessedStateType.Balance: + case AccessedStateType.Nonce: + case AccessedStateType.CodeSize: { + const decodedValue = bytesToBigInt(hexToBytes(value), true) + return `${decodedValue}` + } + + case AccessedStateType.CodeHash: + case AccessedStateType.Code: + case AccessedStateType.Storage: { + return value + } + } +} diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index f76e43c6c2..4a6a062897 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -26,6 +26,7 @@ import { CODE_SIZE_LEAF_KEY, NONCE_LEAF_KEY, VERSION_LEAF_KEY, + decodeValue, getTreeIndexesForStorageSlot, getTreeIndicesForCodeChunk, } from './accessWitness.js' @@ -658,9 +659,23 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } if (computedValue !== canonicalValue) { + const decodedComputedValue = decodeValue(accessedState.type, computedValue) + const decodedCanonicalValue = decodeValue(accessedState.type, canonicalValue) + + const displayComputedValue = + computedValue === decodedComputedValue + ? computedValue + : `${computedValue} (${decodedComputedValue})` + const displayCanonicalValue = + canonicalValue === decodedCanonicalValue + ? canonicalValue + : `${canonicalValue} (${decodedCanonicalValue})` + debug( - `Block accesses mismatch: expected=${canonicalValue} computed=${computedValue} address=${address} type=${type} ${extraMeta} chunkKey=${chunkKey}` + `Block accesses mismatch address=${address} type=${type} ${extraMeta} chunkKey=${chunkKey}` ) + debug(`expected=${displayCanonicalValue}`) + debug(`computed=${displayComputedValue}`) debug(`verifyPostState=false`) return false } From d4eb8e64eebf3680a7e559547f942bd4753d9f85 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 16 Jan 2024 22:12:44 +0530 Subject: [PATCH 41/75] improve chunk verification tracking logging and fix post/prestate key coding from the witnesses --- packages/statemanager/src/accessWitness.ts | 7 +++++-- .../src/statelessVerkleStateManager.ts | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index c24f98cd23..36ab9f414e 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -5,7 +5,7 @@ import debugDefault from 'debug' import type { Address, PrefixedHexString } from '@ethereumjs/util' const { debug: createDebugLogger } = debugDefault -const debug = createDebugLogger('statemanager:aw') +const debug = createDebugLogger('statemanager:verkle:aw') /** * Tree key constants. @@ -229,7 +229,7 @@ export class AccessWitness { } debug( - `touchAddressAndChargeGas address=${address} treeIndex=${treeIndex} subIndex=${subIndex} isWrite=${isWrite} charges gas=${gas} for steamRead=${stemRead} stemWrite=${stemWrite} chunkRead=${chunkRead} chunkWrite=${chunkWrite} chunkFill=${chunkFill}` + `touchAddressAndChargeGas=${gas} address=${address} treeIndex=${treeIndex} subIndex=${subIndex}` ) return gas @@ -281,6 +281,9 @@ export class AccessWitness { } } + debug( + `${accessedChunkKeyHex}: isWrite=${isWrite} for steamRead=${stemRead} stemWrite=${stemWrite} chunkRead=${chunkRead} chunkWrite=${chunkWrite} chunkFill=${chunkFill}` + ) return { stemRead, stemWrite, chunkRead, chunkWrite, chunkFill } } diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 4a6a062897..9ab2fc2159 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -255,7 +255,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // Populate the pre-state and post-state from the executionWitness const preStateRaw = executionWitness.stateDiff.flatMap(({ stem, suffixDiffs }) => { const suffixDiffPairs = suffixDiffs.map(({ currentValue, suffix }) => { - const key = `${stem}${padToEven(suffix.toString(16))}` + const key = `${stem}${padToEven(Number(suffix).toString(16))}` return { [key]: currentValue, } @@ -273,7 +273,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const postStateRaw = executionWitness.stateDiff.flatMap(({ stem, suffixDiffs }) => { const suffixDiffPairs = suffixDiffs.map(({ newValue, suffix }) => { - const key = `${stem}${padToEven(suffix.toString(16))}` + const key = `${stem}${padToEven(Number(suffix).toString(16))}` // A postState value of null means there was no change from the preState. // In this implementation, we therefore replace null with the preState. const value = newValue ?? this._state[key] @@ -639,6 +639,10 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // Verifies that the witness post-state matches the computed post-state verifyPostState(): boolean { + // track what all chunks were accessed so as to compare in the end if any chunks were missed + // in access while comparising against the provided poststate in the execution witness + const accessedChunks = new Map() + for (const accessedState of this.accessWitness!.accesses()) { const { address, type } = accessedState let extraMeta = '' @@ -649,6 +653,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } const { chunkKey } = accessedState + accessedChunks.set(chunkKey, true) let computedValue = this.getComputedValue(accessedState) let canonicalValue: string | null = this._postState[chunkKey] ?? null // if the access type is code, then we can't match the first byte because since the computed value @@ -680,6 +685,15 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { return false } } + + for (const canChunkKey of Object.keys(this._postState)) { + if (accessedChunks.get(canChunkKey) === undefined) { + debug(`Missing chunk access for canChunkKey=${canChunkKey}`) + debug(`verifyPostState=false`) + return false + } + } + debug(`verifyPostState=true`) return true } From 3b714fab9a1c73f0cb67702d465503adb0da2248 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 16 Jan 2024 22:19:36 +0530 Subject: [PATCH 42/75] debug and fix code accesses and overhaul/fix accesscharges on create/call --- packages/evm/src/evm.ts | 170 +++++++++++++------------- packages/evm/src/interpreter.ts | 21 ++-- packages/evm/src/opcodes/functions.ts | 4 +- 3 files changed, 95 insertions(+), 100 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 9a20d306ec..8cfe68bfae 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -222,28 +222,22 @@ export class EVM implements EVMInterface { } protected async _executeCall(message: MessageWithTo): Promise { - let accessGasUsed = BIGINT_0 + let gasLimit = message.gasLimit + if (this.common.isActivatedEIP(6800)) { if (message.depth === 0) { const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas( message.authcallOrigin ?? message.caller ) - accessGasUsed += originAccessGas - message.gasLimit -= originAccessGas - if (message.gasLimit < BIGINT_0) { - // remove this negative amount from accessGasUsed to get the real gas used and set - // gasLimit back to zero and throw OOG - accessGasUsed += message.gasLimit - message.gasLimit = BIGINT_0 + gasLimit -= originAccessGas + if (gasLimit < BIGINT_0) { if (this.DEBUG) { - debugGas( - `Origin access charged(${originAccessGas}) caused OOG (-> ${message.gasLimit})` - ) + debugGas(`Origin access charged(${originAccessGas}) caused OOG (-> ${gasLimit})`) } - return { execResult: OOGResult(accessGasUsed) } + return { execResult: OOGResult(message.gasLimit) } } else { if (this.DEBUG) { - debugGas(`Origin access used (${originAccessGas} gas (-> ${message.gasLimit}))`) + debugGas(`Origin access used (${originAccessGas} gas (-> ${gasLimit}))`) } } } @@ -269,22 +263,15 @@ export class EVM implements EVMInterface { const destAccessGas = message.accessWitness!.touchTxExistingAndComputeGas(message.to, { sendsValue, }) - accessGasUsed += destAccessGas - message.gasLimit -= destAccessGas - if (message.gasLimit < BIGINT_0) { - // remove this negative amount from accessGasUsed to get the real gas used and set - // gasLimit back to zero and throw OOG - accessGasUsed += message.gasLimit - message.gasLimit = BIGINT_0 + gasLimit -= destAccessGas + if (gasLimit < BIGINT_0) { if (this.DEBUG) { - debugGas( - `Destination access charged(${destAccessGas}) caused OOG (-> ${message.gasLimit})` - ) + debugGas(`Destination access charged(${destAccessGas}) caused OOG (-> ${gasLimit})`) } - return { execResult: OOGResult(accessGasUsed) } + return { execResult: OOGResult(message.gasLimit) } } else { if (this.DEBUG) { - debugGas(`Destination access used (${destAccessGas} gas (-> ${message.gasLimit}))`) + debugGas(`Destination access used (${destAccessGas} gas (-> ${gasLimit}))`) } } } @@ -297,24 +284,17 @@ export class EVM implements EVMInterface { const absenceProofAccessGas = message.accessWitness!.touchAndChargeProofOfAbsence( message.to ) - accessGasUsed += absenceProofAccessGas - message.gasLimit -= accessGasUsed - if (message.gasLimit < BIGINT_0) { - // remove this negative amount from accessGasUsed to get the real gas used and set - // gasLimit back to zero and throw OOG - accessGasUsed += message.gasLimit - message.gasLimit = BIGINT_0 + gasLimit -= absenceProofAccessGas + if (gasLimit < BIGINT_0) { if (this.DEBUG) { debugGas( - `Proof of absense access charged(${absenceProofAccessGas}) caused OOG (-> ${message.gasLimit})` + `Proof of absense access charged(${absenceProofAccessGas}) caused OOG (-> ${gasLimit})` ) } - return { execResult: OOGResult(accessGasUsed) } + return { execResult: OOGResult(message.gasLimit) } } else { if (this.DEBUG) { - debugGas( - `Proof of absense access used (${absenceProofAccessGas} gas (-> ${message.gasLimit}))` - ) + debugGas(`Proof of absense access used (${absenceProofAccessGas} gas (-> ${gasLimit}))`) } } } @@ -348,7 +328,7 @@ export class EVM implements EVMInterface { return { execResult: { gasRefund: message.gasRefund, - executionGasUsed: accessGasUsed, + executionGasUsed: message.gasLimit - gasLimit, exceptionError: errorMessage, // Only defined if addToBalance failed returnValue: new Uint8Array(0), }, @@ -365,11 +345,7 @@ export class EVM implements EVMInterface { target = getPrecompileName(target) ?? target.slice(20) timer = this.performanceLogger.startTimer(target) } - result = await this.runPrecompile( - message.code as PrecompileFunc, - message.data, - message.gasLimit - ) + result = await this.runPrecompile(message.code as PrecompileFunc, message.data, gasLimit) if (this._optsCached.profiler?.enabled === true) { this.performanceLogger.stopTimer(timer!, Number(result.executionGasUsed), 'precompiles') @@ -379,14 +355,14 @@ export class EVM implements EVMInterface { if (this.DEBUG) { debug(`Start bytecode processing...`) } - result = await this.runInterpreter(message) + result = await this.runInterpreter({ ...message, gasLimit } as Message) } if (message.depth === 0) { this.postMessageCleanup() } - result.executionGasUsed += accessGasUsed + result.executionGasUsed += message.gasLimit - gasLimit return { execResult: result, @@ -394,22 +370,16 @@ export class EVM implements EVMInterface { } protected async _executeCreate(message: Message): Promise { - let accessGasUsed = BIGINT_0 let gasLimit = message.gasLimit if (this.common.isActivatedEIP(6800)) { const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas(message.caller) - accessGasUsed += originAccessGas gasLimit -= originAccessGas if (gasLimit < BIGINT_0) { - // remove this negative amount from accessGasUsed to get the real gas used and set - // gasLimit back to zero and throw OOG - accessGasUsed += message.gasLimit - gasLimit = BIGINT_0 if (this.DEBUG) { debugGas(`Origin access charged(${originAccessGas}) caused OOG (-> ${gasLimit})`) } - return { execResult: OOGResult(accessGasUsed) } + return { execResult: OOGResult(message.gasLimit) } } else { if (this.DEBUG) { debugGas(`Origin access used (${originAccessGas} gas (-> ${gasLimit}))`) @@ -444,49 +414,66 @@ export class EVM implements EVMInterface { message.data = new Uint8Array(0) message.to = await this._generateAddress(message) + if (this.common.isActivatedEIP(6780)) { + message.createdAddresses!.add(message.to.toString()) + } + + if (this.DEBUG) { + debug(`Generated CREATE contract address ${message.to}`) + } + let toAccount = await this.stateManager.getAccount(message.to) + if (!toAccount) { + if (this.common.isActivatedEIP(6800)) { + const absenceProofAccessGas = message.accessWitness!.touchAndChargeProofOfAbsence( + message.to + ) + gasLimit -= absenceProofAccessGas + if (gasLimit < BIGINT_0) { + if (this.DEBUG) { + debugGas( + `Proof of absense access charged(${absenceProofAccessGas}) caused OOG (-> ${gasLimit})` + ) + } + return { execResult: OOGResult(message.gasLimit) } + } else { + if (this.DEBUG) { + debugGas(`Proof of absense access used (${absenceProofAccessGas} gas (-> ${gasLimit}))`) + } + } + } + + toAccount = new Account() + } + if (this.common.isActivatedEIP(6800)) { const sendsValue = message.value !== BIGINT_0 const contractCreateAccessGas = message.accessWitness!.touchAndChargeContractCreateInit( message.to, { sendsValue } ) - accessGasUsed += contractCreateAccessGas gasLimit -= contractCreateAccessGas if (gasLimit < BIGINT_0) { - // remove this negative amount from accessGasUsed to get the real gas used and set - // gasLimit back to zero and throw OOG - accessGasUsed += message.gasLimit - gasLimit = BIGINT_0 if (this.DEBUG) { - debugGas(`Origin access charged(${contractCreateAccessGas}) caused OOG (-> ${gasLimit})`) + debugGas( + `Contract create (sendsValue=${sendsValue}) charge(${contractCreateAccessGas}) caused OOG (-> ${gasLimit})` + ) } return { execResult: OOGResult(message.gasLimit) } } else { if (this.DEBUG) { - debugGas(`Origin access used (${contractCreateAccessGas} gas (-> ${gasLimit}))`) + debugGas( + `Contract create (sendsValue=${sendsValue}) charged (${contractCreateAccessGas} gas (-> ${gasLimit}))` + ) } } } - if (this.common.isActivatedEIP(6780)) { - message.createdAddresses!.add(message.to.toString()) - } - - if (this.DEBUG) { - debug(`Generated CREATE contract address ${message.to}`) - } - let toAccount = await this.stateManager.getAccount(message.to) - if (!toAccount) { - toAccount = new Account() - } - // Check for collision if ( (toAccount.nonce && toAccount.nonce > BIGINT_0) || !(equalsBytes(toAccount.codeHash, KECCAK256_NULL) === true) ) { if (this.DEBUG) { - accessGasUsed debug(`Returning on address collision`) } return { @@ -546,8 +533,7 @@ export class EVM implements EVMInterface { return { createdAddress: message.to, execResult: { - // Query? is there any gas used here i.e. accessGasUsed ? - executionGasUsed: BIGINT_0, + executionGasUsed: message.gasLimit - gasLimit, gasRefund: message.gasRefund, exceptionError: errorMessage, // only defined if addToBalance failed returnValue: new Uint8Array(0), @@ -561,7 +547,7 @@ export class EVM implements EVMInterface { // run the message with the updated gas limit and add accessed gas used to the result let result = await this.runInterpreter({ ...message, gasLimit } as Message) - result.executionGasUsed += accessGasUsed + result.executionGasUsed += message.gasLimit - gasLimit // fee for size of the return value let totalGas = result.executionGasUsed @@ -574,7 +560,6 @@ export class EVM implements EVMInterface { debugGas(`Add return value size fee (${returnFee} to gas used (-> ${totalGas}))`) } } - gasLimit = message.gasLimit - totalGas // Check for SpuriousDragon EIP-170 code size limit let allowedCodeSize = true @@ -654,28 +639,37 @@ export class EVM implements EVMInterface { } } - // Save code if a new contract was created - if ( - !result.exceptionError && - result.returnValue !== undefined && - result.returnValue.length !== 0 - ) { + // get the fresh gas limit for the rest of the ops + gasLimit = message.gasLimit - result.executionGasUsed + if (!result.exceptionError && this.common.isActivatedEIP(6800)) { const createCompleteAccessGas = message.accessWitness!.touchAndChargeContractCreateCompleted( message.to ) gasLimit -= createCompleteAccessGas if (gasLimit < BIGINT_0) { if (this.DEBUG) { - debug(`Contract create access (${createCompleteAccessGas}) caused OOG (-> ${gasLimit})`) + debug( + `ContractCreateComplete access gas (${createCompleteAccessGas}) caused OOG (-> ${gasLimit})` + ) } result = { ...result, ...OOGResult(message.gasLimit) } } else { - debug(`Contract create access used (${createCompleteAccessGas}) gas (-> ${gasLimit})`) + debug( + `ContractCreateComplete access used (${createCompleteAccessGas}) gas (-> ${gasLimit})` + ) result.executionGasUsed += createCompleteAccessGas - await this.stateManager.putContractCode(message.to, result.returnValue) - if (this.DEBUG) { - debug(`Code saved on new contract creation`) - } + } + } + + // Save code if a new contract was created + if ( + !result.exceptionError && + result.returnValue !== undefined && + result.returnValue.length !== 0 + ) { + await this.stateManager.putContractCode(message.to, result.returnValue) + if (this.DEBUG) { + debug(`Code saved on new contract creation`) } } else if (CodestoreOOG) { // This only happens at Frontier. But, let's do a sanity check; diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index c001d803a2..d4051fcc4b 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -319,6 +319,17 @@ export class Interpreter { // It needs the base fee, for correct gas limit calculation for the CALL opcodes gas = await opEntry.gasHandler(this._runState, gas, this.common) } + if (this.common.isActivatedEIP(6800)) { + const contract = this._runState.interpreter.getAddress() + const statelessGas = + this._runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( + contract, + this._runState.programCounter, + this._runState.programCounter + ) + gas += statelessGas + debugGas(`codechunk accessed statelessGas=${statelessGas} (-> ${gas})`) + } if (this._evm.events.listenerCount('step') > 0 || this._evm.DEBUG) { // Only run this stepHook function if there is an event listener (e.g. test runner) @@ -331,16 +342,6 @@ export class Interpreter { throw new EvmError(ERROR.INVALID_OPCODE) } - if (this.common.isActivatedEIP(6800)) { - const contract = this._runState.interpreter.getAddress() - const statelessGas = - this._runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( - contract, - this._runState.programCounter, - this._runState.programCounter - ) - gas += statelessGas - } // Reduce opcode's base fee this.useGas(gas, opInfo) diff --git a/packages/evm/src/opcodes/functions.ts b/packages/evm/src/opcodes/functions.ts index d100d8d65c..5cd413c9e9 100644 --- a/packages/evm/src/opcodes/functions.ts +++ b/packages/evm/src/opcodes/functions.ts @@ -913,8 +913,8 @@ export const handlers: Map = new Map([ if (common.isActivatedEIP(6800)) { const contract = runState.interpreter.getAddress() - const startOffset = Math.min(runState.code.length, runState.programCounter - numToPush + 1) - const endOffset = Math.min(runState.code.length, startOffset + numToPush) + const startOffset = Math.min(runState.code.length, runState.programCounter + 1) + const endOffset = Math.min(runState.code.length, startOffset + numToPush - 1) const statelessGas = runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( contract, startOffset, From ba54f16c8e8ff30240d932fb47824184894f6d71 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 16 Jan 2024 22:26:52 +0530 Subject: [PATCH 43/75] add a more complete matching of generated and provided executed witnesses --- .../src/statelessVerkleStateManager.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 9ab2fc2159..ccb36e78fb 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -642,6 +642,8 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { // track what all chunks were accessed so as to compare in the end if any chunks were missed // in access while comparising against the provided poststate in the execution witness const accessedChunks = new Map() + // switch to false if postVerify fails + let postVerified = true for (const accessedState of this.accessWitness!.accesses()) { const { address, type } = accessedState @@ -655,7 +657,16 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { const { chunkKey } = accessedState accessedChunks.set(chunkKey, true) let computedValue = this.getComputedValue(accessedState) - let canonicalValue: string | null = this._postState[chunkKey] ?? null + let canonicalValue: string | null | undefined = this._postState[chunkKey] + + if (canonicalValue === undefined) { + debug( + `Block accesses missing in canonical address=${address} type=${type} ${extraMeta} chunkKey=${chunkKey}` + ) + postVerified = false + continue + } + // if the access type is code, then we can't match the first byte because since the computed value // doesn't has the first byte for push data since previous chunk code itself might not be available if (accessedState.type === AccessedStateType.Code) { @@ -681,19 +692,18 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { ) debug(`expected=${displayCanonicalValue}`) debug(`computed=${displayComputedValue}`) - debug(`verifyPostState=false`) - return false + postVerified = false } } for (const canChunkKey of Object.keys(this._postState)) { if (accessedChunks.get(canChunkKey) === undefined) { debug(`Missing chunk access for canChunkKey=${canChunkKey}`) - debug(`verifyPostState=false`) - return false + postVerified = false } } - debug(`verifyPostState=true`) + + debug(`verifyPostState=${postVerified}`) return true } From 9ac950de5e4e4e4f187c9aa3d37385ff959eb9c7 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 16 Jan 2024 22:34:53 +0530 Subject: [PATCH 44/75] fix return --- packages/statemanager/src/statelessVerkleStateManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index ccb36e78fb..9162a26351 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -704,7 +704,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } debug(`verifyPostState=${postVerified}`) - return true + return postVerified } getComputedValue(accessedState: AccessedStateWithAddress): PrefixedHexString | null { From e2e5330286b6badb23013a0933e2ba58eb6d2748 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 16 Jan 2024 22:56:49 +0530 Subject: [PATCH 45/75] debug, discuss and remove proof of absence charges for contract create for fixing the extra witnesses --- packages/evm/src/evm.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 8cfe68bfae..57c6782e82 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -423,25 +423,6 @@ export class EVM implements EVMInterface { } let toAccount = await this.stateManager.getAccount(message.to) if (!toAccount) { - if (this.common.isActivatedEIP(6800)) { - const absenceProofAccessGas = message.accessWitness!.touchAndChargeProofOfAbsence( - message.to - ) - gasLimit -= absenceProofAccessGas - if (gasLimit < BIGINT_0) { - if (this.DEBUG) { - debugGas( - `Proof of absense access charged(${absenceProofAccessGas}) caused OOG (-> ${gasLimit})` - ) - } - return { execResult: OOGResult(message.gasLimit) } - } else { - if (this.DEBUG) { - debugGas(`Proof of absense access used (${absenceProofAccessGas} gas (-> ${gasLimit}))`) - } - } - } - toAccount = new Account() } From 66bef47e2ea7a136d48186a4aab01183975050e4 Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 18 Jan 2024 22:09:22 +0530 Subject: [PATCH 46/75] only charge code accesses if accessed from state and when code is written on contract creation --- packages/evm/src/evm.ts | 26 ++++++++++++++++++++++ packages/evm/src/interpreter.ts | 3 ++- packages/evm/src/opcodes/functions.ts | 2 +- packages/statemanager/src/accessWitness.ts | 9 ++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 57c6782e82..1e935e3b99 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -648,6 +648,30 @@ export class EVM implements EVMInterface { result.returnValue !== undefined && result.returnValue.length !== 0 ) { + // Add access charges for writing this code to the state + if (this.common.isActivatedEIP(6800)) { + const byteCodeWriteAccessfee = + message.accessWitness!.touchCodeChunksRangeOnWriteAndChargeGas( + message.to, + 0, + message.code!.length - 1 + ) + gasLimit -= byteCodeWriteAccessfee + if (gasLimit < BIGINT_0) { + if (this.DEBUG) { + debug( + `byteCodeWrite access gas (${byteCodeWriteAccessfee}) caused OOG (-> ${gasLimit})` + ) + } + result = { ...result, ...OOGResult(message.gasLimit) } + } else { + debug( + `ContractCreateComplete access used (${byteCodeWriteAccessfee}) gas (-> ${gasLimit})` + ) + result.executionGasUsed += byteCodeWriteAccessfee + } + } + await this.stateManager.putContractCode(message.to, result.returnValue) if (this.DEBUG) { debug(`Code saved on new contract creation`) @@ -697,6 +721,7 @@ export class EVM implements EVMInterface { codeAddress: message.codeAddress, gasRefund: message.gasRefund, containerCode: message.containerCode, + chargeCodeAccesses: message.chargeCodeAccesses, blobVersionedHashes: message.blobVersionedHashes ?? [], accessWitness: message.accessWitness, createdAddresses: message.createdAddresses, @@ -961,6 +986,7 @@ export class EVM implements EVMInterface { } else { message.containerCode = await this.stateManager.getContractCode(message.codeAddress) message.isCompiled = false + message.chargeCodeAccesses = true if (this.common.isActivatedEIP(3540)) { message.code = getEOFCode(message.containerCode) } else { diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index d4051fcc4b..88db4e6c74 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -70,6 +70,7 @@ export interface Env { blobVersionedHashes: Uint8Array[] /** Versioned hashes for blob transactions */ createdAddresses?: Set accessWitness?: AccessWitness + chargeCodeAccesses?: boolean } export interface RunState { @@ -319,7 +320,7 @@ export class Interpreter { // It needs the base fee, for correct gas limit calculation for the CALL opcodes gas = await opEntry.gasHandler(this._runState, gas, this.common) } - if (this.common.isActivatedEIP(6800)) { + if (this.common.isActivatedEIP(6800) && this._env.chargeCodeAccesses === true) { const contract = this._runState.interpreter.getAddress() const statelessGas = this._runState.env.accessWitness!.touchCodeChunksRangeOnReadAndChargeGas( diff --git a/packages/evm/src/opcodes/functions.ts b/packages/evm/src/opcodes/functions.ts index 5cd413c9e9..8f05ed8be5 100644 --- a/packages/evm/src/opcodes/functions.ts +++ b/packages/evm/src/opcodes/functions.ts @@ -911,7 +911,7 @@ export const handlers: Map = new Map([ trap(ERROR.OUT_OF_RANGE) } - if (common.isActivatedEIP(6800)) { + if (common.isActivatedEIP(6800) && runState.env.chargeCodeAccesses === true) { const contract = runState.interpreter.getAddress() const startOffset = Math.min(runState.code.length, runState.programCounter + 1) const endOffset = Math.min(runState.code.length, startOffset + numToPush - 1) diff --git a/packages/statemanager/src/accessWitness.ts b/packages/statemanager/src/accessWitness.ts index 36ab9f414e..a59a20e47a 100644 --- a/packages/statemanager/src/accessWitness.ts +++ b/packages/statemanager/src/accessWitness.ts @@ -180,6 +180,15 @@ export class AccessWitness { return gas } + touchCodeChunksRangeOnWriteAndChargeGas(contact: Address, startPc: number, endPc: number) { + let gas = BIGINT_0 + for (let chunkNum = Math.floor(startPc / 31); chunkNum <= Math.floor(endPc / 31); chunkNum++) { + const { treeIndex, subIndex } = getTreeIndicesForCodeChunk(chunkNum) + gas += this.touchAddressOnWriteAndComputeGas(contact, treeIndex, subIndex) + } + return gas + } + touchAddressOnWriteAndComputeGas( address: Address, treeIndex: number, From ec52976dfaa41eae6d4ea59d99a7d219de8e0116 Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 19 Jan 2024 22:25:06 +0530 Subject: [PATCH 47/75] handle bigint treeIndex for the bigint slot and debug/match the predersenhash with kauntinen2 usage --- packages/evm/src/message.ts | 1 + packages/evm/src/opcodes/gas.ts | 4 +- packages/statemanager/src/accessWitness.ts | 46 ++++++++++--------- .../src/statelessVerkleStateManager.ts | 6 +-- packages/verkle/src/util/crypto.ts | 11 +++-- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/packages/evm/src/message.ts b/packages/evm/src/message.ts index f1eeee0a92..51fa560d23 100644 --- a/packages/evm/src/message.ts +++ b/packages/evm/src/message.ts @@ -54,6 +54,7 @@ export class Message { isCompiled: boolean salt?: Uint8Array containerCode?: Uint8Array /** container code for EOF1 contracts - used by CODECOPY/CODESIZE */ + chargeCodeAccesses?: boolean /** * Set of addresses to selfdestruct. Key is the unprefixed address. */ diff --git a/packages/evm/src/opcodes/gas.ts b/packages/evm/src/opcodes/gas.ts index 0109908cd0..d1b5ce399d 100644 --- a/packages/evm/src/opcodes/gas.ts +++ b/packages/evm/src/opcodes/gas.ts @@ -253,7 +253,7 @@ export const dynamicGasHandlers: Map= HEADER_STORAGE_OFFSET && position < CODE_OFFSET) { - const slot = BigInt(position - HEADER_STORAGE_OFFSET) + const slot = position - BigInt(HEADER_STORAGE_OFFSET) return { type: AccessedStateType.Storage, slot } } else if (position >= CODE_OFFSET && position < MAIN_STORAGE_OFFSET) { - const codeChunkIdx = position - CODE_OFFSET + const codeChunkIdx = Number(position) - CODE_OFFSET return { type: AccessedStateType.Code, codeOffset: codeChunkIdx * 31 } } else if (position >= MAIN_STORAGE_OFFSET) { const slot = BigInt(position - MAIN_STORAGE_OFFSET) diff --git a/packages/statemanager/src/statelessVerkleStateManager.ts b/packages/statemanager/src/statelessVerkleStateManager.ts index 9162a26351..7bffdcd610 100644 --- a/packages/statemanager/src/statelessVerkleStateManager.ts +++ b/packages/statemanager/src/statelessVerkleStateManager.ts @@ -331,7 +331,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { throw new Error('Not implemented') } - getTreeKeyForStorageSlot(address: Address, storageKey: number) { + getTreeKeyForStorageSlot(address: Address, storageKey: bigint) { const { treeIndex, subIndex } = getTreeIndexesForStorageSlot(storageKey) return getKey(getStem(address, treeIndex), toBytes(subIndex)) @@ -456,7 +456,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { } } - const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) + const storageKey = this.getTreeKeyForStorageSlot(address, BigInt(bytesToHex(key))) const storageValue = toBytes(this._state[bytesToHex(storageKey)]) if (!this._storageCacheSettings.deactivate) { @@ -479,7 +479,7 @@ export class StatelessVerkleStateManager implements EVMStateManagerInterface { this._storageCache!.put(address, key, encodedValue) } else { // TODO: Consider refactoring this in a writeContractStorage function? Like in stateManager.ts - const storageKey = this.getTreeKeyForStorageSlot(address, Number(bytesToHex(key))) + const storageKey = this.getTreeKeyForStorageSlot(address, BigInt(bytesToHex(key))) this._state[bytesToHex(storageKey)] = bytesToHex(setLengthRight(value, 32)) } } diff --git a/packages/verkle/src/util/crypto.ts b/packages/verkle/src/util/crypto.ts index a2b6ce31e0..ca5aa03b63 100644 --- a/packages/verkle/src/util/crypto.ts +++ b/packages/verkle/src/util/crypto.ts @@ -1,5 +1,6 @@ import { type Address, + bigIntToBytes, bytesToHex, concatBytes, int32ToBytes, @@ -39,13 +40,17 @@ export function verifyUpdate( * @param treeIndex The index of the tree to generate the key for. Defaults to 0. * @return The 31-bytes verkle tree stem as a Uint8Array. */ -export function getStem(address: Address, treeIndex: number = 0): Uint8Array { +export function getStem(address: Address, treeIndex: number | bigint = 0): Uint8Array { const address32 = setLengthLeft(address.toBytes(), 32) - const treeIndexBytes = setLengthRight(int32ToBytes(treeIndex, true), 32) + let treeIndexBytes: Uint8Array + if (typeof treeIndex === 'number') { + treeIndexBytes = setLengthRight(int32ToBytes(Number(treeIndex), true), 32) + } else { + treeIndexBytes = setLengthRight(bigIntToBytes(BigInt(treeIndex), true).slice(0, 32), 32) + } const input = concatBytes(address32, treeIndexBytes) - const treeStem = pedersenHash(input).slice(0, 31) return treeStem From 5a51cb86d8fea6766b1b866e0cfad177b78f3cef Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sat, 20 Jan 2024 16:59:05 -0500 Subject: [PATCH 48/75] client: fix kaustinen tests and migrate to new testing framework --- package-lock.json | 3 ++ .../test/rpc/engine/kaustinen2-test.spec.ts | 38 +++++++------------ .../client/test/rpc/engine/kaustinen2.spec.ts | 17 ++++----- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index b51e3737ae..805620277f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16033,6 +16033,9 @@ "bin": { "rlp": "bin/rlp.cjs" }, + "devDependencies": { + "benchmark": "^2.1.4" + }, "engines": { "node": ">=18" } diff --git a/packages/client/test/rpc/engine/kaustinen2-test.spec.ts b/packages/client/test/rpc/engine/kaustinen2-test.spec.ts index ae68ded97d..acab675e59 100644 --- a/packages/client/test/rpc/engine/kaustinen2-test.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2-test.spec.ts @@ -1,14 +1,13 @@ -import { Block, BlockHeader, executionPayloadFromBeaconPayload } from '@ethereumjs/block' +import { Block, executionPayloadFromBeaconPayload } from '@ethereumjs/block' import { Common, Hardfork } from '@ethereumjs/common' import { bytesToHex } from '@ethereumjs/util' -import * as td from 'testdouble' import { assert, describe, it } from 'vitest' import blocks from '../../testdata/blocks/kaustinen2-test.json' import genesisJSON from '../../testdata/geth-genesis/kaustinen2-test.json' -import { baseRequest, params, setupChain } from '../helpers' +import { getRpcClient, setupChain } from '../helpers' -import type { HttpServer } from 'jayson' +import type { HttpClient } from 'jayson/promise' // this verkle genesis stateroot and blockhash of the local generated kaustinen2 network const genesisVerkleStateRoot = '0x30d24fe15e1281600a15328add431b906597d83cf33d23050627c51936bb0d1a' @@ -40,16 +39,12 @@ const merkleGenesisJsonBlock = { withdrawals: [], } -const originalValidate = (BlockHeader as any).prototype._consensusFormatValidation - -export const batchBlocks = async (server: HttpServer) => { +export const batchBlocks = async (rpc: HttpClient) => { for (let i = 0; i < blocks.length; i++) { const executionPayload = executionPayloadFromBeaconPayload(blocks[i] as any) - const req = params('engine_newPayloadV2', [executionPayload]) - const expectRes = (res: any) => { - assert.equal(res.body.result.status, 'VALID') - } - await baseRequest(server, req, 200, expectRes, false, false) + + const res = await rpc.request('engine_newPayloadV2', [executionPayload]) + assert.equal(res.result.status, 'VALID', 'valid status should be received') } } @@ -94,22 +89,15 @@ describe(`valid verkle network setup`, async () => { genesisStateRoot: genesisVerkleStateRoot, }) + const rpc = getRpcClient(server) it('genesis should be correctly setup', async () => { - const req = params('eth_getBlockByNumber', ['0x0', false]) - const expectRes = (res: any) => { - const block0 = res.body.result - assert.equal(block0.hash, genesisVerkleBlockHash) - assert.equal(block0.stateRoot, genesisVerkleStateRoot) - } - await baseRequest(server, req, 200, expectRes, false, false) + const res = await rpc.request('eth_getBlockByNumber', ['0x0', false]) + const block0 = res.result + assert.equal(block0.hash, genesisVerkleBlockHash) + assert.equal(block0.stateRoot, genesisVerkleStateRoot) }) it('should be able to apply new verkle payloads', async () => { - await batchBlocks(server) - }) - - it(`reset TD`, () => { - BlockHeader.prototype['_consensusFormatValidation'] = originalValidate - td.reset() + await batchBlocks(rpc) }) }) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index 23853b4f07..36e87b535d 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -8,14 +8,14 @@ import { getRpcClient, setupChain } from '../helpers.js' import type { Chain } from '../../../src/blockchain' import type { Common } from '@ethereumjs/common' -import type { HttpServer } from 'jayson' +import type { HttpClient } from 'jayson/promise' const genesisVerkleStateRoot = '0x5e8519756841faf0b2c28951c451b61a4b407b70a5ce5b57992f4bec973173ff' const genesisVerkleBlockHash = '0x0884fa3d670543463f7e1d9ea007332e1f8a3564ecf891de95a76e751cde45d7' const originalValidate = (BlockHeader as any).prototype._consensusFormatValidation async function runBlock( - { chain, server, common }: { chain: Chain; server: HttpServer; common: Common }, + { chain, rpc, common }: { chain: Chain; rpc: HttpClient; common: Common }, { execute, parent }: { execute: any; parent: any } ) { const blockCache = chain.blockCache @@ -26,12 +26,8 @@ async function runBlock( blockCache.executedBlocks.set(parentPayload.blockHash.slice(2), parentBlock) const executePayload = executionPayloadFromBeaconPayload(execute as any) - const req = params('engine_newPayloadV2', [executePayload]) - const expectRes = (res: any) => { - assert.equal(res.body.result.status, 'VALID') - } - - await baseRequest(server, req, 200, expectRes, false, false) + const res = await rpc.request('engine_newPayloadV2', [executePayload]) + assert.equal(res.result.status, 'VALID', 'valid status should be received') } describe(`valid verkle network setup`, async () => { @@ -54,10 +50,11 @@ describe(`valid verkle network setup`, async () => { const testCases = [ // 'block13', 'block16', - ] + ] as const + for (const testCase of testCases) { it(`run ${testCase}`, async () => { - await runBlock({ common, chain, server }, blocks[testCase]) + await runBlock({ common, chain, rpc }, blocks[testCase]) }) } From 0a7997543d60276a6e2d409a51b50e1f715d2946 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 21 Jan 2024 17:22:33 +0530 Subject: [PATCH 49/75] shift kaustinen 2 test to block 13 --- packages/client/test/rpc/engine/kaustinen2.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index 36e87b535d..ad20aa832d 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -48,8 +48,8 @@ describe(`valid verkle network setup`, async () => { // to not do clean init of the statemanager. this isn't a problem in sequential // execution, but need to be fixed up in the stateless random execution const testCases = [ - // 'block13', - 'block16', + 'block13', + // 'block16', ] as const for (const testCase of testCases) { From c0c02f9c0211c159e3b9a7609460cb7fcbfbd492 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 21 Jan 2024 18:08:21 -0500 Subject: [PATCH 50/75] client: remove stale kaustinen2 test data --- .../test/rpc/engine/kaustinen2-test.spec.ts | 103 --- .../test/testdata/blocks/kaustinen2-test.json | 788 ------------------ .../geth-genesis/kaustinen2-test.json | 86 -- 3 files changed, 977 deletions(-) delete mode 100644 packages/client/test/rpc/engine/kaustinen2-test.spec.ts delete mode 100644 packages/client/test/testdata/blocks/kaustinen2-test.json delete mode 100644 packages/client/test/testdata/geth-genesis/kaustinen2-test.json diff --git a/packages/client/test/rpc/engine/kaustinen2-test.spec.ts b/packages/client/test/rpc/engine/kaustinen2-test.spec.ts deleted file mode 100644 index acab675e59..0000000000 --- a/packages/client/test/rpc/engine/kaustinen2-test.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Block, executionPayloadFromBeaconPayload } from '@ethereumjs/block' -import { Common, Hardfork } from '@ethereumjs/common' -import { bytesToHex } from '@ethereumjs/util' -import { assert, describe, it } from 'vitest' - -import blocks from '../../testdata/blocks/kaustinen2-test.json' -import genesisJSON from '../../testdata/geth-genesis/kaustinen2-test.json' -import { getRpcClient, setupChain } from '../helpers' - -import type { HttpClient } from 'jayson/promise' - -// this verkle genesis stateroot and blockhash of the local generated kaustinen2 network -const genesisVerkleStateRoot = '0x30d24fe15e1281600a15328add431b906597d83cf33d23050627c51936bb0d1a' -const genesisVerkleBlockHash = '0x65bb31e62063fccdd3addd1da3a27c27d83f2eced51cad22da2a49e400b2f85c' -const merkleGenesisJsonBlock = { - number: '0x0', - hash: '0xdca7128b1c8b8ceff0c97c407f462dd50ee4dce2e28450b6bfecfaa8b293b7ab', - parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000', - mixHash: '0x0000000000000000000000000000000000000000000000000000000000000000', - nonce: '0x0000000000000056', - sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - stateRoot: '0xb1a96ff063ca4cdc5e605ae282c5d525894633e6e5eeac958f5b26252b62b526', - receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - miner: '0x0000000000000000000000000000000000000000', - difficulty: '0x1', - totalDifficulty: '0x1', - extraData: '0x', - size: '0x57b', - gasLimit: '0x2fefd8', - gasUsed: '0x0', - timestamp: '0x641d76f8', - transactions: [], - uncles: [], - baseFeePerGas: '0x3b9aca00', - withdrawalsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - withdrawals: [], -} - -export const batchBlocks = async (rpc: HttpClient) => { - for (let i = 0; i < blocks.length; i++) { - const executionPayload = executionPayloadFromBeaconPayload(blocks[i] as any) - - const res = await rpc.request('engine_newPayloadV2', [executionPayload]) - assert.equal(res.result.status, 'VALID', 'valid status should be received') - } -} - -describe(`verkle genesis checks`, () => { - const common = Common.fromGethGenesis(genesisJSON, { chain: 'kaustinen2' }) - it('genesis fork', async () => { - assert.equal(common.hardfork(), Hardfork.Prague, 'should be set at prague hardfork for verkle') - }) - const merkleGenesisBlock = Block.fromRPC(merkleGenesisJsonBlock, [], { common }) - assert.equal(merkleGenesisJsonBlock.hash, bytesToHex(merkleGenesisBlock.hash())) - - // get the block with the verkle genesis root instead of merkle root - const verkleGenesisBlock = Block.fromRPC( - { ...merkleGenesisJsonBlock, stateRoot: genesisVerkleStateRoot }, - [], - { common } - ) - assert.equal(genesisVerkleBlockHash, bytesToHex(verkleGenesisBlock.hash())) -}) - -describe(`invalid verkle network setup`, () => { - it('start client without verkle state root', async () => { - // assign a chain id not of kaustinen2 chain so as to not interfere with the stateroot lookup of - // kaustinen in genesis state enum of well known networks - const invalidGenesis = Object.assign({}, genesisJSON, { - config: { ...genesisJSON.config, chainId: 90069420 }, - }) - try { - await setupChain(invalidGenesis, 'post-merge', { - engine: true, - }) - assert.fail('Should have failed to start') - } catch (e: any) { - assert.equal(e.message, 'Verkle trie state not yet supported') - } - }) -}) - -describe(`valid verkle network setup`, async () => { - const { server } = await setupChain(genesisJSON, 'post-merge', { - engine: true, - genesisStateRoot: genesisVerkleStateRoot, - }) - - const rpc = getRpcClient(server) - it('genesis should be correctly setup', async () => { - const res = await rpc.request('eth_getBlockByNumber', ['0x0', false]) - const block0 = res.result - assert.equal(block0.hash, genesisVerkleBlockHash) - assert.equal(block0.stateRoot, genesisVerkleStateRoot) - }) - - it('should be able to apply new verkle payloads', async () => { - await batchBlocks(rpc) - }) -}) diff --git a/packages/client/test/testdata/blocks/kaustinen2-test.json b/packages/client/test/testdata/blocks/kaustinen2-test.json deleted file mode 100644 index 1e49f409f3..0000000000 --- a/packages/client/test/testdata/blocks/kaustinen2-test.json +++ /dev/null @@ -1,788 +0,0 @@ -[ - { - "parent_hash": "0x65bb31e62063fccdd3addd1da3a27c27d83f2eced51cad22da2a49e400b2f85c", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x30d24fe15e1281600a15328add431b906597d83cf33d23050627c51936bb0d1a", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0x65bb31e62063fccdd3addd1da3a27c27d83f2eced51cad22da2a49e400b2f85c", - "block_number": "1", - "gas_limit": "3144658", - "gas_used": "0", - "timestamp": "1699897334", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "875000000", - "block_hash": "0x997c1b4f06abc80b2f59ed3b75932ec07f08bc403c3eef91aee9e2be48842c27", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": null, - "newValue": null - }, - { - "suffix": "1", - "currentValue": null, - "newValue": null - }, - { - "suffix": "2", - "currentValue": null, - "newValue": null - }, - { - "suffix": "3", - "currentValue": null, - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x08", - "commitmentsByPath": [], - "d": "0x3c156cfeb05e3fcddfb4a1ed08b485cffa5aec47cda7068f8d19abfc9e45c5d9", - "ipaProof": { - "cl": [ - "0x1e8bc037a7e8d8d6be22573d7e5a689effb8a2172a3fece1ff812e8ca2f7a010", - "0x621b9840ba2b87d26f343916bdb3b98de00bbed59d2bd5d0018ed469414a76e5", - "0x2daf62b58e072395d95b7c0c08c4f5fa7a939aed4bd3a650c84d111f3e4096cb", - "0x72c3d220ed0a1f2bb8ac456f1833506897ef70c211a5da87f4b6f0f7b1872a7a", - "0x376c8cc36adaa8c59d5ea2da4553fb14f2e4460856d5ea245a587eaca5323314", - "0x4262d01cd550e149dfc253ee71425344950ba6eb989542aca813995f2f6e0f42", - "0x119dd4b8979746aeb016292cdf63e1050486f20dabb4fb5ce33c79a56806cf23", - "0x4be5ceba9d6233ada63cc21e583dd3c27d8309b983d247c8bda3ce35a6145611" - ], - "cr": [ - "0x207d90229537b988e6ffade58ec996866c76a2d1a277654fb318ee35f0b7f3aa", - "0x2ffcf497ec85a2b7338e53b26ca2c3f7b3b667cb3fe3cd9338ce7aa748c24520", - "0x5d1fb43a25d969b920178988c1abe64e893ce15827ccec836c9869c018bcfa7b", - "0x450db35e5f46b1914c8befbddf376fb6e72e4d5fbe88414c495051ec6f56bb52", - "0x62a318e1241d1aab99dc4f717afaefd3f88ec6446dcc1d3bbf825afc76dbfd50", - "0x7398cd3d17b4436f012144e718048b2c617e3443b5f6551c3dfb5e5e8986da9e", - "0x5e9cae984e7e512673875810f3665b224ac30e61a3c4ef255134699b36503d05", - "0x56f85963be7815f0910983cf01122e29414f327c0641351beda0ae2c2502e739" - ], - "finalEvaluation": "0x137a6618e6cde3243b5cc8963c92751bf82ec08d28e5b9b2a193a42619bcd1ed" - } - } - } - }, - { - "parent_hash": "0x997c1b4f06abc80b2f59ed3b75932ec07f08bc403c3eef91aee9e2be48842c27", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x30d24fe15e1281600a15328add431b906597d83cf33d23050627c51936bb0d1a", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0xae5c4a884a86a417470042cc784d628d8ede255992144d52649d564ac97dd82c", - "block_number": "2", - "gas_limit": "3147727", - "gas_used": "0", - "timestamp": "1699897340", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "765625000", - "block_hash": "0x831bf4167e6ba809055c956f6189e5d46cf6b4db9254af6a1a66503bd95d75ca", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": null, - "newValue": null - }, - { - "suffix": "1", - "currentValue": null, - "newValue": null - }, - { - "suffix": "2", - "currentValue": null, - "newValue": null - }, - { - "suffix": "3", - "currentValue": null, - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x08", - "commitmentsByPath": [], - "d": "0x3c156cfeb05e3fcddfb4a1ed08b485cffa5aec47cda7068f8d19abfc9e45c5d9", - "ipaProof": { - "cl": [ - "0x1e8bc037a7e8d8d6be22573d7e5a689effb8a2172a3fece1ff812e8ca2f7a010", - "0x621b9840ba2b87d26f343916bdb3b98de00bbed59d2bd5d0018ed469414a76e5", - "0x2daf62b58e072395d95b7c0c08c4f5fa7a939aed4bd3a650c84d111f3e4096cb", - "0x72c3d220ed0a1f2bb8ac456f1833506897ef70c211a5da87f4b6f0f7b1872a7a", - "0x376c8cc36adaa8c59d5ea2da4553fb14f2e4460856d5ea245a587eaca5323314", - "0x4262d01cd550e149dfc253ee71425344950ba6eb989542aca813995f2f6e0f42", - "0x119dd4b8979746aeb016292cdf63e1050486f20dabb4fb5ce33c79a56806cf23", - "0x4be5ceba9d6233ada63cc21e583dd3c27d8309b983d247c8bda3ce35a6145611" - ], - "cr": [ - "0x207d90229537b988e6ffade58ec996866c76a2d1a277654fb318ee35f0b7f3aa", - "0x2ffcf497ec85a2b7338e53b26ca2c3f7b3b667cb3fe3cd9338ce7aa748c24520", - "0x5d1fb43a25d969b920178988c1abe64e893ce15827ccec836c9869c018bcfa7b", - "0x450db35e5f46b1914c8befbddf376fb6e72e4d5fbe88414c495051ec6f56bb52", - "0x62a318e1241d1aab99dc4f717afaefd3f88ec6446dcc1d3bbf825afc76dbfd50", - "0x7398cd3d17b4436f012144e718048b2c617e3443b5f6551c3dfb5e5e8986da9e", - "0x5e9cae984e7e512673875810f3665b224ac30e61a3c4ef255134699b36503d05", - "0x56f85963be7815f0910983cf01122e29414f327c0641351beda0ae2c2502e739" - ], - "finalEvaluation": "0x137a6618e6cde3243b5cc8963c92751bf82ec08d28e5b9b2a193a42619bcd1ed" - } - } - } - }, - { - "parent_hash": "0x831bf4167e6ba809055c956f6189e5d46cf6b4db9254af6a1a66503bd95d75ca", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4250f5f8c4067a671b247ea6f8b820982f9057aa4062a88d1d7165d79892b9a3", - "receipts_root": "0xc3b8f4b1785850ff169304af7194d35792f4a71215b92a134b6670be472bfae5", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0x011d0e875b91fc39d02b7ad37a2b176959f41b04b629a7cb0a63f130c23f71c3", - "block_number": "3", - "gas_limit": "3150799", - "gas_used": "34300", - "timestamp": "1699897346", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "669921875", - "block_hash": "0xb197644aa5e5ef320bc203a3ee57c3e507c3d6ffa8477ce083ca267863d55e02", - "transactions": [ - "0x02f87283010f2c808405f5e1008511d970eaa0830f4240943da33b9a0894b908ddbb00d96399e506515a1009830f424080c001a0b42278ecb4ab875bb5b930354f803f154a3cc9704844936f1af609d6dc2bbf29a03b9296672f5722e03968187e9bf60f1ec9eeb93d7436fae3260c1358f8bc2c75" - ], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": null, - "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "1", - "currentValue": null, - "newValue": "0x007cee9b1e030000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": null, - "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "3", - "currentValue": null, - "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - }, - { - "stem": "0x5e3427be607e90505472f200e64a2ebfcb990b46f8688d0b0f35a9c11025e0", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": null, - "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "1", - "currentValue": null, - "newValue": "0x40420f0000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": null, - "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "3", - "currentValue": null, - "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - }, - { - "stem": "0x97233a822ee74c294ccec8e4e0c65106b374d4423d5d09236d0f6c6647e185", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x0000004a48011416954508000000000000000000000000000000000000000000", - "newValue": "0x0c99639f43e91316954508000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": "0x0100000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x08080a", - "commitmentsByPath": [ - "0x6d377ca1fdd68b453d921cb4bd01a57cd2e06ae8573482c779fdcd7eea9a0a6c", - "0x29f3b12087b4d56fb2b406eadbbb2677427fb8b72b0c9221bb1acfe10b5e9494" - ], - "d": "0x31ac0c6a2ffaebf19e06070c9dd51edf0b4e226be8ce82c89b5ce7cd9007002c", - "ipaProof": { - "cl": [ - "0x250c5b780488a534e7db36e3331edc20e8bf66686e7e4babe3c09c61d502f84b", - "0x0af08c0c70c9ac0a156fcb0307e573c0cada87c4f5d55c4705e85ddd01a78e4d", - "0x5b2a0e06d51e12dc994b36d140a1c7f82913ac8a8ad61adc833944cafca80d75", - "0x54c67b4692bc0d424ea20787842858b13591af5b2de0213070294d15ebbe94f2", - "0x2685e70ccee07cf86c19a08ce06fa6fd739d94117f9c9251bedbe1683bf19c2e", - "0x71ffa0a6760c59c711f57757e97802bd4440d86ea76c58ae821beadfa6e654ec", - "0x331551f3488ff10ced2fd229c36110c83e9c4a9b94532bc08bda4128f392c7c5", - "0x52defe3fb4e63399ddc600afb55c5754f62670355c7378b0a3015e94278c365d" - ], - "cr": [ - "0x2519f1964a29c23f99284d5543f9d3edb61c75a2bed357a0f337d92c558d5458", - "0x51a00d6dcf8457fd8db623e71118a406f781c2a7b6c1deb783b676c89d32b681", - "0x3c9c51736b579624939648a6416e4f14cde382fc5aef7b0c06eb00184b6c944f", - "0x055bd0d33005e2d823b1a06eb5c610a73a89a45393142351ea54df0994e17a75", - "0x4a92c119a1f305455ee9c42cc3130a1eba083c40580e75e93a86174b479e25e9", - "0x6adb4916dcd820c358d77f73481cc8b935bd032ebe08c78272be05218b8c8a0f", - "0x218d77f25c096818426f1dd17818579ed0723c5de905b4403e51f76b546ca38b", - "0x1038998e1602cc4ba49005d77327937a0a5c95f62acae1c4157abdb6880bb242" - ], - "finalEvaluation": "0x1cbe43e36c4c77ae43e3051d7dcf977ca5b35011e1f0195b9de022818301438e" - } - } - } - }, - { - "parent_hash": "0xb197644aa5e5ef320bc203a3ee57c3e507c3d6ffa8477ce083ca267863d55e02", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4250f5f8c4067a671b247ea6f8b820982f9057aa4062a88d1d7165d79892b9a3", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0x7477e90a214b800fb9f8000a909ef7a7c831bb439fef70499052c87459e7f552", - "block_number": "4", - "gas_limit": "3153874", - "gas_used": "0", - "timestamp": "1699897352", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "588004855", - "block_hash": "0xa4f8ae89e318800edb233e97663f122044d5e4ae9f4dfd64f59acb97aba15b3d", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x007cee9b1e030000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x0a", - "commitmentsByPath": [ - "0x3602af74c4621b740a52f19778bf2c4f5749833b22edf0e95e3234168c786234", - "0x5213f3b137020e7e95ac1c5ac1ddac551b9c7cc80663a2a625e4382d907685d8" - ], - "d": "0x6efdb8268b2ed07371ab19bdae6f2e966034c2ee380b45ad41a1a92b3ebb435c", - "ipaProof": { - "cl": [ - "0x4a58265ee6e48d145093ef17c90c65c45fffa6f8384d37b4d5d782b670b5ad73", - "0x19cef344cf6406509a612697df1f5879dd2235d353660f19939edd331a4b46b8", - "0x5352f3ff1a77bcea8859b8d1bf906d658f60e94d723d9f4dfb3f822cc6c4f293", - "0x06fe05179105212e2eb4ee546a5969814f90863a208800787f330026677a1351", - "0x10231b0c4720d0208f8e1f7fc70a1994af1af308eb5cefa6e5b8fe2e3f5c36e8", - "0x2ea4da976f38ad1cc275871904f269cd36b62149e0c4271f43516472013e6fe6", - "0x328e67ea51377efca4b5f336e90e68e3524b876d0c44002850b84b94e5a88acb", - "0x30fe2558df07d09d025ae35c7d2f4802f92832503579de2bb718fd19577e2b9b" - ], - "cr": [ - "0x2359207ecf58dd1c10c6fbd3cc6b4a27a9005438951faedf5d631356bebd22af", - "0x2ab9cfc92d8f0f98e7f70383b058545cd075f45689622821e09d7f5e83d0b44a", - "0x10f2e0eb95041e2258fad7a24a17bb62017656f72027d63633c9566d60d1eacc", - "0x25acb28b7990eb2b478151b5714996e12e20b0098577f18ee4bbfe765bcb4c8f", - "0x0170c542013175cd68223688552ad5ecbb70b5a16e60145771ddb1a4b730f214", - "0x178df6d6d14c74cc6fbc7da9d877ffff47b43f374b6e5b8157086b8ee4f03f6e", - "0x46492793a51370908302f4f9e936417ee95d63aa8bfe3b2edfaacb75d92c21ac", - "0x4c24f9b2d541a32cf43593cc1607effdce6814ec1ebd9d1ea69f15c77b9bb6a2" - ], - "finalEvaluation": "0x0bcac30e940d1fbe2948be28f9c14afc070222e03f392ef79725a6bda9d17ad7" - } - } - } - }, - { - "parent_hash": "0xa4f8ae89e318800edb233e97663f122044d5e4ae9f4dfd64f59acb97aba15b3d", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4b20302831ee663994bcb346aa8c49de52f501b52997ba47b49649c43124904f", - "receipts_root": "0xc3b8f4b1785850ff169304af7194d35792f4a71215b92a134b6670be472bfae5", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0xdb36ad05305cd8212ed3381592f882431f1b851ebbd29ad0feac6f0e52a55cbd", - "block_number": "5", - "gas_limit": "3156952", - "gas_used": "34300", - "timestamp": "1699897358", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "514504249", - "block_hash": "0x81cf4fcface70ad71b73a5f313400ac10c08fe33935d78bb2275ce6747c5b406", - "transactions": [ - "0x02f87283010f2c018405f5e100850a814f2988830f4240943da33b9a0894b908ddbb00d96399e506515a1009830f424080c001a0a465121d691cfa8cee351bc2716f1c9ca9bf13326093f15e38cbedb78227af92a04a15f8ee7f5856291b015f3a95b1978f6833a4c4731c3a5078721cb0f0641348" - ], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x007cee9b1e030000000000000000000000000000000000000000000000000000", - "newValue": "0x00f8dc373d060000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - }, - { - "stem": "0x5e3427be607e90505472f200e64a2ebfcb990b46f8688d0b0f35a9c11025e0", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x40420f0000000000000000000000000000000000000000000000000000000000", - "newValue": "0x80841e0000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - }, - { - "stem": "0x97233a822ee74c294ccec8e4e0c65106b374d4423d5d09236d0f6c6647e185", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x0c99639f43e91316954508000000000000000000000000000000000000000000", - "newValue": "0xb0ddae2218d61316954508000000000000000000000000000000000000000000" - }, - { - "suffix": "2", - "currentValue": "0x0100000000000000000000000000000000000000000000000000000000000000", - "newValue": "0x0200000000000000000000000000000000000000000000000000000000000000" - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x0a0a0a", - "commitmentsByPath": [ - "0x3602af74c4621b740a52f19778bf2c4f5749833b22edf0e95e3234168c786234", - "0x5213f3b137020e7e95ac1c5ac1ddac551b9c7cc80663a2a625e4382d907685d8", - "0x18df835e0891dec6af9ab1014cfa419cd3a0ec8fd1937ff1c478a8cca17fec89", - "0x0afb82b44a0a45f072e2d9f75d74cb6b1f19711c30f95e67a8b67e4b5810a214", - "0x6db0f61ac54f18358f02683a676a45a16d15f0bce0772ca0c92bb4bf5980b1b5", - "0x32c8845bba888721c1fb7ce75d70a7e20b195fa4bc3d8d0c566e9c6aefb81429" - ], - "d": "0x634fae8e0f97dfed86ed58061c08654b8df161cfa133098643a6ece8af5f076e", - "ipaProof": { - "cl": [ - "0x52f3bd558dd2e226e28f029a8afd0cfbd48b5fc74309e76b28fa7d2165933e71", - "0x65bcab2d79371e9ec8cb3b6bed8b0fefe42cc7c92ba02ea8bef5e603cff7d733", - "0x502fef5f1299c3d81f9b558088424448f81e62dbf4d39d8b3db7f0ec17900e2d", - "0x3c1532a2b81d72a3005eb502a5cac73ec4b9b5e5f7ef46eaf45c3bd221953be3", - "0x58f9fcfcd3e7acb50d51ffdaaa8c5cd95289038a3334b2088a9e9f35f0c2b305", - "0x16c2735193a895bc955aa906c999fde489ea4584c83e7dfd7e335385968c1689", - "0x019fd3cd6c8df2e30ff42e87043c3e6783be11d039be6211c5d4c70cccb6fc41", - "0x5e99042581d29ce46bc40e1ddce5b087c0ad9f1405618d540c088a1525881ec7" - ], - "cr": [ - "0x647b30c6015fc8d0a85fd0d54268c0f8ac804c297a50caefc31341878fe51389", - "0x5052cff45999dcef8beb6bc8a089eb0b2aba0f53fed05caba508e0d7e3390488", - "0x57bab8adb1d1ad380fb201ddcd21ab7d8ca28a5d6dc6bc05a57dcc2201e25025", - "0x1aa5b880b18147d6db6fb03eca2221201d874cd362523a2ef4a8c6490679d7e5", - "0x304abd16f9a8598c0b8020f164a763141a7507529f2270861606929cbf8bf8dc", - "0x004c630be92bb68b186a8f83def940450cf2ce330089c9225e50114cb14f0387", - "0x3af5cf8aa59e85a4a8d262dc6d3a139989929cee98dea9afd524da264babfb4f", - "0x2e5ea3b5fdd80c4eb4e3bd7f16be44747368cb541ccb75ceb26c7426745f3248" - ], - "finalEvaluation": "0x0562f49390508e8a657c7690dd43bf259965452585fea1ebb4ebd076eaeb05f4" - } - } - } - }, - { - "parent_hash": "0x81cf4fcface70ad71b73a5f313400ac10c08fe33935d78bb2275ce6747c5b406", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4b20302831ee663994bcb346aa8c49de52f501b52997ba47b49649c43124904f", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0x98f6d35950dd43a4b3850b84213f46603d89d28e0ee77be5a45b468a04baa2fa", - "block_number": "6", - "gas_limit": "3160033", - "gas_used": "0", - "timestamp": "1699897364", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "451588729", - "block_hash": "0xe8f8aee5b549dffbc6ee37cbcefb3ba0d0b04dbbf931598fe3ddefa4936adae5", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x00f8dc373d060000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x0a", - "commitmentsByPath": [ - "0x29e615233d2b8fa3621c62250d4d8bbaef899b06ffafdc5de864d656f9c004b7", - "0x64b20c84f53d077f01a7818f67d2f975eaefa7722be90ca062c30c9c083bbcd2" - ], - "d": "0x4b54c77b8b5a612cafeeed38806ee21c7c4cf356e24dab2b740bffa56db4532c", - "ipaProof": { - "cl": [ - "0x5401e49d28116b01f8c88a23951bb97b870bcf0c1a686a2216c0a6ab1d0980ca", - "0x4bcdb912ea7bc8e79f85e56ec064a119be5d2957ca5dd706d79e39a212c20f0c", - "0x4897419b281e181b7c86de7c77f7eabbe78f3ede04fe66c1d0807e0188c488e0", - "0x4c6bf2502c8d72a7692b0ebdce97882db786f089d75ccb2df042576fecb54e95", - "0x0c6eb9ef3d089038cfd867925ada9f0d76bc69eba4b80e3ae4f03db71347520b", - "0x680b0bdb201c8765b0375a4e1eecc69607cf0a190e0d0a0df91613cb10c187f5", - "0x49417a59b2405b0117d5c1b1baed25319f9f1eb8aaa04cd73c30474d6f1d4b42", - "0x2dadc51222595c67e441515a6b87966384b0ded8e5bf8b3c55d7d63d08cb2c65" - ], - "cr": [ - "0x207de707a365bb8516ae012c28d998c6b9d03e78617f712957f640f55bc50009", - "0x352b1d8322433a27a2468963a61c81fe6d96ddb12e4755d88f377c8b012de331", - "0x6745c34e3c1292e88e8d564f003870c6381920724a9c9bd50866b88626d99b04", - "0x552b584ef2c001bf5b66a9358c3055f9274f231867746e0faf77d2f0d41cb939", - "0x576db2a9b2fb8e2de022a29743dc8ddb5777c3d7d9bce242bb88bfdb1da136d9", - "0x0342d60f32675d2c18da7e872fb761dbb410cae4d38e1ac75278f0ed5e1979b1", - "0x27c2458e23bbf066f7a3285d71f2934050a92cb282d8395409b80502f253f613", - "0x5a067db1769ab6202d9dcb7d2910b7b7e10129aa5d1fa34baa159a097db93c46" - ], - "finalEvaluation": "0x05d983cebb39139feddbe89d8ff57e69674fdc059a347db1dd9e713e1b65ec41" - } - } - } - }, - { - "parent_hash": "0xe8f8aee5b549dffbc6ee37cbcefb3ba0d0b04dbbf931598fe3ddefa4936adae5", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4b20302831ee663994bcb346aa8c49de52f501b52997ba47b49649c43124904f", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0x07d083040dcf80f9ae5c5bd84651b5ec5fda254025271057f8b3d8120459bda4", - "block_number": "7", - "gas_limit": "3163117", - "gas_used": "0", - "timestamp": "1699897370", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "395140138", - "block_hash": "0x42db9449e69ce333690212e6d5fd64b742ac7d86fd7674afefed03bc1129b624", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x00f8dc373d060000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x0a", - "commitmentsByPath": [ - "0x29e615233d2b8fa3621c62250d4d8bbaef899b06ffafdc5de864d656f9c004b7", - "0x64b20c84f53d077f01a7818f67d2f975eaefa7722be90ca062c30c9c083bbcd2" - ], - "d": "0x4b54c77b8b5a612cafeeed38806ee21c7c4cf356e24dab2b740bffa56db4532c", - "ipaProof": { - "cl": [ - "0x5401e49d28116b01f8c88a23951bb97b870bcf0c1a686a2216c0a6ab1d0980ca", - "0x4bcdb912ea7bc8e79f85e56ec064a119be5d2957ca5dd706d79e39a212c20f0c", - "0x4897419b281e181b7c86de7c77f7eabbe78f3ede04fe66c1d0807e0188c488e0", - "0x4c6bf2502c8d72a7692b0ebdce97882db786f089d75ccb2df042576fecb54e95", - "0x0c6eb9ef3d089038cfd867925ada9f0d76bc69eba4b80e3ae4f03db71347520b", - "0x680b0bdb201c8765b0375a4e1eecc69607cf0a190e0d0a0df91613cb10c187f5", - "0x49417a59b2405b0117d5c1b1baed25319f9f1eb8aaa04cd73c30474d6f1d4b42", - "0x2dadc51222595c67e441515a6b87966384b0ded8e5bf8b3c55d7d63d08cb2c65" - ], - "cr": [ - "0x207de707a365bb8516ae012c28d998c6b9d03e78617f712957f640f55bc50009", - "0x352b1d8322433a27a2468963a61c81fe6d96ddb12e4755d88f377c8b012de331", - "0x6745c34e3c1292e88e8d564f003870c6381920724a9c9bd50866b88626d99b04", - "0x552b584ef2c001bf5b66a9358c3055f9274f231867746e0faf77d2f0d41cb939", - "0x576db2a9b2fb8e2de022a29743dc8ddb5777c3d7d9bce242bb88bfdb1da136d9", - "0x0342d60f32675d2c18da7e872fb761dbb410cae4d38e1ac75278f0ed5e1979b1", - "0x27c2458e23bbf066f7a3285d71f2934050a92cb282d8395409b80502f253f613", - "0x5a067db1769ab6202d9dcb7d2910b7b7e10129aa5d1fa34baa159a097db93c46" - ], - "finalEvaluation": "0x05d983cebb39139feddbe89d8ff57e69674fdc059a347db1dd9e713e1b65ec41" - } - } - } - }, - { - "parent_hash": "0x42db9449e69ce333690212e6d5fd64b742ac7d86fd7674afefed03bc1129b624", - "fee_recipient": "0xcccccccccccccccccccccccccccccccccccccccc", - "state_root": "0x4b20302831ee663994bcb346aa8c49de52f501b52997ba47b49649c43124904f", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "prev_randao": "0xb0a73f71497e1599a0df3799604f52b6ab7e0eeadbbfd4be762506b72715ed74", - "block_number": "8", - "gas_limit": "3166204", - "gas_used": "0", - "timestamp": "1699897376", - "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", - "base_fee_per_gas": "345747621", - "block_hash": "0x88bf75dd8909f8c47f5f3b0c0c89cf425e71cb5ae8cb92a0f1add8c96f93b063", - "transactions": [], - "withdrawals": [], - "execution_witness": { - "stateDiff": [ - { - "stem": "0x3cc88d00122c996769be8222a4d8e62caeb8929f307d2b947ac956d49b2362", - "suffixDiffs": [ - { - "suffix": "0", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "1", - "currentValue": "0x00f8dc373d060000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "2", - "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", - "newValue": null - }, - { - "suffix": "3", - "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "newValue": null - }, - { - "suffix": "4", - "currentValue": null, - "newValue": null - } - ] - } - ], - "verkleProof": { - "otherStems": [], - "depthExtensionPresent": "0x0a", - "commitmentsByPath": [ - "0x29e615233d2b8fa3621c62250d4d8bbaef899b06ffafdc5de864d656f9c004b7", - "0x64b20c84f53d077f01a7818f67d2f975eaefa7722be90ca062c30c9c083bbcd2" - ], - "d": "0x4b54c77b8b5a612cafeeed38806ee21c7c4cf356e24dab2b740bffa56db4532c", - "ipaProof": { - "cl": [ - "0x5401e49d28116b01f8c88a23951bb97b870bcf0c1a686a2216c0a6ab1d0980ca", - "0x4bcdb912ea7bc8e79f85e56ec064a119be5d2957ca5dd706d79e39a212c20f0c", - "0x4897419b281e181b7c86de7c77f7eabbe78f3ede04fe66c1d0807e0188c488e0", - "0x4c6bf2502c8d72a7692b0ebdce97882db786f089d75ccb2df042576fecb54e95", - "0x0c6eb9ef3d089038cfd867925ada9f0d76bc69eba4b80e3ae4f03db71347520b", - "0x680b0bdb201c8765b0375a4e1eecc69607cf0a190e0d0a0df91613cb10c187f5", - "0x49417a59b2405b0117d5c1b1baed25319f9f1eb8aaa04cd73c30474d6f1d4b42", - "0x2dadc51222595c67e441515a6b87966384b0ded8e5bf8b3c55d7d63d08cb2c65" - ], - "cr": [ - "0x207de707a365bb8516ae012c28d998c6b9d03e78617f712957f640f55bc50009", - "0x352b1d8322433a27a2468963a61c81fe6d96ddb12e4755d88f377c8b012de331", - "0x6745c34e3c1292e88e8d564f003870c6381920724a9c9bd50866b88626d99b04", - "0x552b584ef2c001bf5b66a9358c3055f9274f231867746e0faf77d2f0d41cb939", - "0x576db2a9b2fb8e2de022a29743dc8ddb5777c3d7d9bce242bb88bfdb1da136d9", - "0x0342d60f32675d2c18da7e872fb761dbb410cae4d38e1ac75278f0ed5e1979b1", - "0x27c2458e23bbf066f7a3285d71f2934050a92cb282d8395409b80502f253f613", - "0x5a067db1769ab6202d9dcb7d2910b7b7e10129aa5d1fa34baa159a097db93c46" - ], - "finalEvaluation": "0x05d983cebb39139feddbe89d8ff57e69674fdc059a347db1dd9e713e1b65ec41" - } - } - } - } -] \ No newline at end of file diff --git a/packages/client/test/testdata/geth-genesis/kaustinen2-test.json b/packages/client/test/testdata/geth-genesis/kaustinen2-test.json deleted file mode 100644 index a865839056..0000000000 --- a/packages/client/test/testdata/geth-genesis/kaustinen2-test.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "config": { - "chainId": 69420, - "homesteadBlock": 0, - "daoForkBlock": 0, - "daoForkSupport": false, - "eip150Block": 0, - "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "mergeNetsplitBlock": 0, - "shanghaiTime":0, - "pragueTime":1679652600, - "terminalTotalDifficulty": 0, - "terminalTotalDifficultyPassed": true, - "proofInBlocks": true - }, - "nonce": "0x56", - "timestamp": "1679652600", - "extraData": "0x", - "gasLimit": "0x2fefd8", - "difficulty": "0x1", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134": { - "balance": "10000000000000000000000000" - }, - "0x878705ba3f8bc32fcf7f4caa1a35e72af65cf766": { - "balance": "10000000000000000000000000" - }, - "0x97C9B168C5E14d5D369B6D88E9776E5B7b11dcC1": { - "balance": "10000000000000000000000000" - }, - "0x2c3b8eb88245b03d2ee67a24b54525b4696d827f": { - "balance": "10000000000000000000000000" - }, - "0x4242424242424242424242424242424242424242": { - "balance": "0", - "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", - "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", - "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", - "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", - "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", - "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", - "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", - "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", - "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", - "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", - "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", - "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", - "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", - "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", - "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", - "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", - "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", - "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", - "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", - "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", - "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", - "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", - "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", - "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", - "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", - "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", - "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", - "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", - "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", - "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", - "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" - } - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} From c21ef84fbf48224b81fc7b5d48be06aa5d8a9708 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 21 Jan 2024 22:00:31 -0500 Subject: [PATCH 51/75] vm: adjust rewardAccount new common arg ordering and make it optional --- packages/vm/src/buildBlock.ts | 4 ++-- packages/vm/src/runBlock.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index e8f61278cd..b9f21b55a0 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -173,7 +173,7 @@ export class BlockBuilder { this.headerData.coinbase !== undefined ? new Address(toBytes(this.headerData.coinbase)) : Address.zero() - await rewardAccount(this.vm.common, this.vm.evm, coinbase, reward) + await rewardAccount(this.vm.evm, coinbase, reward, this.vm.common) } /** @@ -189,7 +189,7 @@ export class BlockBuilder { if (amount === 0n) continue // Withdrawal amount is represented in Gwei so needs to be // converted to wei - await rewardAccount(this.vm.common, this.vm.evm, address, amount * GWEI_TO_WEI) + await rewardAccount(this.vm.evm, address, amount * GWEI_TO_WEI, this.vm.common) } } diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 5a9d95f96a..31d4aaa3c5 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -507,7 +507,7 @@ async function assignWithdrawals(this: VM, block: Block): Promise { // converted to wei // Note: event if amount is 0, still reward the account // such that the account is touched and marked for cleanup if it is empty - await rewardAccount(this.common, this.evm, address, amount * GWEI_TO_WEI) + await rewardAccount(this.evm, address, amount * GWEI_TO_WEI, this.common) } } @@ -524,14 +524,14 @@ async function assignBlockRewards(this: VM, block: Block): Promise { // Reward ommers for (const ommer of ommers) { const reward = calculateOmmerReward(ommer.number, block.header.number, minerReward) - const account = await rewardAccount(this.common, this.evm, ommer.coinbase, reward) + const account = await rewardAccount(this.evm, ommer.coinbase, reward, this.common) if (this.DEBUG) { debug(`Add uncle reward ${reward} to account ${ommer.coinbase} (-> ${account.balance})`) } } // Reward miner const reward = calculateMinerReward(minerReward, ommers.length) - const account = await rewardAccount(this.common, this.evm, block.header.coinbase, reward) + const account = await rewardAccount(this.evm, block.header.coinbase, reward, this.common) if (this.DEBUG) { debug(`Add miner reward ${reward} to account ${block.header.coinbase} (-> ${account.balance})`) } @@ -559,14 +559,14 @@ export function calculateMinerReward(minerReward: bigint, ommersNum: number): bi } export async function rewardAccount( - common: Common, evm: EVMInterface, address: Address, - reward: bigint + reward: bigint, + common?: Common ): Promise { let account = await evm.stateManager.getAccount(address) if (account === undefined) { - if (common.isActivatedEIP(6800)) { + if (common?.isActivatedEIP(6800) === true) { ;( evm.stateManager as StatelessVerkleStateManager ).accessWitness!.touchAndChargeProofOfAbsence(address) @@ -576,7 +576,7 @@ export async function rewardAccount( account.balance += reward await evm.journal.putAccount(address, account) - if (common.isActivatedEIP(6800)) { + if (common?.isActivatedEIP(6800) === true) { // use this utility to build access but the computed gas is not charged and hence free ;(evm.stateManager as StatelessVerkleStateManager).accessWitness!.touchTxExistingAndComputeGas( address, From 7ddd761e808e32c08e0d0733962573c8fefefb51 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 27 Jan 2024 19:08:34 +0530 Subject: [PATCH 52/75] add block12 to the spec list --- .../client/test/rpc/engine/kaustinen2.spec.ts | 1 + .../test/testdata/blocks/kaustinen2.json | 266 ++++++++++++++++++ 2 files changed, 267 insertions(+) diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index ad20aa832d..477424e46d 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -48,6 +48,7 @@ describe(`valid verkle network setup`, async () => { // to not do clean init of the statemanager. this isn't a problem in sequential // execution, but need to be fixed up in the stateless random execution const testCases = [ + // 'block12', 'block13', // 'block16', ] as const diff --git a/packages/client/test/testdata/blocks/kaustinen2.json b/packages/client/test/testdata/blocks/kaustinen2.json index 6ae73d837c..3c8be8ca65 100644 --- a/packages/client/test/testdata/blocks/kaustinen2.json +++ b/packages/client/test/testdata/blocks/kaustinen2.json @@ -1,4 +1,270 @@ { + "block12":{ + "parent":{ + "parent_hash": "0x1f6b2657716798142d316f6cd439c1bd79e8ccb4adff583eb95cc0bc7116da09", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x5e8519756841faf0b2c28951c451b61a4b407b70a5ce5b57992f4bec973173ff", + "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xf62beb8fd024fdfb4014a0b50239542030bb2552d43a309ab297e12aaebca74f", + "block_number": "11", + "gas_limit": "25269853", + "gas_used": "0", + "timestamp": "1700826732", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "230191131", + "block_hash": "0xb3b593ec721b3210f1d95938e52b231d22520250f7a1df018559171e843eadf4", + "transactions": [], + "withdrawals": [], + "execution_witness": { + "state_diff": [ + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffix_diffs": [ + { + "suffix": 0, + "current_value": null, + "new_value": null + }, + { + "suffix": 1, + "current_value": null, + "new_value": null + }, + { + "suffix": 2, + "current_value": null, + "new_value": null + }, + { + "suffix": 3, + "current_value": null, + "new_value": null + }, + { + "suffix": 4, + "current_value": null, + "new_value": null + } + ] + } + ], + "verkle_proof": { + "other_stems": [ + "0x8d1ed2380e53baf4d77bdb0adaeec334d72569de8e12d371ab2e4d6b131a37" + ], + "depth_extension_present": "0x09", + "commitments_by_path": [ + "0x12823635f1b4863990e04f17b699b018c8909455710ec2aed425d49d4af58db3" + ], + "d": "0x6f9f26ae4ee94d72c04c2c05570dc99ed715e8f1e49635744252945ed8f2b90d", + "ipa_proof": { + "cl": [ + "0x639d29b11c0d55203f0f1711a390b31ca0c2ba0fdfbc21f884fc6583177f0909", + "0x7113433b4199d42f645158ddef9083039e9765d8fa9eacf8f649e736df7b877b", + "0x01bc246cebcb30ecc694744968aec6a3acb4d381f07124618f631a8b4a133f12", + "0x6817a4ad5be2947ab6cb1951f547fd4ccd9d2431a5931fe893edac914e61a77d", + "0x714463d61d0dd687990529d0f7d5bc14b2950a137df4448f8cf4e8834a65ca7d", + "0x66da12b4ac2dcaad76a6cd3456c8bbea6bc1f54a7a74e9d69e65439843eb9daf", + "0x63f0524871f4f4c203f790ed7a0d859f3a06ce1a53fb750bee814df23ed69f00", + "0x23be67484d7eb0df84517fad5494a92e49be12eff0446a273ef77a0b70e4674f" + ], + "cr": [ + "0x141bddf7d7e2b2334cd098bf94f09c05e7d74da546da725d12a0cc8859ca381d", + "0x5d2f70a7f3ec509cd332feca57e6b83726ee65f8a9de46d3337bcabd2f23bb6f", + "0x5845326f733826e9c5a8e180cc9ea51489fe3429587c2ae2cd435a995c480926", + "0x5ae341f452acd7c98d2e67c37feb648082327c863a7eeb94d11fce6ff674c175", + "0x6543b52abf9c2316302153395777378c4e39e6376897ca9f0624d390e0d283d9", + "0x17ccf867c8c79b4ae2baa5b63478087b2dd02002d95cfde90b6e5810c6eb2fe7", + "0x67ecffef984a8d828421fa62ccb12733dd22e8ced19287e3cfe5b5c5a1743894", + "0x4adffd87fdcff6950a8220a78a34bb524f5bc7752406374a079799c2cda847a7" + ], + "final_evaluation": "0x17411d7fb0a20d044e1642999bfe17bec4573dc4a0f4c6f4ae5462b6d2b1b391" + } + } + } + }, + "execute":{ + "parent_hash": "0xb3b593ec721b3210f1d95938e52b231d22520250f7a1df018559171e843eadf4", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x606482e583d5b8349862a43df0b2e0994d2c434b3099bb01fca5fe7a4f568dc6", + "receipts_root": "0x01838704d6c1bf710ca326f911dff2ea2c834eeba929a8a40c204f9458e85e9b", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0x46e5593823385005b51a99dc72f4c6d39a02c7d37c9430b2b671933d42624e8c", + "block_number": "12", + "gas_limit": "25294529", + "gas_used": "68600", + "timestamp": "1700826744", + "extra_data": "0xd983010c01846765746889676f312e32302e3130856c696e7578", + "base_fee_per_gas": "201417240", + "block_hash": "0x6386c5d6fdbdc1ea5a13c58816a75c4171c5fb7ccd9bdb4bc47efadf4b4572ef", + "transactions": [ + "0xf86d80847735940082f618946177843db3138ae69679a54b95cf345ed759450d870aa87bee5380008083021e7ca06f30db0d28ee7c5f6699558c034c5de92c005853979eb087b62c05fa3ba53674a043664c0bfa955aefdc495116e2b3a85c36d0572a8824e6f5a404b0103db57c84", + "0xf86d01847735940082f61894687704db07e902e9a8b3754031d168d46e3d586e870aa87bee5380008083021e7ca0919b9a7bd0f13fcb13bdb96e593d1428a9c18bdd45754f52bed87c5d05f0bc56a078c06c36bf82ef688b685217d60a49a1330c0a22937367823f4e2dc633a0dcbf" + ], + "withdrawals": [], + "execution_witness": { + "stateDiff": [ + { + "stem": "0x0e88cc6bf033a3ff779335e720d5a7edf907cc70ab7ff31375cd485db779fc", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x714a8e6f30f0dd821d0eb4064e1b3f96721f60a7fb8c369e36af3299259343", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": null + }, + { + "suffix": "1", + "currentValue": "0x000000e83c80d09f3c2e3b030000000000000000000000000000000000000000", + "newValue": "0x00a015ae7cb2ba9f3c2e3b030000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newValue": "0x0200000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "newValue": null + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0x8dc286880de0cc507d96583b7c4c2b2b25239e58f8e67509b32edb5bbf293c", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0xc0509d4a37700000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + }, + { + "stem": "0xc484e43d783cf4f4eded1a8cee57e046e1ac2aaf6937ca4821263f0dbc759e", + "suffixDiffs": [ + { + "suffix": "0", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "1", + "currentValue": null, + "newValue": "0x008053ee7ba80a00000000000000000000000000000000000000000000000000" + }, + { + "suffix": "2", + "currentValue": null, + "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "suffix": "3", + "currentValue": null, + "newValue": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + }, + { + "suffix": "4", + "currentValue": null, + "newValue": null + } + ] + } + ], + "verkleProof": { + "otherStems": [ + "0x8d1ed2380e53baf4d77bdb0adaeec334d72569de8e12d371ab2e4d6b131a37" + ], + "depthExtensionPresent": "0x080a0910", + "commitmentsByPath": [ + "0x00f2c2af75fb32d073540aa153d5dd3a87f7e24b62b3b266b0fcca7bbae77a56", + "0x0ef3fcb96d17a16ee996440fc5bedcb6a82b4ccf7b8b9243228b7bb422f5715b", + "0x12823635f1b4863990e04f17b699b018c8909455710ec2aed425d49d4af58db3", + "0x3c9781a5cc339c771889e698db5baa0766ec750ce7984b329d22b31e62c73bc8" + ], + "d": "0x713fedbc7b55ed57cd3e00407c58de3693106f5d5cd063d5d93284f85d5295c5", + "ipaProof": { + "cl": [ + "0x0e795ba5a3eb31ee1a46d6ef5add90393b7878ef6e13f8d55c52d739d7647315", + "0x47d7b0bec64833a49d2adcfe8f1eeb7ce72cf43d47698c1daf152c9f8ceea351", + "0x523b1ae8c1d9a661aa21280774c9328840487e0ba37594195369002ea1605616", + "0x513e2c28f6378762ec749cbf1efc5af8c9fcefcd2818549801a570d00d44b028", + "0x374317e49ec858921ac6d3330292abe29f149be850253a2e3054b13aeff3da72", + "0x3b14946677a76ae2c90612e597113d65651c4bebc0293a2b169a6139650ef0ca", + "0x59482b573a0dc417b7c820741624b39d9ed7b997656a8dedda08d6d27f86a31a", + "0x0de25f5cff572030d233a52bcb522084ecc4cc9e920ced2127f376ff43d8d5de" + ], + "cr": [ + "0x25096b5fe2377a1ab1184b96e6d15f76459df429e2126af404a35ac31f2a9f48", + "0x019c920847135329ee17ac5607282436b2acc28662d65739ef9c154c01f73db2", + "0x59dc47135eb2f4f8b92773098f1748ad292afbaa9773cc388c75bf1254604603", + "0x6c35d81dbc4c9d3d5fae567b89c2ffc97e19cb9150428a1148d86c1f2d71e5bb", + "0x19a1bb43a76fb302046d425e8505132ddb811fa1bc35c09afd120731badb8bec", + "0x4b4422ae2d34dba19305902d310e78c91a53c7a97f65a070fc3815c3b643cddd", + "0x0e0c25701c0bfb127869a899eff265b7a714fc74d8cb2c3c2fe4b1cf97fc7a4a", + "0x2895fa54cdf38af4fdfc8039776a80c3b41aa1c5e91664bed2fcbcfa8048ba74" + ], + "finalEvaluation": "0x110d669af3542b0a757b612ee6a83b6dd062b20579966fc7219986123753d259" + } + } + } + } + }, "block13":{ "parent": { "parent_hash": "0xb3b593ec721b3210f1d95938e52b231d22520250f7a1df018559171e843eadf4", From a003c89646f5b822ee4401a111554effff15e9aa Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 27 Jan 2024 19:55:50 +0530 Subject: [PATCH 53/75] move invalid opcode check outside jump analysis --- packages/evm/src/interpreter.ts | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index 88db4e6c74..d8a5544043 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -243,25 +243,6 @@ export class Interpreter { let opCodeObj: OpcodeMapEntry if (doJumpAnalysis) { opCode = this._runState.code[programCounter] - - // if its an invalid opcode with verkle activated, then check if its because of a missing code - // chunk in the witness, and throw appropriate error to distinguish from an actual invalid opcod - if ( - opCode === 0xfe && - this.common.isActivatedEIP(6800) && - this._runState.stateManager instanceof StatelessVerkleStateManager - ) { - const contract = this._runState.interpreter.getAddress() - if ( - !(this._runState.stateManager as StatelessVerkleStateManager).checkChunkWitnessPresent( - contract, - programCounter - ) - ) { - throw Error(`Invalid witness with missing codeChunk for pc=${programCounter}`) - } - } - // Only run the jump destination analysis if `code` actually contains a JUMP/JUMPI/JUMPSUB opcode if (opCode === 0x56 || opCode === 0x57 || opCode === 0x5e) { const { jumps, pushes, opcodesCached } = this._getValidJumpDests(this._runState.code) @@ -275,6 +256,25 @@ export class Interpreter { opCodeObj = cachedOpcodes![programCounter] opCode = opCodeObj.opcodeInfo.code } + + // if its an invalid opcode with verkle activated, then check if its because of a missing code + // chunk in the witness, and throw appropriate error to distinguish from an actual invalid opcod + if ( + opCode === 0xfe && + this.common.isActivatedEIP(6800) && + this._runState.stateManager instanceof StatelessVerkleStateManager + ) { + const contract = this._runState.interpreter.getAddress() + if ( + !(this._runState.stateManager as StatelessVerkleStateManager).checkChunkWitnessPresent( + contract, + programCounter + ) + ) { + throw Error(`Invalid witness with missing codeChunk for pc=${programCounter}`) + } + } + this._runState.opCode = opCode! try { From 89959b7da2c9b2da0b312daa6c3ebf081195875e Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 27 Jan 2024 20:03:00 +0530 Subject: [PATCH 54/75] small cleanup in runtx --- packages/vm/src/runTx.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 51f715f414..bcd96f1bf3 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,6 +1,6 @@ import { Block } from '@ethereumjs/block' import { ConsensusType, Hardfork } from '@ethereumjs/common' -import { AccessWitness, StatelessVerkleStateManager } from '@ethereumjs/statemanager' +import { StatelessVerkleStateManager } from '@ethereumjs/statemanager' import { BlobEIP4844Transaction, Capability, isBlobEIP4844Tx } from '@ethereumjs/tx' import { Account, @@ -216,11 +216,6 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { throw Error(`StatelessVerkleStateManager needed for execution of verkle blocks`) } stateAccesses = (this.stateManager as StatelessVerkleStateManager).accessWitness - } else { - // assign an empty witness to prevent unnecessary code spagetti of null/undefined checks while usage - // but its totally possible that merkle can also accumulate witnesses if such feature was to be made - // available there - stateAccesses = new AccessWitness() } let txAccesses = stateAccesses?.shallowCopy() From bb6d298805e71f1a05e4cbad5ddba0635ca9f41a Mon Sep 17 00:00:00 2001 From: harkamal Date: Mon, 29 Jan 2024 22:07:48 +0530 Subject: [PATCH 55/75] add preimages spec --- .../client/test/rpc/engine/preimages.spec.ts | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 packages/client/test/rpc/engine/preimages.spec.ts diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts new file mode 100644 index 0000000000..95c6ba22f3 --- /dev/null +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -0,0 +1,136 @@ +import { Block, BlockHeader } from '@ethereumjs/block' +import { TransactionFactory } from '@ethereumjs/tx' +import { + Withdrawal, + bytesToHex, + hexToBytes, + intToBytes, + intToHex, + setLengthRight, +} from '@ethereumjs/util' +import * as td from 'testdouble' +import { assert, describe, it } from 'vitest' + +import { blockToExecutionPayload } from '../../../src/rpc/modules/index.js' +import genesisJSON from '../../testdata/geth-genesis/kaustinen2.json' +import { getRpcClient, setupChain } from '../helpers.js' + +import type { Common } from '@ethereumjs/common' +import type { PrefixedHexString } from '@ethereumjs/util' +import type { HttpClient } from 'jayson/promise' + +const genesisStateRoot = '0x78026f1e4f2ff57c340634f844f47cb241beef4c965be86a483c855793e4b07d' +const genesisBlockHash = '0x76a519ccb8a2b12d733ad7d88e2d5f4a11d6dc6ca320edccd3b8a3e9081ca1b3' + +const originalValidate = (BlockHeader as any).prototype._consensusFormatValidation +BlockHeader.prototype['_consensusFormatValidation'] = () => {} //stub + +async function genBlockWithdrawals(blockNumber: number) { + const withdrawals = Array.from({ length: 8 }, (_v, i) => { + const withdrawalIndex = blockNumber * 16 + i + + // just return a withdrawal based on withdrawalIndex + return { + index: intToHex(withdrawalIndex), + validatorIndex: intToHex(withdrawalIndex), + address: bytesToHex(setLengthRight(intToBytes(withdrawalIndex), 20)), + amount: intToHex(withdrawalIndex), + } + }) + const withdrawalsRoot = bytesToHex( + await Block.genWithdrawalsTrieRoot(withdrawals.map(Withdrawal.fromWithdrawalData)) + ) + + return { withdrawals, withdrawalsRoot } +} + +async function runBlock( + { common, rpc }: { common: Common; rpc: HttpClient }, + runData: { + parentHash: PrefixedHexString + transactions: PrefixedHexString[] + blockNumber: PrefixedHexString + stateRoot: PrefixedHexString + receiptTrie: PrefixedHexString + } +) { + const { transactions, parentHash, blockNumber, stateRoot, receiptTrie } = runData + const txs = [] + for (const [index, serializedTx] of transactions.entries()) { + try { + const tx = TransactionFactory.fromSerializedData(hexToBytes(serializedTx), { + common, + }) + txs.push(tx) + } catch (error) { + const validationError = `Invalid tx at index ${index}: ${error}` + throw validationError + } + } + const transactionsTrie = bytesToHex(await Block.genTransactionsTrieRoot(txs)) + + const { withdrawals, withdrawalsRoot } = await genBlockWithdrawals(Number(blockNumber)) + + const headerData = { + parentHash, + number: blockNumber, + withdrawalsRoot, + transactionsTrie, + stateRoot, + receiptTrie, + } + const blockData = { header: headerData, transactions, withdrawals } + const executeBlock = Block.fromBlockData(blockData, { common }) + const executePayload = blockToExecutionPayload(executeBlock, BigInt(0)).executionPayload + const res = await rpc.request('engine_newPayloadV2', [executePayload]) + assert.equal(res.result.status, 'VALID', 'valid status should be received') + return executePayload +} + +describe(`valid verkle network setup`, async () => { + // unschedule verkle + const unschedulePragueJson = { + ...genesisJSON, + config: { ...genesisJSON.config, pragueTime: undefined }, + } + const { server, chain, common } = await setupChain(unschedulePragueJson, 'post-merge', { + engine: true, + }) + ;(chain.blockchain as any).validateHeader = () => {} + + const rpc = getRpcClient(server) + it('genesis should be correctly setup', async () => { + const res = await rpc.request('eth_getBlockByNumber', ['0x0', false]) + + const block0 = res.result + assert.equal(block0.hash, genesisBlockHash) + assert.equal(block0.stateRoot, genesisStateRoot) + }) + + const testCases = [ + { + name: 'block 1 no txs', + blockData: { + transactions: [], + blockNumber: '0x01', + stateRoot: '0xa7a1687c948aa6466cbb91d9dae6ad1fac5f7c789f392912bfdb34d492e1dc7d', + receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + }, + }, + ] as const + + let parentHash = genesisBlockHash + for (const testCase of testCases) { + const { name, blockData } = testCase + it(`run ${name}`, async () => { + const { blockHash } = await runBlock({ common, rpc }, { ...blockData, parentHash }) + parentHash = blockHash + }) + } + + it(`reset TD`, () => { + server.close() + BlockHeader.prototype['_consensusFormatValidation'] = originalValidate + td.reset() + }) +}) From 9b8a5bc84304d18d44220f0d0ee8e1980236a732 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 18 Feb 2024 15:11:32 +0530 Subject: [PATCH 56/75] build various block scenarios for preimages gen --- .../client/test/rpc/engine/preimages.spec.ts | 82 +++++++++++++++---- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts index 95c6ba22f3..a6d783dbc3 100644 --- a/packages/client/test/rpc/engine/preimages.spec.ts +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -12,6 +12,7 @@ import * as td from 'testdouble' import { assert, describe, it } from 'vitest' import { blockToExecutionPayload } from '../../../src/rpc/modules/index.js' +import blocks from '../../testdata/blocks/kaustinen2.json' import genesisJSON from '../../testdata/geth-genesis/kaustinen2.json' import { getRpcClient, setupChain } from '../helpers.js' @@ -26,17 +27,21 @@ const originalValidate = (BlockHeader as any).prototype._consensusFormatValidati BlockHeader.prototype['_consensusFormatValidation'] = () => {} //stub async function genBlockWithdrawals(blockNumber: number) { - const withdrawals = Array.from({ length: 8 }, (_v, i) => { - const withdrawalIndex = blockNumber * 16 + i - - // just return a withdrawal based on withdrawalIndex - return { - index: intToHex(withdrawalIndex), - validatorIndex: intToHex(withdrawalIndex), - address: bytesToHex(setLengthRight(intToBytes(withdrawalIndex), 20)), - amount: intToHex(withdrawalIndex), - } - }) + // if block 1, bundle 0 withdrawals + const withdrawals = + blockNumber === 1 + ? [] + : Array.from({ length: 8 }, (_v, i) => { + const withdrawalIndex = blockNumber * 16 + i + + // just return a withdrawal based on withdrawalIndex + return { + index: intToHex(withdrawalIndex), + validatorIndex: intToHex(withdrawalIndex), + address: bytesToHex(setLengthRight(intToBytes(withdrawalIndex), 20)), + amount: intToHex(withdrawalIndex), + } + }) const withdrawalsRoot = bytesToHex( await Block.genWithdrawalsTrieRoot(withdrawals.map(Withdrawal.fromWithdrawalData)) ) @@ -52,9 +57,12 @@ async function runBlock( blockNumber: PrefixedHexString stateRoot: PrefixedHexString receiptTrie: PrefixedHexString + gasUsed: PrefixedHexString + coinbase: PrefixedHexString } ) { - const { transactions, parentHash, blockNumber, stateRoot, receiptTrie } = runData + const { transactions, parentHash, blockNumber, stateRoot, receiptTrie, gasUsed, coinbase } = + runData const txs = [] for (const [index, serializedTx] of transactions.entries()) { try { @@ -78,8 +86,10 @@ async function runBlock( transactionsTrie, stateRoot, receiptTrie, + gasUsed, + coinbase, } - const blockData = { header: headerData, transactions, withdrawals } + const blockData = { header: headerData, transactions: txs, withdrawals } const executeBlock = Block.fromBlockData(blockData, { common }) const executePayload = blockToExecutionPayload(executeBlock, BigInt(0)).executionPayload const res = await rpc.request('engine_newPayloadV2', [executePayload]) @@ -107,14 +117,58 @@ describe(`valid verkle network setup`, async () => { assert.equal(block0.stateRoot, genesisStateRoot) }) + // build some testcases uses some transactions from kaustinen2 which have + // normal txs, contract fail, contract success tx, although kaustinen2 + // is verkle, but we run the tests in the merkle (pre-verkle) setup + // + // withdrawals are generated and bundled using genBlockWithdrawals util + // and for block1 are coded to return no withdrawals + // + // third consideration is for feerecipient which are added here as random + // coinbase addrs const testCases = [ { name: 'block 1 no txs', blockData: { transactions: [], blockNumber: '0x01', - stateRoot: '0xa7a1687c948aa6466cbb91d9dae6ad1fac5f7c789f392912bfdb34d492e1dc7d', + stateRoot: '0x78026f1e4f2ff57c340634f844f47cb241beef4c965be86a483c855793e4b07d', + receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + gasUsed: '0x0', + coinbase: '0x78026f1e4f2ff57c340634f844f47cb241beef4c', + }, + }, + { + name: 'block 2 having kaustinen2 block 12 txs', + blockData: { + transactions: blocks.block12.execute.transactions, + blockNumber: '0x02', + stateRoot: '0xa86d54279c8faebed72e112310b29115d3600e8cc6ff2a2e4466a788b8776ad9', + receiptTrie: '0xd95b673818fa493deec414e01e610d97ee287c9421c8eff4102b1647c1a184e4', + gasUsed: '0xa410', + coinbase: '0x9da2abca45e494476a21c49982619ee038b68556', + }, + }, + { + name: 'block 3 no txs with just withdrawals but zero coinbase', + blockData: { + transactions: [], + blockNumber: '0x03', + stateRoot: '0xe4538f9d7531eb76e82edf7480e4578bc2be5f454ab02db4d9db6187dfa1f9ca', receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + gasUsed: '0x0', + coinbase: '0x0000000000000000000000000000000000000000', + }, + }, + { + name: 'block 3 no txs with just withdrawals', + blockData: { + transactions: blocks.block13.execute.transactions, + blockNumber: '0x04', + stateRoot: '0x57e675e1d6b2ab5d65601e81658de1468afad77752a271a48364dcefda856614', + receiptTrie: '0x6a0be0e8208f625225e43681258eb9901ed753e2656f0cd6c0a3971fada5f190', + gasUsed: '0x3c138', + coinbase: '0xa874386cdb13f6cb3b974d1097b25116e67fc21e', }, }, ] as const From 9d1e9450a61cc6a795654e5c96b664add62bd471 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 18 Feb 2024 12:06:11 -0500 Subject: [PATCH 57/75] client: revert vmexecution preimages test --- .../client/test/execution/vmexecution.spec.ts | 189 +----------------- 1 file changed, 1 insertion(+), 188 deletions(-) diff --git a/packages/client/test/execution/vmexecution.spec.ts b/packages/client/test/execution/vmexecution.spec.ts index 691c8faf2b..c3b774db88 100644 --- a/packages/client/test/execution/vmexecution.spec.ts +++ b/packages/client/test/execution/vmexecution.spec.ts @@ -1,11 +1,8 @@ import { Block } from '@ethereumjs/block' import { Blockchain } from '@ethereumjs/blockchain' import { Chain as ChainEnum, Common, Hardfork } from '@ethereumjs/common' -import { keccak256 } from '@ethereumjs/devp2p' -import { LegacyTransaction } from '@ethereumjs/tx' -import { bytesToHex, equalsBytes, hexToBytes } from '@ethereumjs/util' +import { bytesToHex } from '@ethereumjs/util' import { VM } from '@ethereumjs/vm' -import { MemoryLevel } from 'memory-level' import { assert, describe, it } from 'vitest' import { Chain } from '../../src/blockchain' @@ -17,138 +14,6 @@ import blocksDataMainnet from '../testdata/blocks/mainnet.json' import testnet from '../testdata/common/testnet.json' import shanghaiJSON from '../testdata/geth-genesis/withdrawals.json' -import type { Address } from '@ethereumjs/util' - -const testGenesisBlock = { - header: { - bloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - coinbase: '0x8888f1f195afa192cfee860698584c030f4c9db1', - difficulty: '0x020000', - extraData: '0x42', - gasLimit: '0x023e38', - gasUsed: '0x00', - hash: '0xce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae', - mixHash: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - nonce: '0x0102030405060708', - number: '0x00', - parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000', - receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - stateRoot: '0xaf81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0', - timestamp: '0x54c98c81', - transactionsTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', - uncleHash: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - }, -} -const testBlock = { - header: { - bloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - coinbase: '0x8888f1f195afa192cfee860698584c030f4c9db1', - difficulty: '0x020000', - extraData: '0x', - gasLimit: '0x023ec6', - gasUsed: '0x021536', - hash: '0xf53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3', - mixHash: '0x29f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3', - nonce: '0x8957e6d004a31802', - number: '0x1', - parentHash: '0xce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1ae', - receiptTrie: '0x5c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7', - stateRoot: '0xa65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4', - timestamp: '0x56851097', - transactionsTrie: '0x70616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2', - uncleHash: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - }, - // rlp: '0xf904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0', - transactions: [ - { - data: '0x', - gasLimit: '0x55f0', - gasPrice: '0x0a', - nonce: '0x', - r: '0x575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecd', - s: '0x6baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188', - to: '0xaaaf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1c', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x01', - r: '0x4fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5b', - s: '0x17bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192e', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1b', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x02', - r: '0x04377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458ada', - s: '0x53a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1c', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x03', - r: '0x4fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615', - s: '0x651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1c', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x04', - r: '0x78e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567d', - s: '0x13254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198dd', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1b', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x05', - r: '0xa7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54', - s: '0x534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1b', - value: '0x0a', - }, - { - data: '0x', - gasLimit: '0x5208', - gasPrice: '0x0a', - nonce: '0x06', - r: '0x34bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59', - s: '0x78807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616', - to: '0xbbbf5374fce5edbc8e2a8697c15331677e6ebf0b', - v: '0x1b', - value: '0x0a', - }, - ], - uncleHeaders: [], -} - -const setBalance = async (vm: VM, address: Address, balance: bigint) => { - await vm.stateManager.checkpoint() - await vm.stateManager.modifyAccountFields(address, { balance }) - await vm.stateManager.commit() -} - describe('[VMExecution]', async () => { it('Initialization', async () => { const vm = await VM.create() @@ -213,58 +78,6 @@ describe('[VMExecution]', async () => { ) }) - it.only( - 'Test block execution with savePreimages enabled', - async () => { - const testSetupWithPreimages = async (blockchain: Blockchain) => { - const config = new Config({ - accountCache: 10000, - storageCache: 1000, - savePreimages: true, - }) - const chain = await Chain.create({ config, blockchain }) - const exec = new VMExecution({ config, chain, metaDB: new MemoryLevel() }) - await chain.open() - await exec.open() - return exec - } - - const blockchain = await Blockchain.create({ - validateBlocks: false, - validateConsensus: false, - }) - - const block = Block.fromBlockData(testBlock, { common: blockchain.common }) - await blockchain.putBlock(block) - - const exec = await testSetupWithPreimages(blockchain) - - await exec.run() - - const touchedAccounts = block.transactions.flatMap((transcation) => [ - transcation.to!.bytes, - transcation.getSenderAddress().bytes, - ]) - const touchedAccountsHashedKeys = touchedAccounts.map((address) => keccak256(address)) - - // The preimagesManager should be instantiated - assert.ok(exec.preimagesManager !== undefined, 'preimagesManager should be instantiated') - - console.log('before for of loop') - for (const [index, touchedAccount] of touchedAccounts.entries()) { - console.log('inside loop') - console.log('index: ', index) - console.log('touchedAccount', bytesToHex(touchedAccount)) - const preimage = await exec.preimagesManager!.getPreimage(touchedAccountsHashedKeys[index]) - assert.ok( - preimage !== null && equalsBytes(preimage, touchedAccount), - 'preimage should be recovered' - ) - } - }, - { timeout: 50000 } - ) - it('Should fail opening if vmPromise already assigned', async () => { const blockchain = await Blockchain.create({ validateBlocks: true, From 6aee56a78247bb6126016fc8708eb682d66b1906 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 18 Feb 2024 12:11:25 -0500 Subject: [PATCH 58/75] client: remove unnecessary boolean explicit comparison --- packages/client/src/execution/vmexecution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index 0dcdca2369..b133281fc2 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -125,7 +125,7 @@ export class VMExecution extends Execution { } ) } - if (this.config.savePreimages === true) { + if (this.config.savePreimages) { this.preimagesManager = new PreimagesManager({ chain: this.chain, config: this.config, @@ -712,7 +712,7 @@ export class VMExecution extends Execution { await this.receiptsManager?.saveReceipts(block, result.receipts) - if (this.config.savePreimages === true && this.preimagesManager !== undefined) { + if (this.config.savePreimages && this.preimagesManager !== undefined) { for (const txResult of result.results) { if (txResult.preimages === undefined) { continue From 58c8ecd6a9aadb27fa7caed25feceffeb3d908f3 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 18 Feb 2024 12:12:42 -0500 Subject: [PATCH 59/75] client: remove unused import --- packages/client/test/miner/miner.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/test/miner/miner.spec.ts b/packages/client/test/miner/miner.spec.ts index d78f5ca484..5f4cbbcf3d 100644 --- a/packages/client/test/miner/miner.spec.ts +++ b/packages/client/test/miner/miner.spec.ts @@ -1,6 +1,5 @@ import { Block, BlockHeader } from '@ethereumjs/block' import { Common, Chain as CommonChain, Hardfork } from '@ethereumjs/common' -import { keccak256 } from '@ethereumjs/devp2p' import { DefaultStateManager } from '@ethereumjs/statemanager' import { FeeMarketEIP1559Transaction, LegacyTransaction } from '@ethereumjs/tx' import { Address, equalsBytes, hexToBytes } from '@ethereumjs/util' From b7214cd2c1452e416677d9c19150b68b8528cace Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 18 Feb 2024 12:16:12 -0500 Subject: [PATCH 60/75] client: revert re-ordering --- packages/client/test/testdata/geth-genesis/kaustinen2.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/test/testdata/geth-genesis/kaustinen2.json b/packages/client/test/testdata/geth-genesis/kaustinen2.json index 26e17f1ea7..6f57267325 100644 --- a/packages/client/test/testdata/geth-genesis/kaustinen2.json +++ b/packages/client/test/testdata/geth-genesis/kaustinen2.json @@ -12,10 +12,10 @@ "berlinBlock": 0, "londonBlock": 0, "mergeNetsplitBlock": 0, - "terminalTotalDifficulty": 0, - "terminalTotalDifficultyPassed": true, "shanghaiTime": 0, "pragueTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, "proofInBlocks": true }, "alloc": { From 66b18a56f241ea91f28ee4f33d1e04a36fe9d381 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 18 Feb 2024 12:16:29 -0500 Subject: [PATCH 61/75] stateManager: support non keccak256 applied keys --- packages/statemanager/src/rpcStateManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/statemanager/src/rpcStateManager.ts b/packages/statemanager/src/rpcStateManager.ts index 41d2a571f1..676e545dad 100644 --- a/packages/statemanager/src/rpcStateManager.ts +++ b/packages/statemanager/src/rpcStateManager.ts @@ -374,8 +374,7 @@ export class RPCStateManager implements EVMStateManagerInterface { * @returns {Uint8Array} - The applied key (e.g. hashed address) */ getAppliedKey(address: Uint8Array): Uint8Array { - // TODO: Consider not hardcoding keccak256 as a hashing function? - return keccak256(address) + return this.keccakFunction(address) } /** From 80a25039240b58c638a625c4d97b35b1b7d726f6 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 21 Feb 2024 22:55:05 +0530 Subject: [PATCH 62/75] debug and persist preimages on runWithoutSetHead as well --- packages/client/src/execution/vmexecution.ts | 43 ++++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index b133281fc2..fb4c248a06 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -34,7 +34,7 @@ import { ReceiptsManager } from './receipt' import type { ExecutionOptions } from './execution' import type { Block } from '@ethereumjs/block' -import type { RunBlockOpts, TxReceipt } from '@ethereumjs/vm' +import type { RunBlockOpts, RunTxResult, TxReceipt } from '@ethereumjs/vm' export enum ExecStatus { VALID = 'VALID', @@ -426,8 +426,18 @@ export class VMExecution extends Execution { if (skipHeaderValidation) { skipBlockchain = true } + const reportPreimages = this.config.savePreimages - const result = await vm.runBlock({ clearCache, ...opts, skipHeaderValidation }) + const result = await vm.runBlock({ + clearCache, + ...opts, + skipHeaderValidation, + reportPreimages, + }) + + if (this.config.savePreimages) { + await this.savePreimages(result.results) + } receipts = result.receipts } if (receipts !== undefined) { @@ -457,6 +467,22 @@ export class VMExecution extends Execution { return true } + async savePreimages(results: RunTxResult[]) { + const preimages = [] + if (this.preimagesManager !== undefined) { + for (const txResult of results) { + if (txResult.preimages === undefined) { + continue + } + + for (const [key, preimage] of txResult.preimages) { + preimages.push(bytesToHex(preimage)) + await this.preimagesManager.savePreimage(hexToBytes(key), preimage) + } + } + } + } + /** * Sets the chain to a new head block. * Should only be used after {@link VMExecution.runWithoutSetHead} @@ -711,17 +737,8 @@ export class VMExecution extends Execution { } await this.receiptsManager?.saveReceipts(block, result.receipts) - - if (this.config.savePreimages && this.preimagesManager !== undefined) { - for (const txResult of result.results) { - if (txResult.preimages === undefined) { - continue - } - - for (const [key, preimage] of txResult.preimages) { - await this.preimagesManager.savePreimage(hexToBytes(key), preimage) - } - } + if (this.config.savePreimages) { + await this.savePreimages(result.results) } txCounter += block.transactions.length From 73c034d394b10a54ed641989e10f76c34cb6b7f2 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 21 Feb 2024 22:56:10 +0530 Subject: [PATCH 63/75] add preimages for coinbase,withdrawals to the test and fix the spec to validate them --- .../client/test/rpc/engine/preimages.spec.ts | 71 +++++++++++++++++-- packages/client/test/rpc/helpers.ts | 2 + 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts index a6d783dbc3..ffffb1482a 100644 --- a/packages/client/test/rpc/engine/preimages.spec.ts +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -8,6 +8,7 @@ import { intToHex, setLengthRight, } from '@ethereumjs/util' +import { keccak256 } from 'ethereum-cryptography/keccak.js' import * as td from 'testdouble' import { assert, describe, it } from 'vitest' @@ -103,9 +104,14 @@ describe(`valid verkle network setup`, async () => { ...genesisJSON, config: { ...genesisJSON.config, pragueTime: undefined }, } - const { server, chain, common } = await setupChain(unschedulePragueJson, 'post-merge', { - engine: true, - }) + const { server, chain, common, execution } = await setupChain( + unschedulePragueJson, + 'post-merge', + { + engine: true, + savePreimages: true, + } + ) ;(chain.blockchain as any).validateHeader = () => {} const rpc = getRpcClient(server) @@ -137,6 +143,12 @@ describe(`valid verkle network setup`, async () => { gasUsed: '0x0', coinbase: '0x78026f1e4f2ff57c340634f844f47cb241beef4c', }, + preimages: [ + // coinbase + '0x78026f1e4f2ff57c340634f844f47cb241beef4c', + // no withdrawals + // no tx accesses + ], }, { name: 'block 2 having kaustinen2 block 12 txs', @@ -148,6 +160,21 @@ describe(`valid verkle network setup`, async () => { gasUsed: '0xa410', coinbase: '0x9da2abca45e494476a21c49982619ee038b68556', }, + // add preimages for addresses accessed in txs + preimages: [ + // coinbase + '0x9da2abca45e494476a21c49982619ee038b68556', + // withdrawals + '0x2000000000000000000000000000000000000000', + '0x2100000000000000000000000000000000000000', + '0x2200000000000000000000000000000000000000', + '0x2300000000000000000000000000000000000000', + '0x2400000000000000000000000000000000000000', + '0x2500000000000000000000000000000000000000', + '0x2600000000000000000000000000000000000000', + '0x2700000000000000000000000000000000000000', + // txs + ], }, { name: 'block 3 no txs with just withdrawals but zero coinbase', @@ -159,9 +186,23 @@ describe(`valid verkle network setup`, async () => { gasUsed: '0x0', coinbase: '0x0000000000000000000000000000000000000000', }, + preimages: [ + // coinbase + '0x0000000000000000000000000000000000000000', + // withdrawals, + '0x3000000000000000000000000000000000000000', + '0x3100000000000000000000000000000000000000', + '0x3200000000000000000000000000000000000000', + '0x3300000000000000000000000000000000000000', + '0x3400000000000000000000000000000000000000', + '0x3500000000000000000000000000000000000000', + '0x3600000000000000000000000000000000000000', + '0x3700000000000000000000000000000000000000', + // no txs + ], }, { - name: 'block 3 no txs with just withdrawals', + name: 'block 4 no txs with just withdrawals', blockData: { transactions: blocks.block13.execute.transactions, blockNumber: '0x04', @@ -170,14 +211,34 @@ describe(`valid verkle network setup`, async () => { gasUsed: '0x3c138', coinbase: '0xa874386cdb13f6cb3b974d1097b25116e67fc21e', }, + preimages: [ + // coinbase + '0xa874386cdb13f6cb3b974d1097b25116e67fc21e', + // withdrawals + '0x4000000000000000000000000000000000000000', + '0x4100000000000000000000000000000000000000', + '0x4200000000000000000000000000000000000000', + '0x4300000000000000000000000000000000000000', + '0x4400000000000000000000000000000000000000', + '0x4500000000000000000000000000000000000000', + '0x4600000000000000000000000000000000000000', + '0x4700000000000000000000000000000000000000', + ], + // no txs }, ] as const let parentHash = genesisBlockHash for (const testCase of testCases) { - const { name, blockData } = testCase + const { name, blockData, preimages } = testCase it(`run ${name}`, async () => { const { blockHash } = await runBlock({ common, rpc }, { ...blockData, parentHash }) + // check the preimages are in the preimage managaer + for (const preimage of preimages) { + const hashedImage = keccak256(hexToBytes(preimage)) + const savedPreImage = await execution.preimagesManager!.getPreimage(hashedImage) + assert.equal(bytesToHex(savedPreImage), preimage) + } parentHash = blockHash }) } diff --git a/packages/client/test/rpc/helpers.ts b/packages/client/test/rpc/helpers.ts index 0c637e44ec..1ff4c267ff 100644 --- a/packages/client/test/rpc/helpers.ts +++ b/packages/client/test/rpc/helpers.ts @@ -53,6 +53,7 @@ type createClientArgs = { opened: boolean genesisState: GenesisState genesisStateRoot: Uint8Array + savePreimages: boolean } export function startRPC( methods: any, @@ -97,6 +98,7 @@ export async function createClient(clientOpts: Partial = {}) { txLookupLimit: clientOpts.txLookupLimit, accountCache: 10000, storageCache: 1000, + savePreimages: clientOpts.savePreimages, }) const blockchain = clientOpts.blockchain ?? mockBlockchain() From 8c5930294b88a69f143d1811950de4bf0ea4b7e8 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sat, 24 Feb 2024 09:04:25 -0500 Subject: [PATCH 64/75] client: fix preimage tests ts errors --- packages/client/test/rpc/engine/preimages.spec.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts index ffffb1482a..dc64164bfd 100644 --- a/packages/client/test/rpc/engine/preimages.spec.ts +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -3,6 +3,7 @@ import { TransactionFactory } from '@ethereumjs/tx' import { Withdrawal, bytesToHex, + equalsBytes, hexToBytes, intToBytes, intToHex, @@ -136,7 +137,7 @@ describe(`valid verkle network setup`, async () => { { name: 'block 1 no txs', blockData: { - transactions: [], + transactions: [] as string[], blockNumber: '0x01', stateRoot: '0x78026f1e4f2ff57c340634f844f47cb241beef4c965be86a483c855793e4b07d', receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', @@ -179,7 +180,7 @@ describe(`valid verkle network setup`, async () => { { name: 'block 3 no txs with just withdrawals but zero coinbase', blockData: { - transactions: [], + transactions: [] as string[], blockNumber: '0x03', stateRoot: '0xe4538f9d7531eb76e82edf7480e4578bc2be5f454ab02db4d9db6187dfa1f9ca', receiptTrie: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', @@ -235,9 +236,11 @@ describe(`valid verkle network setup`, async () => { const { blockHash } = await runBlock({ common, rpc }, { ...blockData, parentHash }) // check the preimages are in the preimage managaer for (const preimage of preimages) { - const hashedImage = keccak256(hexToBytes(preimage)) - const savedPreImage = await execution.preimagesManager!.getPreimage(hashedImage) - assert.equal(bytesToHex(savedPreImage), preimage) + const preimageBytes = hexToBytes(preimage) + const savedPreImage = await execution.preimagesManager!.getPreimage( + keccak256(preimageBytes) + ) + assert.ok(savedPreImage !== null && equalsBytes(savedPreImage, preimageBytes)) } parentHash = blockHash }) From 3a459fee12c96ec287cd79e6ab876cdcfbac1fae Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 25 Feb 2024 14:50:31 -0500 Subject: [PATCH 65/75] client: minor adjustments to preimage test --- packages/client/test/rpc/engine/preimages.spec.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts index dc64164bfd..522e04f285 100644 --- a/packages/client/test/rpc/engine/preimages.spec.ts +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -234,13 +234,17 @@ describe(`valid verkle network setup`, async () => { const { name, blockData, preimages } = testCase it(`run ${name}`, async () => { const { blockHash } = await runBlock({ common, rpc }, { ...blockData, parentHash }) - // check the preimages are in the preimage managaer + // check the preimages are in the preimage manager for (const preimage of preimages) { const preimageBytes = hexToBytes(preimage) - const savedPreImage = await execution.preimagesManager!.getPreimage( + const savedPreimage = await execution.preimagesManager!.getPreimage( keccak256(preimageBytes) ) - assert.ok(savedPreImage !== null && equalsBytes(savedPreImage, preimageBytes)) + assert.isNotNull(savedPreimage, `Missing preimage for ${preimage}`) + assert.ok( + savedPreimage !== null && equalsBytes(savedPreimage, preimageBytes), + `Incorrect preimage for ${preimage}` + ) } parentHash = blockHash }) From cb76436e42c1be22347fd11a2d8b96374d14b51a Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 25 Feb 2024 14:51:21 -0500 Subject: [PATCH 66/75] client: save preimages helper --- packages/client/src/execution/vmexecution.ts | 24 +++++++------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/packages/client/src/execution/vmexecution.ts b/packages/client/src/execution/vmexecution.ts index fb4c248a06..7a852451f6 100644 --- a/packages/client/src/execution/vmexecution.ts +++ b/packages/client/src/execution/vmexecution.ts @@ -34,7 +34,7 @@ import { ReceiptsManager } from './receipt' import type { ExecutionOptions } from './execution' import type { Block } from '@ethereumjs/block' -import type { RunBlockOpts, RunTxResult, TxReceipt } from '@ethereumjs/vm' +import type { RunBlockOpts, TxReceipt } from '@ethereumjs/vm' export enum ExecStatus { VALID = 'VALID', @@ -435,8 +435,8 @@ export class VMExecution extends Execution { reportPreimages, }) - if (this.config.savePreimages) { - await this.savePreimages(result.results) + if (this.config.savePreimages && result.preimages !== undefined) { + await this.savePreimages(result.preimages) } receipts = result.receipts } @@ -467,18 +467,10 @@ export class VMExecution extends Execution { return true } - async savePreimages(results: RunTxResult[]) { - const preimages = [] + async savePreimages(preimages: Map) { if (this.preimagesManager !== undefined) { - for (const txResult of results) { - if (txResult.preimages === undefined) { - continue - } - - for (const [key, preimage] of txResult.preimages) { - preimages.push(bytesToHex(preimage)) - await this.preimagesManager.savePreimage(hexToBytes(key), preimage) - } + for (const [key, preimage] of preimages) { + await this.preimagesManager.savePreimage(hexToBytes(key), preimage) } } } @@ -737,8 +729,8 @@ export class VMExecution extends Execution { } await this.receiptsManager?.saveReceipts(block, result.receipts) - if (this.config.savePreimages) { - await this.savePreimages(result.results) + if (this.config.savePreimages && result.preimages !== undefined) { + await this.savePreimages(result.preimages) } txCounter += block.transactions.length From d128cf62d1ad7005f876cbd49e59317be72a59f9 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 25 Feb 2024 14:51:48 -0500 Subject: [PATCH 67/75] vm: save preimages at the block level, new applyBlockResult type --- packages/vm/src/runBlock.ts | 30 ++++++++++++++++++++++++++++-- packages/vm/src/types.ts | 34 ++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 79b307b751..0b51457539 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -27,6 +27,7 @@ import { Bloom } from './bloom/index.js' import type { AfterBlockEvent, + ApplyBlockResult, PostByzantiumTxReceipt, PreByzantiumTxReceipt, RunBlockOpts, @@ -158,7 +159,7 @@ export async function runBlock(this: VM, opts: RunBlockOpts): Promise> + let result: ApplyBlockResult try { result = await applyBlock.bind(this)(block, opts) @@ -273,6 +274,7 @@ export async function runBlock(this: VM, opts: RunBlockOpts): Promise { // Validate block if (opts.skipBlockValidation !== true) { if (block.header.gasLimit >= BigInt('0x8000000000000000')) { @@ -365,8 +367,31 @@ async function applyBlock(this: VM, block: Block, opts: RunBlockOpts) { console.time(withdrawalsRewardsCommitLabel) } + // Add txResult preimages to the blockResults preimages + // Also add the coinbase preimage + + if (opts.reportPreimages === true) { + blockResults.preimages.set( + bytesToHex(this.evm.stateManager.getAppliedKey(block.header.coinbase.toBytes())), + block.header.coinbase.toBytes() + ) + for (const txResult of blockResults.results) { + if (txResult.preimages !== undefined) { + for (const [key, preimage] of txResult.preimages) { + blockResults.preimages.set(key, preimage) + } + } + } + } + if (this.common.isActivatedEIP(4895)) { + if (opts.reportPreimages === true) this.evm.journal.startReportingPreimages() await assignWithdrawals.bind(this)(block) + if (opts.reportPreimages === true && this.evm.journal.preimages !== undefined) { + for (const [key, preimage] of this.evm.journal.preimages) { + blockResults.preimages.set(key, preimage) + } + } await this.evm.journal.cleanup() } // Pay ommers and miners @@ -495,6 +520,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { return { bloom, gasUsed, + preimages: new Map(), receiptsRoot, receipts, results: txResults, diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index b761683ed0..768774abd4 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -283,9 +283,21 @@ export interface RunBlockOpts { } /** - * Result of {@link runBlock} + * Result of {@link applyBlock} */ -export interface RunBlockResult { +export interface ApplyBlockResult { + /** + * The Bloom filter + */ + bloom: Bloom + /** + * The gas used after executing the block + */ + gasUsed: bigint + /** + * The receipt root after executing the block + */ + receiptsRoot: Uint8Array /** * Receipts generated for transactions in the block */ @@ -295,21 +307,23 @@ export interface RunBlockResult { */ results: RunTxResult[] /** - * The stateRoot after executing the block + * Preimages mapping of the touched accounts from the block (see reportPreimages option) */ - stateRoot: Uint8Array + preimages?: Map +} + +/** + * Result of {@link runBlock} + */ +export interface RunBlockResult extends Omit { /** - * The gas used after executing the block + * The stateRoot after executing the block */ - gasUsed: bigint + stateRoot: Uint8Array /** * The bloom filter of the LOGs (events) after executing the block */ logsBloom: Uint8Array - /** - * The receipt root after executing the block - */ - receiptsRoot: Uint8Array } export interface AfterBlockEvent extends RunBlockResult { From 6bbd14f7892543474d65eef843b2679d9f93b9a5 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 25 Feb 2024 19:33:24 -0500 Subject: [PATCH 68/75] common: make getAppliedKey optional --- packages/common/src/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/src/interfaces.ts b/packages/common/src/interfaces.ts index 9ac15217c2..eecd212a0c 100644 --- a/packages/common/src/interfaces.ts +++ b/packages/common/src/interfaces.ts @@ -83,7 +83,7 @@ export interface StateManagerInterface { getProof?(address: Address, storageSlots: Uint8Array[]): Promise hasStateRoot(root: Uint8Array): Promise // only used in client shallowCopy(downlevelCaches?: boolean): StateManagerInterface - getAppliedKey(address: Uint8Array): Uint8Array + getAppliedKey?(address: Uint8Array): Uint8Array } export interface EVMStateManagerInterface extends StateManagerInterface { From 0e589de68aa6ac26599198a44ed37c4f926dd6fc Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Sun, 25 Feb 2024 19:34:06 -0500 Subject: [PATCH 69/75] evm/vm: handle optional getAppliedKey --- packages/evm/src/journal.ts | 5 +++++ packages/vm/src/runBlock.ts | 5 +++++ packages/vm/test/api/runTx.spec.ts | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/evm/src/journal.ts b/packages/evm/src/journal.ts index 5ba34b296a..8e52d8ac6f 100644 --- a/packages/evm/src/journal.ts +++ b/packages/evm/src/journal.ts @@ -100,6 +100,11 @@ export class Journal { // If preimages are being reported, add the address to the preimages map if (this.preimages !== undefined) { const bytesAddress = unprefixedHexToBytes(address) + if (this.stateManager.getAppliedKey === undefined) { + throw new Error( + 'touchAccount: stateManager.getAppliedKey can not be undefined if preimage storing is enabled' + ) + } const hashedKey = this.stateManager.getAppliedKey(bytesAddress) this.preimages.set(bytesToHex(hashedKey), bytesAddress) } diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 0b51457539..689f18885c 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -371,6 +371,11 @@ async function applyBlock(this: VM, block: Block, opts: RunBlockOpts): Promise API parameter usage/data errors', () => { const res = await vm.runTx({ tx, reportPreimages: true }) - const hashedCallerKey = vm.stateManager.getAppliedKey(caller.bytes) + const hashedCallerKey = vm.stateManager.getAppliedKey!(caller.bytes) const retrievedPreimage = res.preimages?.get(bytesToHex(hashedCallerKey)) From 1c413faa73c30b3a59cf43d06f84cceb81b173af Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 26 Feb 2024 11:09:34 +0100 Subject: [PATCH 70/75] client: add preimage doc --- packages/client/src/execution/preimage.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/client/src/execution/preimage.ts b/packages/client/src/execution/preimage.ts index e211d0a207..53ef200415 100644 --- a/packages/client/src/execution/preimage.ts +++ b/packages/client/src/execution/preimage.ts @@ -1,5 +1,11 @@ import { DBKey, MetaDBManager } from '../util/metaDBManager' +/** + * The `PreImagesManager` saves the preimages of hashed keys. This is necessary for the Verkle transition. + * A "PreImage" of a hash is whatever the input is to the hashed function. So, if one calls `keccak256(X)` with + * output `Y` then `X` is the preimage of `Y`. It thus serves to recover the input to the trapdoor hash function, + * which would otherwise not be feasible. + */ export class PreimagesManager extends MetaDBManager { /** * Returns the preimage for a given hashed key From d5a6ca8702a7199baf530388cb74f3d066402316 Mon Sep 17 00:00:00 2001 From: Scotty <66335769+ScottyPoi@users.noreply.github.com> Date: Mon, 26 Feb 2024 03:09:32 -0700 Subject: [PATCH 71/75] trie: export "Path" interface (#3292) * trie: export "Path" interface * Move over Path interface export to types for consistency --------- Co-authored-by: Holger Drewes --- packages/trie/src/trie.ts | 7 +------ packages/trie/src/types.ts | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/trie/src/trie.ts b/packages/trie/src/trie.ts index 6ced72adcb..b63036cf5b 100644 --- a/packages/trie/src/trie.ts +++ b/packages/trie/src/trie.ts @@ -37,6 +37,7 @@ import type { EmbeddedNode, FoundNodeFunction, Nibbles, + Path, Proof, TrieNode, TrieOpts, @@ -47,12 +48,6 @@ import type { OnFound } from './util/asyncWalk.js' import type { BatchDBOp, DB, PutBatch } from '@ethereumjs/util' import type { Debugger } from 'debug' -interface Path { - node: TrieNode | null - remaining: Nibbles - stack: TrieNode[] -} - /** * The basic trie interface, use with `import { Trie } from '@ethereumjs/trie'`. */ diff --git a/packages/trie/src/types.ts b/packages/trie/src/types.ts index 9aa2d96e75..5928c2ee8a 100644 --- a/packages/trie/src/types.ts +++ b/packages/trie/src/types.ts @@ -20,6 +20,12 @@ export interface CommonInterface { } } +export interface Path { + node: TrieNode | null + remaining: Nibbles + stack: TrieNode[] +} + export type FoundNodeFunction = ( nodeRef: Uint8Array, node: TrieNode | null, From 92ac2583106be2742f40899a227a582fb9d1b9fc Mon Sep 17 00:00:00 2001 From: Scorbajio Date: Mon, 26 Feb 2024 06:16:18 -0700 Subject: [PATCH 72/75] Snap sync: use zero-element proof for checking validity of final, empty range result (#3047) * Use no-elements proof for final check in account fetcher * Use no-elements proof for final check in storage fetcher * Check inputs after zero element proof code section * Cleanup * Reject peer if zero-element proof fails * Add tests for zero-element proof * Remove proofTrie usage * Use hashing function in static version of verifyRangeProof * Include useKeyHashing in call to fromProof so that hashing function is used in proof verification * Use appliedKey for hashing function instead of the function directly passed in TrieOpts * Pass in hashing function for use in static proof verification calls * Fix static range proof verification errors * Use custom hashing function from opts if available * Add test to check if zero element range proof verification fails with remaining elements to the right * Check if parameters are as expected for zero-element proof * Fix linting issues --------- Co-authored-by: Scotty <66335769+ScottyPoi@users.noreply.github.com> Co-authored-by: Holger Drewes Co-authored-by: Indigo Alpha --- .../client/src/sync/fetcher/accountfetcher.ts | 20 +++- .../client/src/sync/fetcher/storagefetcher.ts | 22 +++- .../test/sync/fetcher/accountfetcher.spec.ts | 82 ++++++++++++++ .../test/sync/fetcher/storagefetcher.spec.ts | 101 +++++++++++++++--- packages/trie/src/proof/range.ts | 39 ++++--- packages/trie/src/trie.ts | 5 +- 6 files changed, 232 insertions(+), 37 deletions(-) diff --git a/packages/client/src/sync/fetcher/accountfetcher.ts b/packages/client/src/sync/fetcher/accountfetcher.ts index 801f6b4842..79c9c48adc 100644 --- a/packages/client/src/sync/fetcher/accountfetcher.ts +++ b/packages/client/src/sync/fetcher/accountfetcher.ts @@ -395,8 +395,26 @@ export class AccountFetcher extends Fetcher rangeResult.accounts.length === 0 || equalsBytes(limit, bigIntToBytes(BIGINT_2EXP256)) === true ) { - // TODO have to check proof of nonexistence -- as a shortcut for now, we can mark as completed if a proof is present + // check zero-element proof if (rangeResult.proof.length > 0) { + try { + const isMissingRightRange = await Trie.verifyRangeProof( + this.root, + origin, + null, + [], + [], + rangeResult.proof, + { useKeyHashingFunction: keccak256 } + ) + // if proof is false, reject corrupt peer + if (isMissingRightRange !== false) return undefined + } catch (e) { + this.debug(e) + // if proof is false, reject corrupt peer + return undefined + } + this.debug(`Data for last range has been received`) // response contains empty object so that task can be terminated in store phase and not reenqueued return Object.assign([], [Object.create(null)], { completed: true }) diff --git a/packages/client/src/sync/fetcher/storagefetcher.ts b/packages/client/src/sync/fetcher/storagefetcher.ts index 66ca10a9b7..ed173499b4 100644 --- a/packages/client/src/sync/fetcher/storagefetcher.ts +++ b/packages/client/src/sync/fetcher/storagefetcher.ts @@ -269,9 +269,27 @@ export class StorageFetcher extends Fetcher 0) { + try { + const isMissingRightRange = await Trie.verifyRangeProof( + task.storageRequests[0].storageRoot, + origin, + null, + [], + [], + rangeResult.proof, + { useKeyHashingFunction: keccak256 } + ) + + // if proof is false, reject corrupt peer + if (isMissingRightRange !== false) return undefined + } catch (e) { + this.debug(e) + // if proof is false, reject corrupt peer + return undefined + } + this.debug(`Empty range was requested - Terminating task`) // response contains empty object so that task can be terminated in store phase and not reenqueued return Object.assign([], [Object.create(null) as any], { completed: true }) diff --git a/packages/client/test/sync/fetcher/accountfetcher.spec.ts b/packages/client/test/sync/fetcher/accountfetcher.spec.ts index ef589aa9ac..3f492b9a21 100644 --- a/packages/client/test/sync/fetcher/accountfetcher.spec.ts +++ b/packages/client/test/sync/fetcher/accountfetcher.spec.ts @@ -1,4 +1,5 @@ import { RLP } from '@ethereumjs/rlp' +import { Trie } from '@ethereumjs/trie' import { bytesToBigInt, hexToBytes } from '@ethereumjs/util' import * as td from 'testdouble' import { assert, describe, it, vi } from 'vitest' @@ -15,6 +16,18 @@ import { wait } from '../../integration/util' export const _accountRangeRLP = '0xf90b7c01f88aeda0000001907a67cf7ece54c42262997b2f19041a4d99466b94b8c12f225827e239cb80872386f26fc100008080eda00000107c642e29a6b613205c923ac3a4cf0cf1704ae9a8bef2784caba060f4b7cb07870e22e1219054118080eda000001d26422787b6d40c0c0c2df85757c5ad4a3e367831e932fa24f34da43d57cb80872386f26fc100008080f90aecb90214f90211a0b3f22b069c398ded55d4ce421b06f6b4d5e13cb53ad1c6220276b2b3a078937ba08a54e492e7b9ef911b4a299487a12390ccd81a087398af7106e00b81a791868da0a323a93f5791d4c39e1496e4856f9233e5e86070c722efde613219aca834bde3a0d8c11a8fc2eba0b47de9d5b207b702a8bd62609e9c2504aaa444fd2e98e31deaa0dbfc625e370fa89cb7b123550ef6fd637687b9e9a7c8556bd41bcd4226226095a094fe5f6ac37c805917beefa220d7c6b3bd50848322f6342e940cc047c9b6a8ffa074af7e57b9c59e06a2e478610d56ab39004cda3109cfd953dc8b1d168c453cbca0d58f31d0ecce773d610aa5d12f7cc2f4ca992db4ce2e154c13a12cb4bb567816a0b26a7d9776165bb52e793df6a77d4032164d788bf9954c9cac289ea0786da2fda043804bd146f583b183dc267b36bbe55f63daa36fd6cbdafce48ce451a444b4eca0fc724e8bb65724450eb3966d8672330c8e49a94c6ceaed06174a2322aafee105a02ccb0445b0a4028f167e425b57cb9462cc6caceda0c3cfb5363f08614314a77ca0c64db3edb50609b6de331f00ba1f455113d1388e9eb5f50f5420983012d62b7da0168c680c03ef3fbcc36a6c1ddd9bf7d46b5fd5ee34dd7048320223c8bbe412f9a05747d2eb930bffce317c253e3889a7db57c87dcc55f1f1f77b3d02fc82bc6bcfa0997073e1664f9cbbcfd968277856596c325a6b83887f4ad007c3b93e1133c65280b90214f90211a0b3e6ec5fa09062b280599994d38261cae87ab198ed1b3a7d7003a277ffc735dfa01bac91007228f4fa15ac9c2a4822b7d4103eafae61dd3db30eb830e31de9cddfa0809973bebc62f48fb834336800b1ce8e1b2128ee5824645464b6c09ddd381578a0f8d54e19e888fc01cd5069bfcddb7ee78a4afdec24aa03822d9fd5356a3c109fa08a61ea95c616906799398778b28f0e8a19f6569f885e4b4f1192f3e9f690cefea09aa53cd259b1df9650222dc285236399da685b7350312a3ac0a07a86bef64d5ea01596637937233489a70e114c23818e3512b3c2abf621d142c14a9b9a3afb09d1a0e8a8bcda78ae77bee956389dff38a10c8c1565bc1a85064da6cd8ba606b9aa35a04ae4b4bfbfb97f5b4e178f8c30a6d93ffd6614c8b4d0b44df31b653a3a1e4f0fa0a4e3413e6ee6c5886ed346827ee0cce05a8e4f799b005aacf002a17e6d93e5aaa09a3e6d344bbd2496bf8fa84abc96a3d5f363ba03103edff2164244bb020c52a2a0998f39835105197f860930b46adad4527f5a9ef31c4744476718b910ffc5e586a01cec4592958b5aefe25bea6a49a11089e798d96aebc2be7fce0f1772146d18aea0d7c178ed5bcf822d22f9ed3ca8c95e5144ee0a9fbae901b21da002e2c3c0415ea0a9d5c5c67326f4154449575827ab68ea47c7c8931490160a7a299f829a670476a074814ffe69da7e253de29fc7d5eb57291a67bd6f16cb52175106b7cbd3b19c8f80b90214f90211a0947eec1b645849d129fb8c65cd06bd52526fb2399d1660ee5108fc4698e809aaa02735f6cbb0e10514b1515826ae1c539850543dbe162badaf2efa51b1a353ca1ca0fde2642bcc8db8d6d6e42731eeae2045fc30b84c6efdc420ce8cee5d537b648fa071e7887ca31ae375838ceeed57165f5592a9e6cae9beb070e92a4f5d5aec5014a0f81f4b4d5e2c52373b8884b398838941df0b16177aa4ea8494b183176cf7d526a0dc6ecec073532c8f9581ece75cb4eea83a40ba0210cc10ef0fd8b27a102a028fa0426f18f1de1bc9b665e9efb45d6547e88e35a267d7ec9197ae97052d1be59ab9a0d6aad68bece934d578e18eb3acd147490bc6cc01e646f1d8618a747526eae4f5a04ffee6f8660794981b15fda1ceafef98db853bfc31c029db7cb515bb34bb5572a0da2497fed45626b94c1eb910c9eedc9c26a4ff5b56b709b96d5a567991ebe2aca021b3bfcd8aa97eb8d9a3ce258389603564f01d6f485899a9f6e0a00d85dc00dfa0339e45f0407ad527a899a2e06e17330c2cfe25b81689dcffd20c166ef256fbc6a0dafd25416aaf44a8bfa1a6bf2b0cc563f9be84b9b3b8bf307983252d7cd63c51a0191504034adb55fe0926c7c4066654739af3e1c9c4173f4d90fa2e1df62a99cca0504e2144c1a889e48cd5a6baa17e39b6a176dbf41147dd171f2673c5c9d849dba04850f33ad929cb1a07136f162e33a5df0f65c48f359637774e7c8ebabe90eb7080b90214f90211a05d16e93a6e58a13a7c7dde40d0c543b9d63d029ec0da5efb4be34cd4ce672181a089cbb0e940fb7bb395091e3b665755be6b51292fba7a7bc39904568c63a907e1a050314b93f73fed553cd9dee63dc1fe9b789f9b9e111a659ff4e4c91c8167a63ca04444bd2a1bb78a83b66a36a09076b2b49eade4e2e8c8ef91538117525893841aa0abde6220817f3608bdfec46ebed292c464ee1d2c58d0b43286b8617bb4cb49d9a07257eff6aebb380db4c75752a84c6b2d0bb86bb190cef2a58829497997262b6aa0a0d4ab9d93be97287f29637a9b16fb8a6c8cd3bc29786b64343113b95a4153ffa0f0d479377ce4c0f31185c45319f915532cea13e97d5abfc939b75b642b5b47bba0eb96a911347f5321e03f1602a041ce82ec29bb4b322faa9f999cf02bb0c7a932a047b6c76ffeb29b4e3c3c09749289213395c8b0126dbd8acee45c6d32d2a0ab5fa0ca462e8ff237f9e56698ca416fac835ed37bc90683d363effe7ec9dacb4963fba0d385f828becce3665e070b645df25dec507a7c6c3813591e3436147be0becc75a0537a7451522228feca0ceb55374615e8396229e1c7a6b0ae16fb49cd8e6ed7a9a0b96561ab484f67b604d2dc46ac170750b321334aabcfb6b212a906e1cb5b3532a09f64f7c76e201d48b4bc1fb02f7e052a5a1bf05b2c59f3c969c8d2d6b373b3dca0398a988af30676952fcf1a968ac530b30dbe32922efe8c27acb9025adcaf1a5180b90134f90131a0b2151043be015f98b1b249180bfac505781022ede708f533f373b2d612837df7a0031e6ffe32d313f0cd57b4bebbf6fcacf83c366157846040108d198129d99a5aa0bfca4f79ac9eb24bcbdbd94fc49c0ca30a6399a2071e4ab3024e1aae0159a31180808080a0f1a2c911436f5bf1aa936e140b17399f7c092ad64a8ab839057a67fc6923a318a0e648ced926c977b0dcc17452361ac43e53f839b8e485a288e93fb667573ae088a0808107d197eb28741f8cec92b6fa76957fa6928b00f4b7301d464809519258098080a02c7ac441b072bbe33030110dccfdda0de6705c4bdb2c94594e10c2fb8687c41080a0162e8104a86bd043ca2fac0c5d56181127c7b24f6c10fefb90c27064b4edeff8a0376bcbdd3b7503a144b9016159b7e2cd074c9566b843cb834123057c61adbd2e80b870f86e9e31907a67cf7ece54c42262997b2f19041a4d99466b94b8c12f225827e239b84df84b80872386f26fc10000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470b873f871a0a75a6fa397f39292a3bb4fdb84463908c473bad9a0206bd00964adabd7a4b589808080808080808080808080a0ea5b9774dfc3fd50b359b86fa49a57fce0186593cf89d865e279413b63947bed80a0a0747bb1023533b4f9cdaa7c845609975d413348fc5f185a120037dccdf3584c80b870f86e9e2026422787b6d40c0c0c2df85757c5ad4a3e367831e932fa24f34da43d57b84df84b80872386f26fc10000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' +export const _zeroElementProofRoot = hexToBytes( + '0xe794e45a596856bcd5412788f46752a559a4aa89fe556ab26a8c2cf0fc24cb5e' +) +export const _zeroElementProofOrigin = bytesToBigInt( + hexToBytes('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa') +) +export const _zeroElementProof = [ + '0xf90211a07d363fdc4ad4413321005a1981d415a872aed14651c159bea575d713fb1d1fd8a0d51e3a39747ab080d602e8dff07ed7fdf18fd5dd480b85ec8d5ebd86475481fba0382fbb965c19798b116e1b32ad64d99bdf09f8f4ed4c83e1b388ffad0ee8bc62a02ff7448b0092b7926a01bbb4f72e6f38366fdf109f3e9f8ac0794af3dc0e3de4a05db544523b1c10f8aead4252bff05665b8c7d21f02a102b51ac79acb6b3d2854a0cb0c46c37d6b44be6ff2204c4f4cea393099fefeae88cf5aa88195da74cca13fa0b459b6b3672dab2bb058e561761a0838e349d1dd1292dda31245e8404ec844eaa082cbce67bd082cb430296662fb1f32aabe866dee947970877abaf4233eb0fb48a0828820316cc02bfefd899aba41340659fd06df1e0a0796287ec2a4110239f6d2a0be88e4724326382a8b56e2328eeef0ad51f18d5bae0e84296afe14c4028c4af9a0c14e9060c6b3784e35b9e6ae2ad2984142a75910ccc89eb89dc1e2f44b6c58c2a091467954490d127631d2a2f39a6edabd702153de817fe8da2ab9a30513e5c6dda01c00f6abbb9bcb3ae9b12c887bc3ea3b13dba33a5dbad455c24778fa7d3ab01ea0899f71abb18c6c956118bf567fac629b75f7e9526873e429d3d8abb6dbb58021a00fd717235298742623c0b3cafb3e4bd86c0b5ab1f71097b4dd19f3d6925d758da011e10e11fa54a847669b26adaf1b5cbe7736eafde6c552b9b6158fe12307e60680', + '0xf90131a0e90a923d3266758f74651084eef91d4d62a6eece11d6bc9724f2b6eef20aaac180808080a07ee878af944ffe26ce5c64042dcc79df748286de580e561107594449d8ed516fa0eb748aae6c0c30fc952f9caa1cd5753bc220e571fdd3eb87f90016b4ee1b0d388080a05f4ca08c32e4a3997d0e94d8946e3d361ec5d0225d9cd85c6de8d572bb0a99c980a0faecf459527318d12fee2db8d85c54fc244d0207ba336a01e397593b801ae61fa0d9b3608f7e3498ffe810563f0c0925bea0287cdea57ea1f3ae29af45a192667fa0ca2e251e82502284289d0066710469330d9ec45890680a0909cf47f06c15855ea06585b163fb3bcf2bb1643d73e26170b6849097a9544b6ed6c6aba86397200297a00844a6824efe874b61c480f88d1b0639780aa16aefbad5647403fc7ea6c274b280', + '0xf869a020fa0eae268038cfa984647a1d0635beb86eda9fb7b500688f3189520cfa9ee5b846f8448001a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', +].map((e) => hexToBytes(e)) + describe('[AccountFetcher]', async () => { class PeerPool { idle() {} @@ -235,6 +248,75 @@ describe('[AccountFetcher]', async () => { await fetcher.request(job as any) }) + it('should verify zero-element proof correctly', async () => { + const config = new Config({ transports: [], accountCache: 10000, storageCache: 1000 }) + const pool = new PeerPool() as any + const fetcher = new AccountFetcher({ + config, + pool, + root: _zeroElementProofRoot, + first: _zeroElementProofOrigin, + count: BigInt(2) ** BigInt(256) - BigInt(1), + }) + const task = { count: BigInt(2) ** BigInt(256) - BigInt(1), first: _zeroElementProofOrigin } + const mockedGetAccountRange = td.func() + td.when(mockedGetAccountRange(td.matchers.anything())).thenReturn({ + reqId: BigInt(1), + accounts: [], + proof: _zeroElementProof, + }) + const peer = { + snap: { getAccountRange: mockedGetAccountRange }, + id: 'random', + address: 'random', + } + const job = { peer, task } + + const ret = await fetcher.request(job as any) + assert.ok( + ret?.completed === true, + 'should handle peer that is signaling that an empty range has been requested with no elements remaining to the right' + ) + }) + + it('should reject zero-element proof if elements still remain to right of requested range', async () => { + const config = new Config({ transports: [], accountCache: 10000, storageCache: 1000 }) + const pool = new PeerPool() as any + + // calculate new root with a key all the way to the right of the trie + const trie = await Trie.createFromProof(_zeroElementProof) + await trie.put(hexToBytes('0x' + 'F'.repeat(32)), hexToBytes('0x' + '123'), true) + const newRoot = trie.root() + + const fetcher = new AccountFetcher({ + config, + pool, + root: newRoot, + first: _zeroElementProofOrigin, + count: BigInt(2) ** BigInt(256) - BigInt(1), + }) + const task = { count: BigInt(2) ** BigInt(256) - BigInt(1), first: _zeroElementProofOrigin } + + const mockedGetAccountRange = td.func() + td.when(mockedGetAccountRange(td.matchers.anything())).thenReturn({ + reqId: BigInt(1), + accounts: [], + proof: _zeroElementProof, + }) + const peer = { + snap: { getAccountRange: mockedGetAccountRange }, + id: 'random', + address: 'random', + } + const job = { peer, task } + + const ret = await fetcher.request(job as any) + assert.ok( + ret?.completed === undefined, + 'proof verification should fail if elements still remain to the right of the proof' + ) + }) + it('should verify proof correctly', async () => { const config = new Config({ accountCache: 10000, storageCache: 1000 }) const chain = await Chain.create({ config }) diff --git a/packages/client/test/sync/fetcher/storagefetcher.spec.ts b/packages/client/test/sync/fetcher/storagefetcher.spec.ts index 3f157d7766..911ca8a24a 100644 --- a/packages/client/test/sync/fetcher/storagefetcher.spec.ts +++ b/packages/client/test/sync/fetcher/storagefetcher.spec.ts @@ -1,4 +1,5 @@ import { RLP } from '@ethereumjs/rlp' +import { Trie } from '@ethereumjs/trie' import { hexToBytes } from '@ethereumjs/util' import { utf8ToBytes } from 'ethereum-cryptography/utils' import { assert, describe, it, vi } from 'vitest' @@ -8,7 +9,12 @@ import { Config } from '../../../src/config' import { SnapProtocol } from '../../../src/net/protocol' import { wait } from '../../integration/util' -import { _accountRangeRLP } from './accountfetcher.spec' +import { + _accountRangeRLP, + _zeroElementProof, + _zeroElementProofOrigin, + _zeroElementProofRoot, +} from './accountfetcher.spec' const _storageRangesRLP = '0xf83e0bf83af838f7a0290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639594053cd080a26cb03d5e6d2956cebb31c56e7660cac0' @@ -295,23 +301,12 @@ describe('[StorageFetcher]', async () => { const job = { peer, partialResult, task } await fetcher.request(job as any) - peer.snap.getStorageRanges = vi.fn().mockReturnValueOnce({ - reqId, - slots: [], - proof: [new Uint8Array()], - }) - let ret = await fetcher.request(job as any) - assert.ok( - ret?.completed === true, - 'should handle peer that is signaling that an empty range has been requested with no elements remaining to the right' - ) - peer.snap.getStorageRanges = vi.fn().mockReturnValueOnce({ reqId, slots: slots + [new Uint8Array()], proof, }) - ret = await fetcher.request(job as any) + let ret = await fetcher.request(job as any) assert.notOk(ret, "Reject the response if the hash sets and slot sets don't match") peer.snap.getStorageRanges = vi.fn().mockReturnValueOnce({ @@ -323,6 +318,86 @@ describe('[StorageFetcher]', async () => { assert.notOk(ret, 'Should stop requesting from peer that rejected storage request') }) + it('should verify zero-element proof correctly', async () => { + const config = new Config({ transports: [], accountCache: 10000, storageCache: 1000 }) + const pool = new PeerPool() as any + const fetcher = new StorageFetcher({ + config, + pool, + root: _zeroElementProofRoot, + }) + const task = { + storageRequests: [ + { + accountHash: hexToBytes('0x0'), + storageRoot: _zeroElementProofRoot, + first: _zeroElementProofOrigin, + count: BigInt(2) ** BigInt(256) - BigInt(1), + }, + ], + } + const mockedGetStorageRanges = vi.fn().mockReturnValueOnce({ + reqId: BigInt(1), + slots: [], + proof: _zeroElementProof, + }) + const peer = { + snap: { getStorageRanges: mockedGetStorageRanges }, + id: 'random', + address: 'random', + } + const job = { peer, task } + + const ret = await fetcher.request(job as any) + assert.ok( + ret?.completed === true, + 'should handle peer that is signaling that an empty range has been requested with no elements remaining to the right' + ) + }) + + it('should reject zero-element proof if elements still remain to right of requested range', async () => { + const config = new Config({ transports: [], accountCache: 10000, storageCache: 1000 }) + const pool = new PeerPool() as any + + // calculate new root with a key all the way to the right of the trie + const trie = await Trie.createFromProof(_zeroElementProof) + await trie.put(hexToBytes('0x' + 'F'.repeat(32)), hexToBytes('0x' + '123'), true) + const newRoot = trie.root() + + const fetcher = new StorageFetcher({ + config, + pool, + root: _zeroElementProofRoot, + }) + const task = { + storageRequests: [ + { + accountHash: hexToBytes('0x0'), + storageRoot: newRoot, + first: _zeroElementProofOrigin, + count: BigInt(2) ** BigInt(256) - BigInt(1), + }, + ], + } + const mockedGetStorageRanges = vi.fn().mockReturnValueOnce({ + reqId: BigInt(1), + slots: [], + proof: _zeroElementProof, + }) + const peer = { + snap: { getStorageRanges: mockedGetStorageRanges }, + id: 'random', + address: 'random', + } + const job = { peer, task } + + const ret = await fetcher.request(job as any) + assert.ok( + ret?.completed === undefined, + 'proof verification should fail if elements still remain to the right of the proof' + ) + }) + it('should verify proof correctly', async () => { const config = new Config({ accountCache: 10000, storageCache: 1000 }) const chain = await Chain.create({ config }) diff --git a/packages/trie/src/proof/range.ts b/packages/trie/src/proof/range.ts index ce7277ba3a..af7938269d 100644 --- a/packages/trie/src/proof/range.ts +++ b/packages/trie/src/proof/range.ts @@ -322,7 +322,10 @@ async function verifyProof( proof: Uint8Array[], useKeyHashingFunction: HashKeysFunction ): Promise<{ value: Uint8Array | null; trie: Trie }> { - const proofTrie = await Trie.fromProof(proof, { root: rootHash, useKeyHashingFunction }) + const proofTrie = await Trie.fromProof(proof, { + root: rootHash, + useKeyHashingFunction, + }) try { const value = await proofTrie.get(key, true) return { @@ -443,28 +446,30 @@ export async function verifyRangeProof( return false } + if (proof !== null && firstKey !== null && lastKey === null) { + // Zero element proof + if (keys.length === 0) { + const { trie, value } = await verifyProof( + rootHash, + nibblestoBytes(firstKey), + proof, + useKeyHashingFunction + ) + + if (value !== null || (await hasRightElement(trie, firstKey))) { + throw new Error('invalid zero element proof: value mismatch') + } + + return false + } + } + if (proof === null || firstKey === null || lastKey === null) { throw new Error( 'invalid all elements proof: proof, firstKey, lastKey must be null at the same time' ) } - // Zero element proof - if (keys.length === 0) { - const { trie, value } = await verifyProof( - rootHash, - nibblestoBytes(firstKey), - proof, - useKeyHashingFunction - ) - - if (value !== null || (await hasRightElement(trie, firstKey))) { - throw new Error('invalid zero element proof: value mismatch') - } - - return false - } - // One element proof if (keys.length === 1 && nibblesCompare(firstKey, lastKey) === 0) { const { trie, value } = await verifyProof( diff --git a/packages/trie/src/trie.ts b/packages/trie/src/trie.ts index b63036cf5b..a47b458bc8 100644 --- a/packages/trie/src/trie.ts +++ b/packages/trie/src/trie.ts @@ -207,10 +207,7 @@ export class Trie { keys.map((k) => k).map(bytesToNibbles), values, proof, - opts?.useKeyHashingFunction ?? - ((msg) => { - return msg - }) + opts?.useKeyHashingFunction ?? keccak256 ) } From e3843bc3a74036f9b35233a2cf271225d2b58f3c Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:02:03 -0500 Subject: [PATCH 73/75] Integrate `kzg-wasm` into monorepo (#3294) * Update to official trusted setup * Remove devnet6 * Add kzg-wasm * Update block tests to use kzg-wasm * Update tests * Add more 4844 tests to browser run * Initial integration of kzg-wasm on git * Update kzg-wasm build * Fix linter weirdness * Move initKzg to `runTests` * Fix tests * More cleanup * Goodbye c-kzg * fix kzg references * Replace c-kzg with kzg-wasm in package.json * Update kzg wasm commit and vm tester config * Update initKzg to createKZG * fix copy pasta * Fix more copy pasta * update kzg-wasm to npm release * One last bit of copy pasta * Address feedback * client: remove try/catch blocks createKZG() and remove the initKZG stale comment --------- Co-authored-by: Jochem Brouwer --- package-lock.json | 65 +- package.json | 4 + packages/block/examples/4844.ts | 5 +- packages/block/package.json | 2 +- packages/block/test/eip4844block.spec.ts | 410 ++++---- .../block/test/from-beacon-payload.spec.ts | 33 +- packages/block/vitest.config.browser.ts | 6 +- packages/client/bin/cli.ts | 6 +- .../devnets/4844-interop/tools/txGenerator.ts | 18 +- packages/client/package.json | 2 +- .../client/test/miner/pendingBlock.spec.ts | 16 +- .../test/rpc/engine/getPayloadV3.spec.ts | 10 +- .../client/test/rpc/engine/kaustinen2.spec.ts | 10 +- .../newPayloadV3VersionedHashes.spec.ts | 10 +- .../test/rpc/eth/getBlockByNumber.spec.ts | 9 +- .../rpc/eth/getTransactionReceipt.spec.ts | 11 +- .../test/rpc/eth/sendRawTransaction.spec.ts | 11 +- packages/client/test/sim/txGenerator.ts | 4 +- packages/common/examples/initKzg.ts | 21 +- packages/evm/package.json | 2 +- packages/evm/test/blobVersionedHashes.spec.ts | 6 +- .../precompiles/0a-pointevaluation.spec.ts | 120 +-- packages/evm/vitest.config.browser.ts | 4 +- packages/tx/examples/blobTx.ts | 59 +- packages/tx/examples/initKzg.ts | 27 +- packages/tx/package.json | 9 +- packages/tx/test/eip4844.spec.ts | 971 +++++++++--------- packages/tx/vitest.config.browser.ts | 5 +- packages/util/package.json | 10 +- packages/vm/package.json | 1 - .../api/EIPs/eip-2565-modexp-gas-cost.spec.ts | 5 +- .../vm/test/api/EIPs/eip-4844-blobs.spec.ts | 148 ++- packages/vm/test/api/runTx.spec.ts | 14 +- packages/vm/test/tester/config.ts | 24 +- packages/vm/test/tester/index.ts | 6 +- packages/vm/vite.config.ts | 3 + 36 files changed, 1018 insertions(+), 1049 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8c93114488..7c2995cc31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "eslint-plugin-prettier": "4.2.1", "eslint-plugin-simple-import-sort": "7.0.0", "eslint-plugin-sonarjs": "0.19.0", + "kzg-wasm": "^0.1.0", "lint-staged": "13.0.3", "lockfile-lint-api": "^5.5.1", "prettier": "2.7.1", @@ -56,6 +57,9 @@ "@vitest/browser": { "optional": true }, + "kzg-wasm": { + "optional": true + }, "playwright": { "optional": true }, @@ -4435,14 +4439,6 @@ "node": ">=14.0.0" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -4648,16 +4644,6 @@ "node": ">= 0.8" } }, - "node_modules/c-kzg": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/c-kzg/-/c-kzg-2.1.2.tgz", - "integrity": "sha512-QmP4vTp5H2hN4mkKXF9VXtZ7k7oH1kmBxLiFT/7LcyE78RgX32zvPGfwtRAsrq/b3T6RZFIsHZvQEN7JdzoNOg==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^5.0.0" - } - }, "node_modules/c8": { "version": "7.12.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", @@ -7529,11 +7515,6 @@ "moment": "^2.29.1" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -9417,6 +9398,11 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, + "node_modules/kzg-wasm": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/kzg-wasm/-/kzg-wasm-0.1.0.tgz", + "integrity": "sha512-K0Y0qmpyc/fhW5Xn8UMh20armhuzgerTZfyx4S75dqD+bpTbeJt6rTWwILgFZ34Bc8VgvuMmG4RGhMocEvwkCw==" + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -10690,11 +10676,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" - }, "node_modules/node-dir": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", @@ -15689,7 +15670,7 @@ "ethereum-cryptography": "^2.1.3" }, "devDependencies": { - "c-kzg": "^2.1.2" + "kzg-wasm": "^0.1.0" }, "engines": { "node": ">=18" @@ -15740,7 +15721,6 @@ "@polkadot/wasm-crypto": "^7.3.2", "abstract-level": "^1.0.3", "body-parser": "^1.19.2", - "c-kzg": "^2.1.2", "chalk": "^4.1.2", "connect": "^3.7.0", "cors": "^2.8.5", @@ -15751,6 +15731,7 @@ "jayson": "^4.0.0", "js-sdsl": "^4.4.0", "jwt-simple": "^0.5.6", + "kzg-wasm": "^0.1.0", "level": "^8.0.0", "memory-level": "^1.0.0", "multiaddr": "^10.0.1", @@ -16079,7 +16060,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", - "c-kzg": "^2.1.2", + "kzg-wasm": "^0.1.0", "level": "^8.0.0", "memory-level": "^1.0.0", "minimist": "^1.2.5", @@ -16182,19 +16163,12 @@ "devDependencies": { "@types/minimist": "^1.2.0", "@types/node-dir": "^0.0.34", + "kzg-wasm": "^0.1.0", "minimist": "^1.2.0", "node-dir": "^0.1.16" }, "engines": { "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } } }, "packages/util": { @@ -16205,17 +16179,11 @@ "@ethereumjs/rlp": "^5.0.2", "ethereum-cryptography": "^2.1.3" }, - "devDependencies": {}, + "devDependencies": { + "kzg-wasm": "^0.1.0" + }, "engines": { "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } } }, "packages/verkle": { @@ -16256,7 +16224,6 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", - "c-kzg": "^2.1.2", "minimist": "^1.2.5", "node-dir": "^0.1.17", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 127614adc4..92c2490cb6 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "eslint-plugin-prettier": "4.2.1", "eslint-plugin-simple-import-sort": "7.0.0", "eslint-plugin-sonarjs": "0.19.0", + "kzg-wasm": "^0.1.0", "lint-staged": "13.0.3", "lockfile-lint-api": "^5.5.1", "prettier": "2.7.1", @@ -66,6 +67,9 @@ }, "@vitest/browser": { "optional": true + }, + "kzg-wasm": { + "optional": true } }, "engines": { diff --git a/packages/block/examples/4844.ts b/packages/block/examples/4844.ts index 8a84183d87..8c1ae64296 100644 --- a/packages/block/examples/4844.ts +++ b/packages/block/examples/4844.ts @@ -2,11 +2,12 @@ import { Common, Chain, Hardfork } from '@ethereumjs/common' import { Block } from '@ethereumjs/block' import { BlobEIP4844Transaction } from '@ethereumjs/tx' import { Address, initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { randomBytes } from 'crypto' const main = async () => { - initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') + const kzg = await createKZG() + initKZG(kzg, '') const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Cancun, diff --git a/packages/block/package.json b/packages/block/package.json index 6f647e7c86..bf4a6eebe4 100644 --- a/packages/block/package.json +++ b/packages/block/package.json @@ -54,7 +54,7 @@ "ethereum-cryptography": "^2.1.3" }, "devDependencies": { - "c-kzg": "^2.1.2" + "kzg-wasm": "^0.1.0" }, "engines": { "node": ">=18" diff --git a/packages/block/test/eip4844block.spec.ts b/packages/block/test/eip4844block.spec.ts index 56ae64199e..2847fa79ec 100644 --- a/packages/block/test/eip4844block.spec.ts +++ b/packages/block/test/eip4844block.spec.ts @@ -7,8 +7,8 @@ import { initKZG, randomBytes, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' -import { assert, describe, it } from 'vitest' +import { createKZG } from 'kzg-wasm' +import { assert, beforeAll, describe, it } from 'vitest' import { BlockHeader } from '../src/header.js' import { fakeExponential, getNumBlobs } from '../src/helpers.js' @@ -17,249 +17,253 @@ import { Block } from '../src/index.js' import gethGenesis from './testdata/4844-hardfork.json' import type { TypedTransaction } from '@ethereumjs/tx' -// Hack to detect if running in browser or not -const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') -if (isBrowser() === false) { - try { - initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } -} - -const common = Common.fromGethGenesis(gethGenesis, { - chain: 'customChain', - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, -}) +describe('EIP4844 header tests', () => { + let common: Common -const blobGasPerBlob = common.param('gasConfig', 'blobGasPerBlob') + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) -describe('EIP4844 header tests', () => { it('should work', () => { - if (isBrowser() === false) { - const earlyCommon = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) - - assert.throws( - () => { - BlockHeader.fromHeaderData( - { - excessBlobGas: 1n, - }, - { - common: earlyCommon, - } - ) - }, - 'excess blob gas can only be provided with EIP4844 activated', - undefined, - 'should throw when setting excessBlobGas with EIP4844 not being activated' - ) + const earlyCommon = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) - assert.throws( - () => { - BlockHeader.fromHeaderData( - { - blobGasUsed: 1n, - }, - { - common: earlyCommon, - } - ) - }, - 'blob gas used can only be provided with EIP4844 activated', - undefined, - 'should throw when setting blobGasUsed with EIP4844 not being activated' - ) + assert.throws( + () => { + BlockHeader.fromHeaderData( + { + excessBlobGas: 1n, + }, + { + common: earlyCommon, + } + ) + }, + 'excess blob gas can only be provided with EIP4844 activated', + undefined, + 'should throw when setting excessBlobGas with EIP4844 not being activated' + ) - const excessBlobGas = BlockHeader.fromHeaderData( - {}, - { common, skipConsensusFormatValidation: true } - ).excessBlobGas - assert.equal( - excessBlobGas, - 0n, - 'instantiates block with reasonable default excess blob gas value when not provided' - ) - assert.doesNotThrow(() => { + assert.throws( + () => { BlockHeader.fromHeaderData( { - excessBlobGas: 0n, + blobGasUsed: 1n, }, { - common, - skipConsensusFormatValidation: true, + common: earlyCommon, } ) - }, 'correctly instantiates an EIP4844 block header') + }, + 'blob gas used can only be provided with EIP4844 activated', + undefined, + 'should throw when setting blobGasUsed with EIP4844 not being activated' + ) - const block = Block.fromBlockData( + const excessBlobGas = BlockHeader.fromHeaderData( + {}, + { common, skipConsensusFormatValidation: true } + ).excessBlobGas + assert.equal( + excessBlobGas, + 0n, + 'instantiates block with reasonable default excess blob gas value when not provided' + ) + assert.doesNotThrow(() => { + BlockHeader.fromHeaderData( { - header: BlockHeader.fromHeaderData({}, { common, skipConsensusFormatValidation: true }), + excessBlobGas: 0n, }, - { common, skipConsensusFormatValidation: true } - ) - assert.equal( - block.toJSON().header?.excessBlobGas, - '0x0', - 'JSON output includes excessBlobGas' + { + common, + skipConsensusFormatValidation: true, + } ) - } + }, 'correctly instantiates an EIP4844 block header') + + const block = Block.fromBlockData( + { + header: BlockHeader.fromHeaderData({}, { common, skipConsensusFormatValidation: true }), + }, + { common, skipConsensusFormatValidation: true } + ) + assert.equal(block.toJSON().header?.excessBlobGas, '0x0', 'JSON output includes excessBlobGas') }) }) describe('blob gas tests', () => { + let common: Common + let blobGasPerBlob: bigint + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + blobGasPerBlob = common.param('gasConfig', 'blobGasPerBlob') + }) it('should work', () => { - if (isBrowser() === false) { - const preShardingHeader = BlockHeader.fromHeaderData({}) + const preShardingHeader = BlockHeader.fromHeaderData({}) - let excessBlobGas = preShardingHeader.calcNextExcessBlobGas() - assert.equal( - excessBlobGas, - 0n, - 'excess blob gas where 4844 is not active on header should be 0' - ) + let excessBlobGas = preShardingHeader.calcNextExcessBlobGas() + assert.equal( + excessBlobGas, + 0n, + 'excess blob gas where 4844 is not active on header should be 0' + ) - assert.throws( - () => preShardingHeader.calcDataFee(1), - 'header must have excessBlobGas field', - undefined, - 'calcDataFee throws when header has no excessBlobGas field' - ) + assert.throws( + () => preShardingHeader.calcDataFee(1), + 'header must have excessBlobGas field', + undefined, + 'calcDataFee throws when header has no excessBlobGas field' + ) - const lowGasHeader = BlockHeader.fromHeaderData( - { number: 1, excessBlobGas: 5000 }, - { common, skipConsensusFormatValidation: true } - ) + const lowGasHeader = BlockHeader.fromHeaderData( + { number: 1, excessBlobGas: 5000 }, + { common, skipConsensusFormatValidation: true } + ) - excessBlobGas = lowGasHeader.calcNextExcessBlobGas() - let blobGasPrice = lowGasHeader.getBlobGasPrice() - assert.equal( - excessBlobGas, - 0n, - 'excess blob gas should be 0 for small parent header blob gas' - ) - assert.equal(blobGasPrice, 1n, 'blob gas price should be 1n when low or no excess blob gas') - const highGasHeader = BlockHeader.fromHeaderData( - { number: 1, excessBlobGas: 6291456, blobGasUsed: BigInt(6) * blobGasPerBlob }, - { common, skipConsensusFormatValidation: true } - ) - excessBlobGas = highGasHeader.calcNextExcessBlobGas() - blobGasPrice = highGasHeader.getBlobGasPrice() - assert.equal(excessBlobGas, 6684672n) - assert.equal(blobGasPrice, 6n, 'computed correct blob gas price') + excessBlobGas = lowGasHeader.calcNextExcessBlobGas() + let blobGasPrice = lowGasHeader.getBlobGasPrice() + assert.equal(excessBlobGas, 0n, 'excess blob gas should be 0 for small parent header blob gas') + assert.equal(blobGasPrice, 1n, 'blob gas price should be 1n when low or no excess blob gas') + const highGasHeader = BlockHeader.fromHeaderData( + { number: 1, excessBlobGas: 6291456, blobGasUsed: BigInt(6) * blobGasPerBlob }, + { common, skipConsensusFormatValidation: true } + ) + excessBlobGas = highGasHeader.calcNextExcessBlobGas() + blobGasPrice = highGasHeader.getBlobGasPrice() + assert.equal(excessBlobGas, 6684672n) + assert.equal(blobGasPrice, 6n, 'computed correct blob gas price') - assert.equal(lowGasHeader.calcDataFee(1), 131072n, 'compute data fee correctly') - assert.equal(highGasHeader.calcDataFee(4), 3145728n, 'compute data fee correctly') - assert.equal(highGasHeader.calcDataFee(6), 4718592n, 'compute data fee correctly') - } + assert.equal(lowGasHeader.calcDataFee(1), 131072n, 'compute data fee correctly') + assert.equal(highGasHeader.calcDataFee(4), 3145728n, 'compute data fee correctly') + assert.equal(highGasHeader.calcDataFee(6), 4718592n, 'compute data fee correctly') }) }) describe('transaction validation tests', () => { + let common: Common + let blobGasPerBlob: bigint + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + blobGasPerBlob = common.param('gasConfig', 'blobGasPerBlob') + }) it('should work', () => { - if (isBrowser() === false) { - const blobs = getBlobs('hello world') - const commitments = blobsToCommitments(blobs) - const blobVersionedHashes = commitmentsToVersionedHashes(commitments) + const blobs = getBlobs('hello world') + const commitments = blobsToCommitments(blobs) + const blobVersionedHashes = commitmentsToVersionedHashes(commitments) - const tx1 = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ).sign(randomBytes(32)) - const tx2 = BlobEIP4844Transaction.fromTxData( + const tx1 = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ).sign(randomBytes(32)) + const tx2 = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + maxFeePerBlobGas: 1n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ).sign(randomBytes(32)) + + const parentHeader = BlockHeader.fromHeaderData( + { number: 1n, excessBlobGas: 4194304, blobGasUsed: 0 }, + { common, skipConsensusFormatValidation: true } + ) + const excessBlobGas = parentHeader.calcNextExcessBlobGas() + + // eslint-disable-next-line no-inner-declarations + function getBlock(transactions: TypedTransaction[]) { + const blobs = getNumBlobs(transactions) + + const blockHeader = BlockHeader.fromHeaderData( { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - maxFeePerBlobGas: 1n, - gasLimit: 0xffffffn, - to: randomBytes(20), + number: 2n, + parentHash: parentHeader.hash(), + excessBlobGas, + blobGasUsed: BigInt(blobs) * blobGasPerBlob, }, - { common } - ).sign(randomBytes(32)) - - const parentHeader = BlockHeader.fromHeaderData( - { number: 1n, excessBlobGas: 4194304, blobGasUsed: 0 }, { common, skipConsensusFormatValidation: true } ) - const excessBlobGas = parentHeader.calcNextExcessBlobGas() - - // eslint-disable-next-line no-inner-declarations - function getBlock(transactions: TypedTransaction[]) { - const blobs = getNumBlobs(transactions) - - const blockHeader = BlockHeader.fromHeaderData( - { - number: 2n, - parentHash: parentHeader.hash(), - excessBlobGas, - blobGasUsed: BigInt(blobs) * blobGasPerBlob, - }, - { common, skipConsensusFormatValidation: true } - ) - const block = Block.fromBlockData( - { header: blockHeader, transactions }, - { common, skipConsensusFormatValidation: true } - ) - return block - } + const block = Block.fromBlockData( + { header: blockHeader, transactions }, + { common, skipConsensusFormatValidation: true } + ) + return block + } - const blockWithValidTx = getBlock([tx1]) + const blockWithValidTx = getBlock([tx1]) - const blockWithInvalidTx = getBlock([tx1, tx2]) + const blockWithInvalidTx = getBlock([tx1, tx2]) - const blockWithTooManyBlobs = getBlock([tx1, tx1, tx1, tx1, tx1, tx1, tx1]) + const blockWithTooManyBlobs = getBlock([tx1, tx1, tx1, tx1, tx1, tx1, tx1]) - assert.doesNotThrow( - () => blockWithValidTx.validateBlobTransactions(parentHeader), - 'does not throw when all tx maxFeePerBlobGas are >= to block blob gas fee' - ) - const blockJson = blockWithValidTx.toJSON() - blockJson.header!.blobGasUsed = '0x0' - const blockWithInvalidHeader = Block.fromBlockData(blockJson, { common }) - assert.throws( - () => blockWithInvalidHeader.validateBlobTransactions(parentHeader), - 'block blobGasUsed mismatch', - undefined, - 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' - ) + assert.doesNotThrow( + () => blockWithValidTx.validateBlobTransactions(parentHeader), + 'does not throw when all tx maxFeePerBlobGas are >= to block blob gas fee' + ) + const blockJson = blockWithValidTx.toJSON() + blockJson.header!.blobGasUsed = '0x0' + const blockWithInvalidHeader = Block.fromBlockData(blockJson, { common }) + assert.throws( + () => blockWithInvalidHeader.validateBlobTransactions(parentHeader), + 'block blobGasUsed mismatch', + undefined, + 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' + ) - assert.throws( - () => blockWithInvalidTx.validateBlobTransactions(parentHeader), - 'than block blob gas price', - undefined, - 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' - ) - assert.throws( - () => blockWithInvalidTx.validateBlobTransactions(parentHeader), - 'than block blob gas price', - undefined, - 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' - ) - assert.throws( - () => blockWithTooManyBlobs.validateBlobTransactions(parentHeader), - 'exceed maximum blob gas per block', - undefined, - 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' - ) + assert.throws( + () => blockWithInvalidTx.validateBlobTransactions(parentHeader), + 'than block blob gas price', + undefined, + 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' + ) + assert.throws( + () => blockWithInvalidTx.validateBlobTransactions(parentHeader), + 'than block blob gas price', + undefined, + 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' + ) + assert.throws( + () => blockWithTooManyBlobs.validateBlobTransactions(parentHeader), + 'exceed maximum blob gas per block', + undefined, + 'throws with correct error message when tx maxFeePerBlobGas less than block blob gas fee' + ) - assert.ok( - blockWithTooManyBlobs - .getTransactionsValidationErrors() - .join(' ') - .includes('exceed maximum blob gas per block'), - 'tx erros includes correct error message when too many blobs in a block' - ) - } + assert.ok( + blockWithTooManyBlobs + .getTransactionsValidationErrors() + .join(' ') + .includes('exceed maximum blob gas per block'), + 'tx erros includes correct error message when too many blobs in a block' + ) }) }) diff --git a/packages/block/test/from-beacon-payload.spec.ts b/packages/block/test/from-beacon-payload.spec.ts index 8a17be8d93..9916ac8832 100644 --- a/packages/block/test/from-beacon-payload.spec.ts +++ b/packages/block/test/from-beacon-payload.spec.ts @@ -1,7 +1,7 @@ import { Common, Hardfork } from '@ethereumjs/common' import { initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' -import { assert, describe, it } from 'vitest' +import { createKZG } from 'kzg-wasm' +import { assert, beforeAll, describe, it } from 'vitest' import * as shardingJson from '../../client/test/sim/configs/4844-devnet.json' import { Block, BlockHeader } from '../src/index.js' @@ -11,20 +11,20 @@ import * as payload87335 from './testdata/payload-slot-87335.json' import * as payload87475 from './testdata/payload-slot-87475.json' import * as testnetVerkleKaustinen from './testdata/testnetVerkleKaustinen.json' -try { - initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') -} catch { - // no-op -} - describe('[fromExecutionPayloadJson]: 4844 devnet 5', () => { - const network = 'sharding' + let kzg + let common: Common + beforeAll(async () => { + kzg = await createKZG() + initKZG(kzg, '') + const commonJson = { ...shardingJson } + commonJson.config = { ...commonJson.config, chainId: 4844001005 } + const network = 'sharding' + common = Common.fromGethGenesis(commonJson, { chain: network, customCrypto: { kzg } }) + // safely change chainId without modifying undelying json - // safely change chainId without modifying undelying json - const commonJson = { ...shardingJson } - commonJson.config = { ...commonJson.config, chainId: 4844001005 } - const common = Common.fromGethGenesis(commonJson, { chain: network, customCrypto: { kzg } }) - common.setHardfork(Hardfork.Cancun) + common.setHardfork(Hardfork.Cancun) + }) it('reconstruct cancun block with blob txs', async () => { for (const payload of [payload87335, payload87475]) { @@ -77,6 +77,11 @@ describe('[fromExecutionPayloadJson]: 4844 devnet 5', () => { }) describe('[fromExecutionPayloadJson]: kaustinen', () => { + let kzg + beforeAll(async () => { + kzg = await createKZG() + initKZG(kzg, '') + }) const network = 'kaustinen' // safely change chainId without modifying undelying json diff --git a/packages/block/vitest.config.browser.ts b/packages/block/vitest.config.browser.ts index 5aa1b6aa12..4b3a3c4b0e 100644 --- a/packages/block/vitest.config.browser.ts +++ b/packages/block/vitest.config.browser.ts @@ -4,9 +4,6 @@ export default defineConfig({ test: { exclude: [ ...configDefaults.exclude, - // c-kzg dependency - 'test/eip4844block.spec.ts', - 'test/from-beacon-payload.spec.ts', // Cannot access uninitialized variable. // (likely local fix possible) 'test/mergeBlock.spec.ts', @@ -14,4 +11,7 @@ export default defineConfig({ 'test/eip1559block.spec.ts', ], }, + optimizeDeps: { + exclude: ['kzg-wasm'], + }, }) diff --git a/packages/client/bin/cli.ts b/packages/client/bin/cli.ts index e2c85c5c81..2d9aefddcf 100755 --- a/packages/client/bin/cli.ts +++ b/packages/client/bin/cli.ts @@ -28,12 +28,12 @@ import { waitReady as waitReadyPolkadotSha256, sha256 as wasmSha256, } from '@polkadot/wasm-crypto' -import * as kzg from 'c-kzg' import { keccak256 } from 'ethereum-cryptography/keccak' import { ecdsaRecover, ecdsaSign } from 'ethereum-cryptography/secp256k1-compat' import { sha256 } from 'ethereum-cryptography/sha256' import { existsSync, writeFileSync } from 'fs' import { ensureDirSync, readFileSync, removeSync } from 'fs-extra' +import { createKZG } from 'kzg-wasm' import { Level } from 'level' import { homedir } from 'os' import * as path from 'path' @@ -806,8 +806,8 @@ async function run() { // Give network id precedence over network name const chain = args.networkId ?? args.network ?? Chain.Mainnet const cryptoFunctions: CustomCrypto = {} - - initKZG(kzg, args.trustedSetup ?? __dirname + '/../src/trustedSetups/official.txt') + const kzg = await createKZG() + initKZG(kzg, '') // Initialize WASM crypto if JS crypto is not specified if (args.useJsCrypto === false) { diff --git a/packages/client/devnets/4844-interop/tools/txGenerator.ts b/packages/client/devnets/4844-interop/tools/txGenerator.ts index e1b7363fae..1e178f111a 100644 --- a/packages/client/devnets/4844-interop/tools/txGenerator.ts +++ b/packages/client/devnets/4844-interop/tools/txGenerator.ts @@ -11,11 +11,9 @@ import { initKZG, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' import { randomBytes } from '@ethereumjs/util' import { Client } from 'jayson/promise' - -initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') +import { createKZG } from 'kzg-wasm' // CLI Args const clientPort = parseInt(process.argv[2]) // EL client port number @@ -23,11 +21,6 @@ const input = process.argv[3] // text to generate blob from const genesisJson = require(process.argv[4]) // Genesis parameters const pkey = hexToBytes('0x' + process.argv[5]) // private key of tx sender as unprefixed hex string (unprefixed in args) const sender = Address.fromPrivateKey(pkey) -const common = Common.fromGethGenesis(genesisJson, { - chain: genesisJson.ChainName ?? 'devnet', - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, -}) async function getNonce(client: Client, account: string) { const nonce = await client.request('eth_getTransactionCount', [account, 'latest'], 2.0) @@ -35,6 +28,15 @@ async function getNonce(client: Client, account: string) { } async function run(data: any) { + const kzg = await createKZG() + initKZG(kzg, '') + + const common = Common.fromGethGenesis(genesisJson, { + chain: genesisJson.ChainName ?? 'devnet', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + const client = Client.http({ port: clientPort }) const blobs = getBlobs(data) diff --git a/packages/client/package.json b/packages/client/package.json index 5fdf394acf..45a0835509 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -74,7 +74,7 @@ "@polkadot/wasm-crypto": "^7.3.2", "abstract-level": "^1.0.3", "body-parser": "^1.19.2", - "c-kzg": "^2.1.2", + "kzg-wasm": "^0.1.0", "chalk": "^4.1.2", "connect": "^3.7.0", "cors": "^2.8.5", diff --git a/packages/client/test/miner/pendingBlock.spec.ts b/packages/client/test/miner/pendingBlock.spec.ts index aaa182362d..dfa6655fe5 100644 --- a/packages/client/test/miner/pendingBlock.spec.ts +++ b/packages/client/test/miner/pendingBlock.spec.ts @@ -20,7 +20,7 @@ import { randomBytes, } from '@ethereumjs/util' import { VM } from '@ethereumjs/vm' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it, vi } from 'vitest' import gethGenesis from '../../../block/test/testdata/4844-hardfork.json' @@ -353,11 +353,8 @@ describe('[PendingBlock]', async () => { }) it('construct blob bundles', async () => { - try { - initKZG(kzg, __dirname + '/../../src/trustedSetups/official.txt') - } catch { - // no-op - } + const kzg = await createKZG() + initKZG(kzg, '') const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -437,11 +434,8 @@ describe('[PendingBlock]', async () => { it('should exclude missingBlobTx', async () => { const gethGenesis = require('../../../block/test/testdata/4844-hardfork.json') - try { - initKZG(kzg, __dirname + '/../../src/trustedSetups/official.txt') - } catch { - //no-op - } + const kzg = await createKZG() + const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/client/test/rpc/engine/getPayloadV3.spec.ts b/packages/client/test/rpc/engine/getPayloadV3.spec.ts index afed6934a7..dda7639137 100644 --- a/packages/client/test/rpc/engine/getPayloadV3.spec.ts +++ b/packages/client/test/rpc/engine/getPayloadV3.spec.ts @@ -12,7 +12,7 @@ import { hexToBytes, initKZG, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { INVALID_PARAMS } from '../../../src/rpc/error-code.js' @@ -68,11 +68,9 @@ describe(method, () => { return this } - try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') - } catch { - //no-op - } + const kzg = await createKZG() + initKZG(kzg, '') + const { service, server, common } = await setupChain(genesisJSON, 'post-merge', { engine: true, hardfork: Hardfork.Cancun, diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index a9f7b6715e..1240b9f9c3 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -1,6 +1,6 @@ import { Block, BlockHeader, executionPayloadFromBeaconPayload } from '@ethereumjs/block' import { initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import * as td from 'testdouble' import { assert, describe, it } from 'vitest' @@ -33,11 +33,9 @@ async function runBlock( } describe(`valid verkle network setup`, async () => { - try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') - } catch { - // no-op - } + const kzg = await createKZG() + initKZG(kzg, '') + const { server, chain, common } = await setupChain(genesisJSON, 'post-merge', { engine: true, genesisStateRoot: genesisVerkleStateRoot, diff --git a/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts b/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts index 01c6060c2a..57cc90adc2 100644 --- a/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts +++ b/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts @@ -1,5 +1,5 @@ import { initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { INVALID_PARAMS } from '../../../src/rpc/error-code.js' @@ -15,11 +15,9 @@ const [blockData] = blocks describe(`${method}: Cancun validations`, () => { it('blobVersionedHashes', async () => { - try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') - } catch { - // no-op - } + const kzg = await createKZG() + initKZG(kzg, '') + const { server } = await setupChain(genesisJSON, 'post-merge', { engine: true, customCrypto: { kzg }, diff --git a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts index 8b4dd16b45..349ce7b616 100644 --- a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts +++ b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts @@ -2,17 +2,14 @@ import { Block } from '@ethereumjs/block' import { Common } from '@ethereumjs/common' import { BlobEIP4844Transaction, LegacyTransaction } from '@ethereumjs/tx' import { Address, hexToBytes, initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { INVALID_PARAMS } from '../../../src/rpc/error-code.js' import { createClient, createManager, dummy, getRpcClient, startRPC } from '../helpers.js' -try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') -} catch { - // no-op -} +const kzg = await createKZG() +initKZG(kzg, '') const common = Common.custom({ chainId: 1 }, { customCrypto: { kzg } }) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index b0758a2077..9b555541f8 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -12,7 +12,7 @@ import { initKZG, randomBytes, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import pow from '../../testdata/geth-genesis/pow.json' @@ -88,11 +88,10 @@ describe(method, () => { assert.ok(true) } else { const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') - try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') - } catch { - // no-op - } + + const kzg = await createKZG() + initKZG(kzg, '') + const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/client/test/rpc/eth/sendRawTransaction.spec.ts b/packages/client/test/rpc/eth/sendRawTransaction.spec.ts index da0e0f87fa..27fc50e35e 100644 --- a/packages/client/test/rpc/eth/sendRawTransaction.spec.ts +++ b/packages/client/test/rpc/eth/sendRawTransaction.spec.ts @@ -16,7 +16,7 @@ import { initKZG, randomBytes, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { INTERNAL_ERROR, INVALID_PARAMS, PARSE_ERROR } from '../../../src/rpc/error-code.js' @@ -219,11 +219,10 @@ describe(method, () => { const consensusFormatValidation = BlockHeader.prototype['_consensusFormatValidation'] BlockHeader.prototype['_consensusFormatValidation'] = (): any => {} const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') - try { - initKZG(kzg, __dirname + '/../../../src/trustedSetups/official.txt') - } catch { - // no-op - } + + const kzg = await createKZG() + initKZG(kzg, '') + const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/client/test/sim/txGenerator.ts b/packages/client/test/sim/txGenerator.ts index 3fc0cf3d7a..8fab408fbe 100644 --- a/packages/client/test/sim/txGenerator.ts +++ b/packages/client/test/sim/txGenerator.ts @@ -6,13 +6,12 @@ import { bytesToHex, commitmentsToVersionedHashes, hexToBytes, - initKZG, randomBytes, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' import { Client } from 'jayson/promise' import type { TransactionType, TxData } from '@ethereumjs/tx' + const clientPort = process.argv[2] const input = process.argv[3] @@ -23,7 +22,6 @@ const MAX_BLOBS_PER_TX = 2 const MAX_USEFUL_BYTES_PER_TX = USEFUL_BYTES_PER_BLOB * MAX_BLOBS_PER_TX - 1 const BLOB_SIZE = BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB -initKZG(kzg, __dirname + '/../../src/trustedSetups/official.txt') const pkey = hexToBytes('0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8') const sender = Address.fromPrivateKey(pkey) diff --git a/packages/common/examples/initKzg.ts b/packages/common/examples/initKzg.ts index cbf4d9360d..39abd25831 100644 --- a/packages/common/examples/initKzg.ts +++ b/packages/common/examples/initKzg.ts @@ -1,11 +1,16 @@ -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { Common, Chain, Hardfork } from '@ethereumjs/common' import { initKZG } from '@ethereumjs/util' -initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') -const common = new Common({ - chain: Chain.Mainnet, - hardfork: Hardfork.Cancun, - customCrypto: { kzg: kzg }, -}) -console.log(common.customCrypto.kzg) // Should print the initialized KZG interface +const main = async () => { + const kzg = await createKZG() + initKZG(kzg, '') + const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Cancun, + customCrypto: { kzg: kzg }, + }) + console.log(common.customCrypto.kzg) // Should print the initialized KZG interface +} + +main() diff --git a/packages/evm/package.json b/packages/evm/package.json index b9ca76d828..dadc38cbe4 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -69,7 +69,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", - "c-kzg": "^2.1.2", + "kzg-wasm": "^0.1.0", "level": "^8.0.0", "memory-level": "^1.0.0", "minimist": "^1.2.5", diff --git a/packages/evm/test/blobVersionedHashes.spec.ts b/packages/evm/test/blobVersionedHashes.spec.ts index f08df8121c..dec3f02b92 100644 --- a/packages/evm/test/blobVersionedHashes.spec.ts +++ b/packages/evm/test/blobVersionedHashes.spec.ts @@ -9,7 +9,7 @@ import type { EVMRunCallOpts } from '../src/types.js' describe('BLOBHASH / access blobVersionedHashes in calldata', () => { it('should work', async () => { // setup the evm - const genesisJSON = require('../../client/test/testdata/geth-genesis/eip4844.json') + const genesisJSON = await import('../../client/test/testdata/geth-genesis/eip4844.json') const common = Common.fromGethGenesis(genesisJSON, { chain: 'custom', hardfork: Hardfork.Cancun, @@ -39,7 +39,7 @@ describe('BLOBHASH / access blobVersionedHashes in calldata', () => { describe(`BLOBHASH: access blobVersionedHashes within contract calls`, () => { it('should work', async () => { // setup the evm - const genesisJSON = require('../../client/test/testdata/geth-genesis/eip4844.json') + const genesisJSON = await import('../../client/test/testdata/geth-genesis/eip4844.json') const common = Common.fromGethGenesis(genesisJSON, { chain: 'custom', hardfork: Hardfork.Cancun, @@ -90,7 +90,7 @@ describe(`BLOBHASH: access blobVersionedHashes within contract calls`, () => { describe(`BLOBHASH: access blobVersionedHashes in a CREATE/CREATE2 frame`, () => { it('should work', async () => { // setup the evm - const genesisJSON = require('../../client/test/testdata/geth-genesis/eip4844.json') + const genesisJSON = await import('../../client/test/testdata/geth-genesis/eip4844.json') const common = Common.fromGethGenesis(genesisJSON, { chain: 'custom', hardfork: Hardfork.Cancun, diff --git a/packages/evm/test/precompiles/0a-pointevaluation.spec.ts b/packages/evm/test/precompiles/0a-pointevaluation.spec.ts index 281d8de720..235090b65d 100644 --- a/packages/evm/test/precompiles/0a-pointevaluation.spec.ts +++ b/packages/evm/test/precompiles/0a-pointevaluation.spec.ts @@ -7,7 +7,7 @@ import { initKZG, unpadBytes, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { EVM, getActivePrecompiles } from '../../src/index.js' @@ -17,79 +17,69 @@ import type { PrecompileInput } from '../../src/index.js' const BLS_MODULUS = BigInt( '52435875175126190479447740508185965837690552500527637822603658699938581184513' ) -const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') describe('Precompiles: point evaluation', () => { it('should work', async () => { - if (isBrowser() === false) { - const genesisJSON = require('../../../client/test/testdata/geth-genesis/eip4844.json') - try { - initKZG(kzg, __dirname + '/../../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } - const common = Common.fromGethGenesis(genesisJSON, { - chain: 'custom', - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, - }) + const genesisJSON = await import('../../../client/test/testdata/geth-genesis/eip4844.json') - const evm = new EVM({ - common, - }) - const addressStr = '000000000000000000000000000000000000000a' - const pointEvaluation = getActivePrecompiles(common).get(addressStr)! + const kzg = await createKZG() + initKZG(kzg, '') - const testCase = { - commitment: hexToBytes( - '0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ), - z: hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000002'), - y: hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000000'), - proof: hexToBytes( - '0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ), - } - const versionedHash = computeVersionedHash(testCase.commitment, 1) + const common = Common.fromGethGenesis(genesisJSON, { + chain: 'custom', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) - const opts: PrecompileInput = { - data: concatBytes( - versionedHash, - testCase.z, - testCase.y, - testCase.commitment, - testCase.proof - ), - gasLimit: 0xfffffffffn, - _EVM: evm, - common, - } + const evm = new EVM({ + common, + }) + const addressStr = '000000000000000000000000000000000000000a' + const pointEvaluation = getActivePrecompiles(common).get(addressStr)! - let res = await pointEvaluation(opts) - assert.equal( - bytesToBigInt(unpadBytes(res.returnValue.slice(32))), - BLS_MODULUS, - 'point evaluation precompile returned expected output' - ) + const testCase = { + commitment: hexToBytes( + '0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + ), + z: hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000002'), + y: hexToBytes('0x0000000000000000000000000000000000000000000000000000000000000000'), + proof: hexToBytes( + '0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + ), + } + const versionedHash = computeVersionedHash(testCase.commitment, 1) + + const opts: PrecompileInput = { + data: concatBytes(versionedHash, testCase.z, testCase.y, testCase.commitment, testCase.proof), + gasLimit: 0xfffffffffn, + _EVM: evm, + common, + } - const optsWithInvalidCommitment: PrecompileInput = { - data: concatBytes( - concatBytes(Uint8Array.from([0]), versionedHash.slice(1)), - testCase.z, - testCase.y, - testCase.commitment, - testCase.proof - ), - gasLimit: 0xfffffffffn, - _EVM: evm, - common, - } + let res = await pointEvaluation(opts) + assert.equal( + bytesToBigInt(unpadBytes(res.returnValue.slice(32))), + BLS_MODULUS, + 'point evaluation precompile returned expected output' + ) - res = await pointEvaluation(optsWithInvalidCommitment) - assert.ok( - res.exceptionError?.error.match('kzg commitment does not match versioned hash'), - 'precompile throws when commitment does not match versioned hash' - ) + const optsWithInvalidCommitment: PrecompileInput = { + data: concatBytes( + concatBytes(Uint8Array.from([0]), versionedHash.slice(1)), + testCase.z, + testCase.y, + testCase.commitment, + testCase.proof + ), + gasLimit: 0xfffffffffn, + _EVM: evm, + common, } + + res = await pointEvaluation(optsWithInvalidCommitment) + assert.ok( + res.exceptionError?.error.match('kzg commitment does not match versioned hash'), + 'precompile throws when commitment does not match versioned hash' + ) }) }) diff --git a/packages/evm/vitest.config.browser.ts b/packages/evm/vitest.config.browser.ts index edde9b2c2d..67047c5807 100644 --- a/packages/evm/vitest.config.browser.ts +++ b/packages/evm/vitest.config.browser.ts @@ -4,7 +4,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ plugins: [wasm(), topLevelAwait()], - test: { - exclude: ['test/blobVersionedHashes.spec.ts', 'test/precompiles/0a-pointevaluation.spec.ts'], // KZG based tests fail since c-kzg doesn't work in browser + optimizeDeps: { + exclude: ['kzg-wasm'], }, }) diff --git a/packages/tx/examples/blobTx.ts b/packages/tx/examples/blobTx.ts index 92c8fa8416..c56279366a 100644 --- a/packages/tx/examples/blobTx.ts +++ b/packages/tx/examples/blobTx.ts @@ -1,35 +1,40 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common' import { BlobEIP4844Transaction } from '@ethereumjs/tx' import { bytesToHex, initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' -initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') +const main = async () => { + const kzg = await createKZG() + initKZG(kzg, '') -const common = new Common({ - chain: Chain.Mainnet, - hardfork: Hardfork.Shanghai, - eips: [4844], - customCrypto: { kzg }, -}) + const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Shanghai, + eips: [4844], + customCrypto: { kzg }, + }) -const txData = { - data: '0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - gasLimit: '0x02625a00', - maxPriorityFeePerGas: '0x01', - maxFeePerGas: '0xff', - maxFeePerDataGas: '0xfff', - nonce: '0x00', - to: '0xcccccccccccccccccccccccccccccccccccccccc', - value: '0x0186a0', - v: '0x01', - r: '0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9', - s: '0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64', - chainId: '0x01', - accessList: [], - type: '0x05', - blobsData: ['abcd'], -} + const txData = { + data: '0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + gasLimit: '0x02625a00', + maxPriorityFeePerGas: '0x01', + maxFeePerGas: '0xff', + maxFeePerDataGas: '0xfff', + nonce: '0x00', + to: '0xcccccccccccccccccccccccccccccccccccccccc', + value: '0x0186a0', + v: '0x01', + r: '0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9', + s: '0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64', + chainId: '0x01', + accessList: [], + type: '0x05', + blobsData: ['abcd'], + } + + const tx = BlobEIP4844Transaction.fromTxData(txData, { common }) -const tx = BlobEIP4844Transaction.fromTxData(txData, { common }) + console.log(bytesToHex(tx.hash())) //0x3c3e7c5e09c250d2200bcc3530f4a9088d7e3fb4ea3f4fccfd09f535a3539e84 +} -console.log(bytesToHex(tx.hash())) //0x3c3e7c5e09c250d2200bcc3530f4a9088d7e3fb4ea3f4fccfd09f535a3539e84 +main() diff --git a/packages/tx/examples/initKzg.ts b/packages/tx/examples/initKzg.ts index 1692315981..86e8e81b29 100644 --- a/packages/tx/examples/initKzg.ts +++ b/packages/tx/examples/initKzg.ts @@ -1,18 +1,19 @@ -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { Chain, Common, Hardfork } from '@ethereumjs/common' import { initKZG } from '@ethereumjs/util' -// Instantiate KZG -try { - initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') -} catch { - // no-op if already loaded +const main = async () => { + const kzg = await createKZG() + initKZG(kzg, '') + + // Instantiate `common` + const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + + console.log(common.customCrypto.kzg) // should output the KZG API as an object } -// Instantiate `common` -const common = new Common({ - chain: Chain.Mainnet, - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, -}) -console.log(common.customCrypto.kzg) // should output the KZG API as an object +main() diff --git a/packages/tx/package.json b/packages/tx/package.json index 88118e273d..983feddfb3 100644 --- a/packages/tx/package.json +++ b/packages/tx/package.json @@ -62,17 +62,10 @@ "@ethereumjs/util": "^9.0.2", "ethereum-cryptography": "^2.1.3" }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - }, "devDependencies": { "@types/minimist": "^1.2.0", "@types/node-dir": "^0.0.34", + "kzg-wasm": "^0.1.0", "minimist": "^1.2.0", "node-dir": "^0.1.16" }, diff --git a/packages/tx/test/eip4844.spec.ts b/packages/tx/test/eip4844.spec.ts index af60d8eb21..53ea0bffa7 100644 --- a/packages/tx/test/eip4844.spec.ts +++ b/packages/tx/test/eip4844.spec.ts @@ -12,34 +12,27 @@ import { hexToBytes, initKZG, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' import { randomBytes } from 'crypto' -import { assert, describe, it } from 'vitest' +import { createKZG } from 'kzg-wasm' +import { assert, beforeAll, describe, it } from 'vitest' import gethGenesis from '../../block/test/testdata/4844-hardfork.json' import { BlobEIP4844Transaction, TransactionFactory } from '../src/index.js' import blobTx from './json/serialized4844tx.json' -// Hack to detect if running in browser or not -const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') - -if (isBrowser() === false) { - try { - initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } -} - const pk = randomBytes(32) -const common = Common.fromGethGenesis(gethGenesis, { - chain: 'customChain', - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, -}) - describe('EIP4844 addSignature tests', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('addSignature() -> correctly adds correct signature values', () => { const privateKey = pk const tx = BlobEIP4844Transaction.fromTxData( @@ -95,509 +88,547 @@ describe('EIP4844 addSignature tests', () => { }) describe('EIP4844 constructor tests - valid scenarios', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('should work', () => { - if (isBrowser() === false) { - const txData = { - type: 0x03, - blobVersionedHashes: [concatBytes(new Uint8Array([1]), randomBytes(31))], - maxFeePerBlobGas: 1n, - to: Address.zero(), - } - const tx = BlobEIP4844Transaction.fromTxData(txData, { common }) - assert.equal(tx.type, 3, 'successfully instantiated a blob transaction from txData') - const factoryTx = TransactionFactory.fromTxData(txData, { common }) - assert.equal(factoryTx.type, 3, 'instantiated a blob transaction from the tx factory') - - const serializedTx = tx.serialize() - assert.equal(serializedTx[0], 3, 'successfully serialized a blob tx') - const deserializedTx = BlobEIP4844Transaction.fromSerializedTx(serializedTx, { common }) - assert.equal(deserializedTx.type, 3, 'deserialized a blob tx') - - const signedTx = tx.sign(pk) - const sender = signedTx.getSenderAddress().toString() - const decodedTx = BlobEIP4844Transaction.fromSerializedTx(signedTx.serialize(), { common }) - assert.equal( - decodedTx.getSenderAddress().toString(), - sender, - 'signature and sender were deserialized correctly' - ) + const txData = { + type: 0x03, + blobVersionedHashes: [concatBytes(new Uint8Array([1]), randomBytes(31))], + maxFeePerBlobGas: 1n, + to: Address.zero(), } + const tx = BlobEIP4844Transaction.fromTxData(txData, { common }) + assert.equal(tx.type, 3, 'successfully instantiated a blob transaction from txData') + const factoryTx = TransactionFactory.fromTxData(txData, { common }) + assert.equal(factoryTx.type, 3, 'instantiated a blob transaction from the tx factory') + + const serializedTx = tx.serialize() + assert.equal(serializedTx[0], 3, 'successfully serialized a blob tx') + const deserializedTx = BlobEIP4844Transaction.fromSerializedTx(serializedTx, { common }) + assert.equal(deserializedTx.type, 3, 'deserialized a blob tx') + + const signedTx = tx.sign(pk) + const sender = signedTx.getSenderAddress().toString() + const decodedTx = BlobEIP4844Transaction.fromSerializedTx(signedTx.serialize(), { common }) + assert.equal( + decodedTx.getSenderAddress().toString(), + sender, + 'signature and sender were deserialized correctly' + ) }) }) describe('fromTxData using from a json', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('should work', () => { - if (isBrowser() === false) { - const txData = { - type: '0x3', - nonce: '0x0', - gasPrice: null, - maxPriorityFeePerGas: '0x12a05f200', - maxFeePerGas: '0x12a05f200', - gasLimit: '0x33450', - value: '0xbc614e', - data: '0x', - v: '0x0', - r: '0x8a83833ec07806485a4ded33f24f5cea4b8d4d24dc8f357e6d446bcdae5e58a7', - s: '0x68a2ba422a50cf84c0b5fcbda32ee142196910c97198ffd99035d920c2b557f8', - to: '0xffb38a7a99e3e2335be83fc74b7faa19d5531243', - chainId: '0x28757b3', - accessList: null, - maxFeePerBlobGas: '0xb2d05e00', - blobVersionedHashes: ['0x01b0a4cdd5f55589f5c5b4d46c76704bb6ce95c0a8c09f77f197a57808dded28'], - } - const txMeta = { - hash: '0xe5e02be0667b6d31895d1b5a8b916a6761cbc9865225c6144a3e2c50936d173e', - serialized: - '0x03f89b84028757b38085012a05f20085012a05f2008303345094ffb38a7a99e3e2335be83fc74b7faa19d553124383bc614e80c084b2d05e00e1a001b0a4cdd5f55589f5c5b4d46c76704bb6ce95c0a8c09f77f197a57808dded2880a08a83833ec07806485a4ded33f24f5cea4b8d4d24dc8f357e6d446bcdae5e58a7a068a2ba422a50cf84c0b5fcbda32ee142196910c97198ffd99035d920c2b557f8', - } - - const c = common.copy() - c['_chainParams'] = Object.assign({}, common['_chainParams'], { - chainId: Number(txData.chainId), - }) - try { - const tx = BlobEIP4844Transaction.fromTxData(txData, { common: c }) - assert.ok(true, 'Should be able to parse a json data and hash it') - - assert.equal(typeof tx.maxFeePerBlobGas, 'bigint', 'should be able to parse correctly') - assert.equal(bytesToHex(tx.serialize()), txMeta.serialized, 'serialization should match') - // TODO: fix the hash - assert.equal(bytesToHex(tx.hash()), txMeta.hash, 'hash should match') - - const jsonData = tx.toJSON() - // override few fields with equivalent values to have a match - assert.deepEqual( - { ...txData, accessList: [] }, - { gasPrice: null, ...jsonData }, - 'toJSON should give correct json' - ) + const txData = { + type: '0x3', + nonce: '0x0', + gasPrice: null, + maxPriorityFeePerGas: '0x12a05f200', + maxFeePerGas: '0x12a05f200', + gasLimit: '0x33450', + value: '0xbc614e', + data: '0x', + v: '0x0', + r: '0x8a83833ec07806485a4ded33f24f5cea4b8d4d24dc8f357e6d446bcdae5e58a7', + s: '0x68a2ba422a50cf84c0b5fcbda32ee142196910c97198ffd99035d920c2b557f8', + to: '0xffb38a7a99e3e2335be83fc74b7faa19d5531243', + chainId: '0x28757b3', + accessList: null, + maxFeePerBlobGas: '0xb2d05e00', + blobVersionedHashes: ['0x01b0a4cdd5f55589f5c5b4d46c76704bb6ce95c0a8c09f77f197a57808dded28'], + } + const txMeta = { + hash: '0xe5e02be0667b6d31895d1b5a8b916a6761cbc9865225c6144a3e2c50936d173e', + serialized: + '0x03f89b84028757b38085012a05f20085012a05f2008303345094ffb38a7a99e3e2335be83fc74b7faa19d553124383bc614e80c084b2d05e00e1a001b0a4cdd5f55589f5c5b4d46c76704bb6ce95c0a8c09f77f197a57808dded2880a08a83833ec07806485a4ded33f24f5cea4b8d4d24dc8f357e6d446bcdae5e58a7a068a2ba422a50cf84c0b5fcbda32ee142196910c97198ffd99035d920c2b557f8', + } - const fromSerializedTx = BlobEIP4844Transaction.fromSerializedTx( - hexToBytes(txMeta.serialized), - { common: c } - ) - assert.equal( - bytesToHex(fromSerializedTx.hash()), - txMeta.hash, - 'fromSerializedTx hash should match' - ) - } catch (e) { - assert.fail('failed to parse json data') - } + const c = common.copy() + c['_chainParams'] = Object.assign({}, common['_chainParams'], { + chainId: Number(txData.chainId), + }) + try { + const tx = BlobEIP4844Transaction.fromTxData(txData, { common: c }) + assert.ok(true, 'Should be able to parse a json data and hash it') + + assert.equal(typeof tx.maxFeePerBlobGas, 'bigint', 'should be able to parse correctly') + assert.equal(bytesToHex(tx.serialize()), txMeta.serialized, 'serialization should match') + // TODO: fix the hash + assert.equal(bytesToHex(tx.hash()), txMeta.hash, 'hash should match') + + const jsonData = tx.toJSON() + // override few fields with equivalent values to have a match + assert.deepEqual( + { ...txData, accessList: [] }, + { gasPrice: null, ...jsonData }, + 'toJSON should give correct json' + ) + + const fromSerializedTx = BlobEIP4844Transaction.fromSerializedTx( + hexToBytes(txMeta.serialized), + { common: c } + ) + assert.equal( + bytesToHex(fromSerializedTx.hash()), + txMeta.hash, + 'fromSerializedTx hash should match' + ) + } catch (e) { + assert.fail('failed to parse json data') } }) }) describe('EIP4844 constructor tests - invalid scenarios', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('should work', () => { - if (isBrowser() === false) { - const baseTxData = { - type: 0x03, - maxFeePerBlobGas: 1n, - to: Address.zero(), - } - const shortVersionHash = { - blobVersionedHashes: [concatBytes(new Uint8Array([3]), randomBytes(3))], - } - const invalidVersionHash = { - blobVersionedHashes: [concatBytes(new Uint8Array([3]), randomBytes(31))], - } - const tooManyBlobs = { - blobVersionedHashes: [ - concatBytes(new Uint8Array([1]), randomBytes(31)), - concatBytes(new Uint8Array([1]), randomBytes(31)), - concatBytes(new Uint8Array([1]), randomBytes(31)), - ], - } - try { - BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...shortVersionHash }, { common }) - } catch (err: any) { - assert.ok( - err.message.includes('versioned hash is invalid length'), - 'throws on invalid versioned hash length' - ) - } - try { - BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...invalidVersionHash }, { common }) - } catch (err: any) { - assert.ok( - err.message.includes('does not start with KZG commitment'), - 'throws on invalid commitment version' - ) - } - try { - BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...tooManyBlobs }, { common }) - } catch (err: any) { - assert.ok( - err.message.includes('tx can contain at most'), - 'throws on too many versioned hashes' - ) - } + const baseTxData = { + type: 0x03, + maxFeePerBlobGas: 1n, + to: Address.zero(), + } + const shortVersionHash = { + blobVersionedHashes: [concatBytes(new Uint8Array([3]), randomBytes(3))], + } + const invalidVersionHash = { + blobVersionedHashes: [concatBytes(new Uint8Array([3]), randomBytes(31))], + } + const tooManyBlobs = { + blobVersionedHashes: [ + concatBytes(new Uint8Array([1]), randomBytes(31)), + concatBytes(new Uint8Array([1]), randomBytes(31)), + concatBytes(new Uint8Array([1]), randomBytes(31)), + ], + } + try { + BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...shortVersionHash }, { common }) + } catch (err: any) { + assert.ok( + err.message.includes('versioned hash is invalid length'), + 'throws on invalid versioned hash length' + ) + } + try { + BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...invalidVersionHash }, { common }) + } catch (err: any) { + assert.ok( + err.message.includes('does not start with KZG commitment'), + 'throws on invalid commitment version' + ) + } + try { + BlobEIP4844Transaction.fromTxData({ ...baseTxData, ...tooManyBlobs }, { common }) + } catch (err: any) { + assert.ok( + err.message.includes('tx can contain at most'), + 'throws on too many versioned hashes' + ) } }) }) describe('Network wrapper tests', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('should work', async () => { - if (isBrowser() === false) { - const blobs = getBlobs('hello world') - const commitments = blobsToCommitments(blobs) - const blobVersionedHashes = commitmentsToVersionedHashes(commitments) - const proofs = blobsToProofs(blobs, commitments) - const unsignedTx = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) + const blobs = getBlobs('hello world') + const commitments = blobsToCommitments(blobs) + const blobVersionedHashes = commitmentsToVersionedHashes(commitments) + const proofs = blobsToProofs(blobs, commitments) + const unsignedTx = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) - const signedTx = unsignedTx.sign(pk) - const sender = signedTx.getSenderAddress().toString() - const wrapper = signedTx.serializeNetworkWrapper() - const deserializedTx = BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(wrapper, { - common, - }) + const signedTx = unsignedTx.sign(pk) + const sender = signedTx.getSenderAddress().toString() + const wrapper = signedTx.serializeNetworkWrapper() + const deserializedTx = BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(wrapper, { + common, + }) - assert.equal( - deserializedTx.type, - 0x03, - 'successfully deserialized a blob transaction network wrapper' - ) - assert.equal( - deserializedTx.blobs?.length, - blobs.length, - 'contains the correct number of blobs' - ) - assert.equal( - deserializedTx.getSenderAddress().toString(), - sender, - 'decoded sender address correctly' - ) - const minimalTx = BlobEIP4844Transaction.minimalFromNetworkWrapper(deserializedTx, { common }) - assert.ok(minimalTx.blobs === undefined, 'minimal representation contains no blobs') - assert.ok( - equalsBytes(minimalTx.hash(), deserializedTx.hash()), - 'has the same hash as the network wrapper version' - ) + assert.equal( + deserializedTx.type, + 0x03, + 'successfully deserialized a blob transaction network wrapper' + ) + assert.equal(deserializedTx.blobs?.length, blobs.length, 'contains the correct number of blobs') + assert.equal( + deserializedTx.getSenderAddress().toString(), + sender, + 'decoded sender address correctly' + ) + const minimalTx = BlobEIP4844Transaction.minimalFromNetworkWrapper(deserializedTx, { common }) + assert.ok(minimalTx.blobs === undefined, 'minimal representation contains no blobs') + assert.ok( + equalsBytes(minimalTx.hash(), deserializedTx.hash()), + 'has the same hash as the network wrapper version' + ) - const simpleBlobTx = BlobEIP4844Transaction.fromTxData( - { - blobsData: ['hello world'], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) + const simpleBlobTx = BlobEIP4844Transaction.fromTxData( + { + blobsData: ['hello world'], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) - assert.equal( - bytesToHex(unsignedTx.blobVersionedHashes[0]), - bytesToHex(simpleBlobTx.blobVersionedHashes[0]), - 'tx versioned hash for simplified blob txData constructor matches fully specified versioned hashes' - ) + assert.equal( + bytesToHex(unsignedTx.blobVersionedHashes[0]), + bytesToHex(simpleBlobTx.blobVersionedHashes[0]), + 'tx versioned hash for simplified blob txData constructor matches fully specified versioned hashes' + ) - assert.throws( - () => - BlobEIP4844Transaction.fromTxData( - { - blobsData: ['hello world'], - blobs: ['hello world'], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ), - 'encoded blobs', - undefined, - 'throws on blobsData and blobs in txData' - ) + assert.throws( + () => + BlobEIP4844Transaction.fromTxData( + { + blobsData: ['hello world'], + blobs: ['hello world'], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ), + 'encoded blobs', + undefined, + 'throws on blobsData and blobs in txData' + ) - assert.throws( - () => - BlobEIP4844Transaction.fromTxData( - { - blobsData: ['hello world'], - kzgCommitments: ['0xabcd'], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ), - 'KZG commitments', - undefined, - 'throws on blobsData and KZG commitments in txData' - ) + assert.throws( + () => + BlobEIP4844Transaction.fromTxData( + { + blobsData: ['hello world'], + kzgCommitments: ['0xabcd'], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ), + 'KZG commitments', + undefined, + 'throws on blobsData and KZG commitments in txData' + ) - assert.throws( - () => - BlobEIP4844Transaction.fromTxData( - { - blobsData: ['hello world'], - blobVersionedHashes: ['0x01cd'], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ), - 'versioned hashes', - undefined, - 'throws on blobsData and versioned hashes in txData' - ) + assert.throws( + () => + BlobEIP4844Transaction.fromTxData( + { + blobsData: ['hello world'], + blobVersionedHashes: ['0x01cd'], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ), + 'versioned hashes', + undefined, + 'throws on blobsData and versioned hashes in txData' + ) - assert.throws( - () => - BlobEIP4844Transaction.fromTxData( - { - blobsData: ['hello world'], - kzgProofs: ['0x01cd'], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ), - 'KZG proofs', - undefined, - 'throws on blobsData and KZG proofs in txData' - ) + assert.throws( + () => + BlobEIP4844Transaction.fromTxData( + { + blobsData: ['hello world'], + kzgProofs: ['0x01cd'], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ), + 'KZG proofs', + undefined, + 'throws on blobsData and KZG proofs in txData' + ) - assert.throws( - () => { - BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes: [], - blobs: [], - kzgCommitments: [], - kzgProofs: [], - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) - }, - 'tx should contain at least one blob', - undefined, - 'throws a transaction with no blobs' - ) + assert.throws( + () => { + BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes: [], + blobs: [], + kzgCommitments: [], + kzgProofs: [], + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) + }, + 'tx should contain at least one blob', + undefined, + 'throws a transaction with no blobs' + ) - const txWithMissingBlob = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs: blobs.slice(1), - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) + const txWithMissingBlob = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs: blobs.slice(1), + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) - const serializedWithMissingBlob = txWithMissingBlob.serializeNetworkWrapper() - assert.throws( - () => - BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(serializedWithMissingBlob, { - common, - }), - 'Number of blobVersionedHashes, blobs, and commitments not all equal', - undefined, - 'throws when blobs/commitments/hashes mismatch' - ) + const serializedWithMissingBlob = txWithMissingBlob.serializeNetworkWrapper() - const mangledValue = commitments[0][0] - - commitments[0][0] = 154 - const txWithInvalidCommitment = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) + assert.throws( + () => + BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(serializedWithMissingBlob, { + common, + }), + 'Number of blobVersionedHashes, blobs, and commitments not all equal', + undefined, + 'throws when blobs/commitments/hashes mismatch' + ) - const serializedWithInvalidCommitment = txWithInvalidCommitment.serializeNetworkWrapper() - assert.throws( - () => - BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper( - serializedWithInvalidCommitment, - { - common, - } - ), - 'KZG verification of blobs fail', - undefined, - 'throws when kzg proof cant be verified' - ) + const mangledValue = commitments[0][0] - blobVersionedHashes[0][1] = 2 - commitments[0][0] = mangledValue - - const txWithInvalidVersionedHashes = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffffn, - to: randomBytes(20), - }, - { common } - ) + commitments[0][0] = 154 + const txWithInvalidCommitment = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) - const serializedWithInvalidVersionedHashes = - txWithInvalidVersionedHashes.serializeNetworkWrapper() - assert.throws( - () => - BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper( - serializedWithInvalidVersionedHashes, - { - common, - } - ), - 'commitment for blob at index 0 does not match versionedHash', - undefined, - 'throws when versioned hashes dont match kzg commitments' - ) - } + const serializedWithInvalidCommitment = txWithInvalidCommitment.serializeNetworkWrapper() + + assert.throws( + () => + BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(serializedWithInvalidCommitment, { + common, + }), + 'KZG proof cannot be verified from blobs/commitments', + undefined, + 'throws when kzg proof cant be verified' + ) + + blobVersionedHashes[0][1] = 2 + commitments[0][0] = mangledValue + + const txWithInvalidVersionedHashes = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffffn, + to: randomBytes(20), + }, + { common } + ) + + const serializedWithInvalidVersionedHashes = + txWithInvalidVersionedHashes.serializeNetworkWrapper() + assert.throws( + () => + BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper( + serializedWithInvalidVersionedHashes, + { + common, + } + ), + 'commitment for blob at index 0 does not match versionedHash', + undefined, + 'throws when versioned hashes dont match kzg commitments' + ) }) }) describe('hash() and signature verification', () => { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + }) it('should work', async () => { - if (isBrowser() === false) { - const unsignedTx = BlobEIP4844Transaction.fromTxData( - { - chainId: 1, - nonce: 1, - blobVersionedHashes: [ - hexToBytes('0x01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e'), - ], - maxFeePerBlobGas: 10000000n, - gasLimit: 123457n, - maxFeePerGas: 42n, - maxPriorityFeePerGas: 10n, - accessList: [ - { - address: '0x0000000000000000000000000000000000000001', - storageKeys: ['0x0000000000000000000000000000000000000000000000000000000000000000'], - }, - ], - to: Address.zero(), - }, - { common } - ) - assert.equal( - bytesToHex(unsignedTx.getHashedMessageToSign()), - '0x02560c5173b0d793ce019cfa515ece6a04a4b3f3d67eab67fbca78dd92d4ed76', - 'produced the correct transaction hash' - ) - const signedTx = unsignedTx.sign( - hexToBytes('0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8') - ) + const unsignedTx = BlobEIP4844Transaction.fromTxData( + { + chainId: 1, + nonce: 1, + blobVersionedHashes: [ + hexToBytes('0x01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e'), + ], + maxFeePerBlobGas: 10000000n, + gasLimit: 123457n, + maxFeePerGas: 42n, + maxPriorityFeePerGas: 10n, + accessList: [ + { + address: '0x0000000000000000000000000000000000000001', + storageKeys: ['0x0000000000000000000000000000000000000000000000000000000000000000'], + }, + ], + to: Address.zero(), + }, + { common } + ) + assert.equal( + bytesToHex(unsignedTx.getHashedMessageToSign()), + '0x02560c5173b0d793ce019cfa515ece6a04a4b3f3d67eab67fbca78dd92d4ed76', + 'produced the correct transaction hash' + ) + const signedTx = unsignedTx.sign( + hexToBytes('0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8') + ) - assert.equal( - signedTx.getSenderAddress().toString(), - '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', - 'was able to recover sender address' - ) - assert.ok(signedTx.verifySignature(), 'signature is valid') - } + assert.equal( + signedTx.getSenderAddress().toString(), + '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', + 'was able to recover sender address' + ) + assert.ok(signedTx.verifySignature(), 'signature is valid') }) }) describe('Network wrapper deserialization test', () => { - it('should work', async () => { - const common = Common.fromGethGenesis(gethGenesis, { + let common: Common + beforeAll(async () => { + const kzg = await createKZG() + initKZG(kzg, '') + common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, customCrypto: { kzg, }, }) - if (isBrowser() === false) { - const txData = { - type: '0x3', - nonce: '0x0', - maxPriorityFeePerGas: '0x0', - maxFeePerGas: '0x0', - gasLimit: '0xffffff', - value: '0x0', - data: '0x', - v: '0x0', - r: '0x3d8cacf503f773c3ae4eed2b38ba68859063bc5ad253a4fb456b1295061f1e0b', - s: '0x616727b04ef78f58d2f521774c6261396fc21eac725ba2a2d89758eae171effb', - to: '0x1f738d535998ba73b31f38f1ecf6a6ad013eaa20', - chainId: '0x1', - accessList: [], - maxFeePerBlobGas: '0x5f5e100', - blobVersionedHashes: ['0x0172ff1d4f354eebdb3cd0cb64e41ac584359094373fd5f979bcccbd6072d936'], - } - const txMeta = { - sender: '0x652a2b04934d96c26c4710853021779fb9f525d2', - unsignedHash: '0x3103e9d2b39b26082a6e36fa0364e5b14502efa0041ad29d485737a10e03431a', - hash: '0x0118d156c8b40c92dd6ef10a09ab967904e1c25fb42ec799e80e0a6271013e46', - // 131325 bytes long i.e. ~128KB - networkSerializedHexLength: 262652, // 0x included - serialized: - '0x03f88a0180808083ffffff941f738d535998ba73b31f38f1ecf6a6ad013eaa208080c08405f5e100e1a00172ff1d4f354eebdb3cd0cb64e41ac584359094373fd5f979bcccbd6072d93680a03d8cacf503f773c3ae4eed2b38ba68859063bc5ad253a4fb456b1295061f1e0ba0616727b04ef78f58d2f521774c6261396fc21eac725ba2a2d89758eae171effb', - } - - const blobs = getBlobs('hello world') - - const commitments = blobsToCommitments(blobs) - const proofs = blobsToProofs(blobs, commitments) - - /* eslint-disable @typescript-eslint/no-use-before-define */ - const wrapper = hexToBytes(blobTx.tx) - const deserializedTx = BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(wrapper, { - common, - }) - const jsonData = deserializedTx.toJSON() - assert.deepEqual(txData, jsonData as any, 'toJSON should give correct json') - - assert.equal(deserializedTx.blobs?.length, 1, 'contains the correct number of blobs') - assert.ok(equalsBytes(deserializedTx.blobs![0], blobs[0]), 'blobs should match') - assert.ok( - equalsBytes(deserializedTx.kzgCommitments![0], commitments[0]), - 'commitments should match' - ) - assert.ok(equalsBytes(deserializedTx.kzgProofs![0], proofs[0]), 'proofs should match') + }) + it('should work', async () => { + const txData = { + type: '0x3', + nonce: '0x0', + maxPriorityFeePerGas: '0x0', + maxFeePerGas: '0x0', + gasLimit: '0xffffff', + value: '0x0', + data: '0x', + v: '0x0', + r: '0x3d8cacf503f773c3ae4eed2b38ba68859063bc5ad253a4fb456b1295061f1e0b', + s: '0x616727b04ef78f58d2f521774c6261396fc21eac725ba2a2d89758eae171effb', + to: '0x1f738d535998ba73b31f38f1ecf6a6ad013eaa20', + chainId: '0x1', + accessList: [], + maxFeePerBlobGas: '0x5f5e100', + blobVersionedHashes: ['0x0172ff1d4f354eebdb3cd0cb64e41ac584359094373fd5f979bcccbd6072d936'], + } + const txMeta = { + sender: '0x652a2b04934d96c26c4710853021779fb9f525d2', + unsignedHash: '0x3103e9d2b39b26082a6e36fa0364e5b14502efa0041ad29d485737a10e03431a', + hash: '0x0118d156c8b40c92dd6ef10a09ab967904e1c25fb42ec799e80e0a6271013e46', + // 131325 bytes long i.e. ~128KB + networkSerializedHexLength: 262652, // 0x included + serialized: + '0x03f88a0180808083ffffff941f738d535998ba73b31f38f1ecf6a6ad013eaa208080c08405f5e100e1a00172ff1d4f354eebdb3cd0cb64e41ac584359094373fd5f979bcccbd6072d93680a03d8cacf503f773c3ae4eed2b38ba68859063bc5ad253a4fb456b1295061f1e0ba0616727b04ef78f58d2f521774c6261396fc21eac725ba2a2d89758eae171effb', + } - const unsignedHash = bytesToHex(deserializedTx.getHashedMessageToSign()) - const hash = bytesToHex(deserializedTx.hash()) - const networkSerialized = bytesToHex(deserializedTx.serializeNetworkWrapper()) - const serialized = bytesToHex(deserializedTx.serialize()) - const sender = deserializedTx.getSenderAddress().toString() - assert.equal(networkSerialized, blobTx.tx, 'network serialization should match') + const blobs = getBlobs('hello world') - assert.deepEqual( - txMeta, - { - unsignedHash, - hash, - serialized, - sender, - networkSerializedHexLength: networkSerialized.length, - }, - 'txMeta should match' - ) - } + const commitments = blobsToCommitments(blobs) + const proofs = blobsToProofs(blobs, commitments) + + /* eslint-disable @typescript-eslint/no-use-before-define */ + const wrapper = hexToBytes(blobTx.tx) + const deserializedTx = BlobEIP4844Transaction.fromSerializedBlobTxNetworkWrapper(wrapper, { + common, + }) + const jsonData = deserializedTx.toJSON() + assert.deepEqual(txData, jsonData as any, 'toJSON should give correct json') + + assert.equal(deserializedTx.blobs?.length, 1, 'contains the correct number of blobs') + assert.ok(equalsBytes(deserializedTx.blobs![0], blobs[0]), 'blobs should match') + assert.ok( + equalsBytes(deserializedTx.kzgCommitments![0], commitments[0]), + 'commitments should match' + ) + assert.ok(equalsBytes(deserializedTx.kzgProofs![0], proofs[0]), 'proofs should match') + + const unsignedHash = bytesToHex(deserializedTx.getHashedMessageToSign()) + const hash = bytesToHex(deserializedTx.hash()) + const networkSerialized = bytesToHex(deserializedTx.serializeNetworkWrapper()) + const serialized = bytesToHex(deserializedTx.serialize()) + const sender = deserializedTx.getSenderAddress().toString() + assert.equal(networkSerialized, blobTx.tx, 'network serialization should match') + + assert.deepEqual( + txMeta, + { + unsignedHash, + hash, + serialized, + sender, + networkSerializedHexLength: networkSerialized.length, + }, + 'txMeta should match' + ) }) }) diff --git a/packages/tx/vitest.config.browser.ts b/packages/tx/vitest.config.browser.ts index d2c82bb0ac..cbd210e7f5 100644 --- a/packages/tx/vitest.config.browser.ts +++ b/packages/tx/vitest.config.browser.ts @@ -4,11 +4,12 @@ export default defineConfig({ test: { exclude: [ ...configDefaults.exclude, - // c-kzg dependency - 'test/eip4844.spec.ts', // default export for minimist // wrong ethereum-tests path reference (../ is stripped) 'test/transactionRunner.spec.ts', ], }, + optimizeDeps: { + exclude: ['kzg-wasm'], + }, }) diff --git a/packages/util/package.json b/packages/util/package.json index 38833cea1d..39e0a516bd 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -94,14 +94,8 @@ "@ethereumjs/rlp": "^5.0.2", "ethereum-cryptography": "^2.1.3" }, - "devDependencies": {}, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } + "devDependencies": { + "kzg-wasm": "^0.1.0" }, "engines": { "node": ">=18" diff --git a/packages/vm/package.json b/packages/vm/package.json index da3d1d42b1..16a54f3e57 100644 --- a/packages/vm/package.json +++ b/packages/vm/package.json @@ -82,7 +82,6 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", - "c-kzg": "^2.1.2", "minimist": "^1.2.5", "node-dir": "^0.1.17", "nyc": "^15.1.0", diff --git a/packages/vm/test/api/EIPs/eip-2565-modexp-gas-cost.spec.ts b/packages/vm/test/api/EIPs/eip-2565-modexp-gas-cost.spec.ts index 3c27c7096c..4303c596b0 100644 --- a/packages/vm/test/api/EIPs/eip-2565-modexp-gas-cost.spec.ts +++ b/packages/vm/test/api/EIPs/eip-2565-modexp-gas-cost.spec.ts @@ -2,10 +2,11 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common' import { Address, bytesToHex, equalsBytes, hexToBytes } from '@ethereumjs/util' import { assert, describe, it } from 'vitest' -import { VM } from '../../../src/vm' +// eslint-disable-next-line import/order +import { VM } from '../../../src/vm.js' // See https://github.com/holiman/go-ethereum/blob/2c99023b68c573ba24a5b01db13e000bd9b82417/core/vm/testdata/precompiles/modexp_eip2565.json -const testData = require('../testdata/eip-2565.json') +import testData from '../testdata/eip-2565.json' describe('EIP-2565 ModExp gas cost tests', () => { it('Test return data, gas cost and execution status against testdata', async () => { diff --git a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts index b0c5ba4b21..320d80f312 100644 --- a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts @@ -14,103 +14,99 @@ import { privateToAddress, zeros, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import * as genesisJSON from '../../../../client/test/testdata/geth-genesis/eip4844.json' import { VM } from '../../../src/vm' import { setBalance } from '../utils' -// Hack to detect if running in browser or not -const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') - const pk = hexToBytes('0x' + '20'.repeat(32)) const sender = bytesToHex(privateToAddress(pk)) describe('EIP4844 tests', () => { it('should build a block correctly with blobs', async () => { - if (isBrowser() === false) { + let kzg + { try { - initKZG(kzg, __dirname + '/../../../../client/src/trustedSetups/official.txt') + //initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') + kzg = await createKZG() + initKZG(kzg, '') } catch { // no-op } - const common = Common.fromGethGenesis(genesisJSON, { - chain: 'eip4844', - hardfork: Hardfork.Cancun, - customCrypto: { kzg }, - }) - const genesisBlock = Block.fromBlockData( - { header: { gasLimit: 50000, parentBeaconBlockRoot: zeros(32) } }, - { common } - ) - const blockchain = await Blockchain.create({ - genesisBlock, - common, - validateBlocks: false, - validateConsensus: false, - }) - const vm = await VM.create({ common, blockchain }) + } + const common = Common.fromGethGenesis(genesisJSON, { + chain: 'eip4844', + hardfork: Hardfork.Cancun, + customCrypto: { kzg }, + }) + const genesisBlock = Block.fromBlockData( + { header: { gasLimit: 50000, parentBeaconBlockRoot: zeros(32) } }, + { common } + ) + const blockchain = await Blockchain.create({ + genesisBlock, + common, + validateBlocks: false, + validateConsensus: false, + }) + const vm = await VM.create({ common, blockchain }) - const address = Address.fromString(sender) - await setBalance(vm, address, 14680063125000000000n) - const vmCopy = await vm.shallowCopy() + const address = Address.fromString(sender) + await setBalance(vm, address, 14680063125000000000n) + const vmCopy = await vm.shallowCopy() - const blockBuilder = await vm.buildBlock({ - parentBlock: genesisBlock, - withdrawals: [], - blockOpts: { - calcDifficultyFromHeader: genesisBlock.header, - freeze: false, - }, - headerData: { - gasLimit: 0xffffn, - }, - }) + const blockBuilder = await vm.buildBlock({ + parentBlock: genesisBlock, + withdrawals: [], + blockOpts: { + calcDifficultyFromHeader: genesisBlock.header, + freeze: false, + }, + headerData: { + gasLimit: 0xffffn, + }, + }) - // Set up tx - const blobs = getBlobs('hello world') - const commitments = blobsToCommitments(blobs) - const blobVersionedHashes = commitmentsToVersionedHashes(commitments) - const proofs = blobsToProofs(blobs, commitments) - const unsignedTx = BlobEIP4844Transaction.fromTxData( - { - blobVersionedHashes, - blobs, - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerGas: 10000000000n, - maxFeePerBlobGas: 100000000n, - gasLimit: 0xffffn, - to: hexToBytes('0xffb38a7a99e3e2335be83fc74b7faa19d5531243'), - }, - { common } - ) - const signedTx = unsignedTx.sign(pk) + // Set up tx + const blobs = getBlobs('hello world') + const commitments = blobsToCommitments(blobs) + const blobVersionedHashes = commitmentsToVersionedHashes(commitments) + const proofs = blobsToProofs(blobs, commitments) + const unsignedTx = BlobEIP4844Transaction.fromTxData( + { + blobVersionedHashes, + blobs, + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerGas: 10000000000n, + maxFeePerBlobGas: 100000000n, + gasLimit: 0xffffn, + to: hexToBytes('0xffb38a7a99e3e2335be83fc74b7faa19d5531243'), + }, + { common } + ) + const signedTx = unsignedTx.sign(pk) - await blockBuilder.addTransaction(signedTx) + await blockBuilder.addTransaction(signedTx) - const block = await blockBuilder.build() - assert.equal(block.transactions.length, 1, 'blob transaction should be included') - assert.equal( - bytesToHex(block.transactions[0].hash()), - bytesToHex(signedTx.hash()), - 'blob transaction should be same' - ) + const block = await blockBuilder.build() + assert.equal(block.transactions.length, 1, 'blob transaction should be included') + assert.equal( + bytesToHex(block.transactions[0].hash()), + bytesToHex(signedTx.hash()), + 'blob transaction should be same' + ) - const blobGasPerBlob = common.param('gasConfig', 'blobGasPerBlob') - assert.equal( - block.header.blobGasUsed, - blobGasPerBlob, - 'blob gas used for 1 blob should match' - ) + const blobGasPerBlob = common.param('gasConfig', 'blobGasPerBlob') + assert.equal(block.header.blobGasUsed, blobGasPerBlob, 'blob gas used for 1 blob should match') - // block should successfully execute with VM.runBlock and have same outputs - const result = await vmCopy.runBlock({ block, skipBlockValidation: true }) - assert.equal(result.gasUsed, block.header.gasUsed) - assert.deepEqual(result.receiptsRoot, block.header.receiptTrie) - assert.deepEqual(result.stateRoot, block.header.stateRoot) - assert.deepEqual(result.logsBloom, block.header.logsBloom) - } + // block should successfully execute with VM.runBlock and have same outputs + const result = await vmCopy.runBlock({ block, skipBlockValidation: true }) + assert.equal(result.gasUsed, block.header.gasUsed) + assert.deepEqual(result.receiptsRoot, block.header.receiptTrie) + assert.deepEqual(result.stateRoot, block.header.stateRoot) + assert.deepEqual(result.logsBloom, block.header.logsBloom) }) }) diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 907935fe3d..228113d021 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -19,7 +19,7 @@ import { initKZG, zeros, } from '@ethereumjs/util' -import * as kzg from 'c-kzg' +import { createKZG } from 'kzg-wasm' import { assert, describe, it } from 'vitest' import { VM } from '../../src/vm' @@ -880,16 +880,8 @@ it('Validate SELFDESTRUCT does not charge new account gas when calling CALLER an describe('EIP 4844 transaction tests', () => { it('should work', async () => { - // Hack to detect if running in browser or not - const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') - - if (isBrowser() === false) { - try { - initKZG(kzg, __dirname + '/../../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } - } + const kzg = await createKZG() + initKZG(kzg, '') const genesisJson = require('../../../block/test/testdata/4844-hardfork.json') const common = Common.fromGethGenesis(genesisJson, { diff --git a/packages/vm/test/tester/config.ts b/packages/vm/test/tester/config.ts index ae98ee336f..cf78393ca5 100644 --- a/packages/vm/test/tester/config.ts +++ b/packages/vm/test/tester/config.ts @@ -1,8 +1,8 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common' -import { initKZG } from '@ethereumjs/util' -import * as kzg from 'c-kzg' import * as path from 'path' +import type { Kzg } from '@ethereumjs/util' + /** * Default tests path (git submodule: ethereum-tests) */ @@ -207,7 +207,7 @@ export function getTestDirs(network: string, testType: string) { * @param ttd If set: total terminal difficulty to switch to merge * @returns */ -function setupCommonWithNetworks(network: string, ttd?: number, timestamp?: number) { +function setupCommonWithNetworks(network: string, ttd?: number, timestamp?: number, kzg?: Kzg) { let networkLowercase: string // This only consists of the target hardfork, so without the EIPs if (network.includes('+')) { const index = network.indexOf('+') @@ -259,11 +259,6 @@ function setupCommonWithNetworks(network: string, ttd?: number, timestamp?: numb } } } - try { - initKZG(kzg, __dirname + '/../../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } const common = Common.custom( { hardforks: testHardforks, @@ -288,7 +283,7 @@ function setupCommonWithNetworks(network: string, ttd?: number, timestamp?: numb * For instance, "London+3855+3860" will also activate EIP-3855 and EIP-3860. * @returns the Common which should be used */ -export function getCommon(network: string): Common { +export function getCommon(network: string, kzg?: Kzg): Common { if (retestethAlias[network as keyof typeof retestethAlias] !== undefined) { network = retestethAlias[network as keyof typeof retestethAlias] } @@ -299,7 +294,7 @@ export function getCommon(network: string): Common { } if (normalHardforks.map((str) => str.toLowerCase()).includes(networkLowercase)) { // Case 1: normal network, such as "London" or "Byzantium" (without any EIPs enabled, and it is not a transition network) - return setupCommonWithNetworks(network) + return setupCommonWithNetworks(network, undefined, undefined, kzg) } else if (networkLowercase.match('tomergeatdiff')) { // Case 2: special case of a transition network, this setups the right common with the right Merge properties (TTD) // This is a HF -> Merge transition @@ -307,9 +302,9 @@ export function getCommon(network: string): Common { const end = start + 'tomergeatdiff'.length const startNetwork = network.substring(0, start) // HF before the merge const TTD = Number('0x' + network.substring(end)) // Total difficulty to transition to PoS - return setupCommonWithNetworks(startNetwork, TTD) + return setupCommonWithNetworks(startNetwork, TTD, undefined, kzg) } else if (networkLowercase === 'shanghaitocancunattime15k') { - return setupCommonWithNetworks('Shanghai', undefined, 15000) + return setupCommonWithNetworks('Shanghai', undefined, 15000, kzg) } else { // Case 3: this is not a "default fork" network, but it is a "transition" network. Test the VM if it transitions the right way const transitionForks = @@ -346,11 +341,6 @@ export function getCommon(network: string): Common { }) } } - try { - initKZG(kzg, __dirname + '/../../../client/src/trustedSetups/official.txt') - } catch { - // no-op - } const common = Common.custom( { hardforks: testHardforks, diff --git a/packages/vm/test/tester/index.ts b/packages/vm/test/tester/index.ts index 1e7be8ae13..1ad81fcdd5 100755 --- a/packages/vm/test/tester/index.ts +++ b/packages/vm/test/tester/index.ts @@ -1,3 +1,5 @@ +import { initKZG } from '@ethereumjs/util' +import { createKZG } from 'kzg-wasm' import * as minimist from 'minimist' import * as path from 'path' import * as process from 'process' @@ -99,6 +101,8 @@ async function runTests() { /** * Run-time configuration */ + const kzg = await createKZG() + initKZG(kzg, '') const runnerArgs: { forkConfigVM: string forkConfigTestSuite: string @@ -114,7 +118,7 @@ async function runTests() { } = { forkConfigVM: FORK_CONFIG_VM, forkConfigTestSuite: FORK_CONFIG_TEST_SUITE, - common: getCommon(FORK_CONFIG_VM), + common: getCommon(FORK_CONFIG_VM, kzg), jsontrace: argv.jsontrace, dist: argv.dist, data: argv.data, // GeneralStateTests diff --git a/packages/vm/vite.config.ts b/packages/vm/vite.config.ts index e620c08fb8..67047c5807 100644 --- a/packages/vm/vite.config.ts +++ b/packages/vm/vite.config.ts @@ -4,4 +4,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ plugins: [wasm(), topLevelAwait()], + optimizeDeps: { + exclude: ['kzg-wasm'], + }, }) From 0b366a25413671d54a0162752e52eafa3209128e Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 29 Feb 2024 13:07:30 +0100 Subject: [PATCH 74/75] Make trustedSetupPath in Util kzg module optional (#3296) --- packages/block/examples/4844.ts | 2 +- packages/block/test/eip4844block.spec.ts | 6 +++--- packages/block/test/from-beacon-payload.spec.ts | 4 ++-- packages/client/bin/cli.ts | 2 +- .../devnets/4844-interop/tools/txGenerator.ts | 2 +- packages/client/test/miner/pendingBlock.spec.ts | 2 +- .../client/test/rpc/engine/getPayloadV3.spec.ts | 2 +- packages/client/test/rpc/engine/kaustinen2.spec.ts | 2 +- .../rpc/engine/newPayloadV3VersionedHashes.spec.ts | 2 +- .../client/test/rpc/eth/getBlockByNumber.spec.ts | 2 +- .../test/rpc/eth/getTransactionReceipt.spec.ts | 2 +- .../client/test/rpc/eth/sendRawTransaction.spec.ts | 2 +- packages/common/examples/initKzg.ts | 2 +- .../test/precompiles/0a-pointevaluation.spec.ts | 2 +- packages/tx/examples/blobTx.ts | 2 +- packages/tx/examples/initKzg.ts | 2 +- packages/tx/test/eip4844.spec.ts | 14 +++++++------- packages/util/src/kzg.ts | 4 ++-- packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts | 2 +- packages/vm/test/api/runTx.spec.ts | 2 +- packages/vm/test/tester/index.ts | 2 +- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/block/examples/4844.ts b/packages/block/examples/4844.ts index 8c1ae64296..bc2a9fe049 100644 --- a/packages/block/examples/4844.ts +++ b/packages/block/examples/4844.ts @@ -7,7 +7,7 @@ import { randomBytes } from 'crypto' const main = async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Cancun, diff --git a/packages/block/test/eip4844block.spec.ts b/packages/block/test/eip4844block.spec.ts index 2847fa79ec..c2b86400f8 100644 --- a/packages/block/test/eip4844block.spec.ts +++ b/packages/block/test/eip4844block.spec.ts @@ -23,7 +23,7 @@ describe('EIP4844 header tests', () => { beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -102,7 +102,7 @@ describe('blob gas tests', () => { let blobGasPerBlob: bigint beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -156,7 +156,7 @@ describe('transaction validation tests', () => { let blobGasPerBlob: bigint beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/block/test/from-beacon-payload.spec.ts b/packages/block/test/from-beacon-payload.spec.ts index 9916ac8832..c4d75009a6 100644 --- a/packages/block/test/from-beacon-payload.spec.ts +++ b/packages/block/test/from-beacon-payload.spec.ts @@ -16,7 +16,7 @@ describe('[fromExecutionPayloadJson]: 4844 devnet 5', () => { let common: Common beforeAll(async () => { kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const commonJson = { ...shardingJson } commonJson.config = { ...commonJson.config, chainId: 4844001005 } const network = 'sharding' @@ -80,7 +80,7 @@ describe('[fromExecutionPayloadJson]: kaustinen', () => { let kzg beforeAll(async () => { kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) }) const network = 'kaustinen' diff --git a/packages/client/bin/cli.ts b/packages/client/bin/cli.ts index 2d9aefddcf..4c57473185 100755 --- a/packages/client/bin/cli.ts +++ b/packages/client/bin/cli.ts @@ -807,7 +807,7 @@ async function run() { const chain = args.networkId ?? args.network ?? Chain.Mainnet const cryptoFunctions: CustomCrypto = {} const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) // Initialize WASM crypto if JS crypto is not specified if (args.useJsCrypto === false) { diff --git a/packages/client/devnets/4844-interop/tools/txGenerator.ts b/packages/client/devnets/4844-interop/tools/txGenerator.ts index 1e178f111a..0eaa80ceef 100644 --- a/packages/client/devnets/4844-interop/tools/txGenerator.ts +++ b/packages/client/devnets/4844-interop/tools/txGenerator.ts @@ -29,7 +29,7 @@ async function getNonce(client: Client, account: string) { async function run(data: any) { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = Common.fromGethGenesis(genesisJson, { chain: genesisJson.ChainName ?? 'devnet', diff --git a/packages/client/test/miner/pendingBlock.spec.ts b/packages/client/test/miner/pendingBlock.spec.ts index dfa6655fe5..37bc721657 100644 --- a/packages/client/test/miner/pendingBlock.spec.ts +++ b/packages/client/test/miner/pendingBlock.spec.ts @@ -354,7 +354,7 @@ describe('[PendingBlock]', async () => { it('construct blob bundles', async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/client/test/rpc/engine/getPayloadV3.spec.ts b/packages/client/test/rpc/engine/getPayloadV3.spec.ts index dda7639137..1b4618ac30 100644 --- a/packages/client/test/rpc/engine/getPayloadV3.spec.ts +++ b/packages/client/test/rpc/engine/getPayloadV3.spec.ts @@ -69,7 +69,7 @@ describe(method, () => { } const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const { service, server, common } = await setupChain(genesisJSON, 'post-merge', { engine: true, diff --git a/packages/client/test/rpc/engine/kaustinen2.spec.ts b/packages/client/test/rpc/engine/kaustinen2.spec.ts index 1240b9f9c3..c0b4c7394b 100644 --- a/packages/client/test/rpc/engine/kaustinen2.spec.ts +++ b/packages/client/test/rpc/engine/kaustinen2.spec.ts @@ -34,7 +34,7 @@ async function runBlock( describe(`valid verkle network setup`, async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const { server, chain, common } = await setupChain(genesisJSON, 'post-merge', { engine: true, diff --git a/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts b/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts index 57cc90adc2..ed3ad75b1f 100644 --- a/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts +++ b/packages/client/test/rpc/engine/newPayloadV3VersionedHashes.spec.ts @@ -16,7 +16,7 @@ const [blockData] = blocks describe(`${method}: Cancun validations`, () => { it('blobVersionedHashes', async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const { server } = await setupChain(genesisJSON, 'post-merge', { engine: true, diff --git a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts index 349ce7b616..03badda8fd 100644 --- a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts +++ b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts @@ -9,7 +9,7 @@ import { INVALID_PARAMS } from '../../../src/rpc/error-code.js' import { createClient, createManager, dummy, getRpcClient, startRPC } from '../helpers.js' const kzg = await createKZG() -initKZG(kzg, '') +initKZG(kzg) const common = Common.custom({ chainId: 1 }, { customCrypto: { kzg } }) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 9b555541f8..6c32b3dfb2 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -90,7 +90,7 @@ describe(method, () => { const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', diff --git a/packages/client/test/rpc/eth/sendRawTransaction.spec.ts b/packages/client/test/rpc/eth/sendRawTransaction.spec.ts index 27fc50e35e..449099402b 100644 --- a/packages/client/test/rpc/eth/sendRawTransaction.spec.ts +++ b/packages/client/test/rpc/eth/sendRawTransaction.spec.ts @@ -221,7 +221,7 @@ describe(method, () => { const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', diff --git a/packages/common/examples/initKzg.ts b/packages/common/examples/initKzg.ts index 39abd25831..a8bfd78061 100644 --- a/packages/common/examples/initKzg.ts +++ b/packages/common/examples/initKzg.ts @@ -4,7 +4,7 @@ import { initKZG } from '@ethereumjs/util' const main = async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Cancun, diff --git a/packages/evm/test/precompiles/0a-pointevaluation.spec.ts b/packages/evm/test/precompiles/0a-pointevaluation.spec.ts index 235090b65d..618990f995 100644 --- a/packages/evm/test/precompiles/0a-pointevaluation.spec.ts +++ b/packages/evm/test/precompiles/0a-pointevaluation.spec.ts @@ -23,7 +23,7 @@ describe('Precompiles: point evaluation', () => { const genesisJSON = await import('../../../client/test/testdata/geth-genesis/eip4844.json') const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = Common.fromGethGenesis(genesisJSON, { chain: 'custom', diff --git a/packages/tx/examples/blobTx.ts b/packages/tx/examples/blobTx.ts index c56279366a..86e9a0e7e6 100644 --- a/packages/tx/examples/blobTx.ts +++ b/packages/tx/examples/blobTx.ts @@ -5,7 +5,7 @@ import { createKZG } from 'kzg-wasm' const main = async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const common = new Common({ chain: Chain.Mainnet, diff --git a/packages/tx/examples/initKzg.ts b/packages/tx/examples/initKzg.ts index 86e8e81b29..94c2905ab9 100644 --- a/packages/tx/examples/initKzg.ts +++ b/packages/tx/examples/initKzg.ts @@ -4,7 +4,7 @@ import { initKZG } from '@ethereumjs/util' const main = async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) // Instantiate `common` const common = new Common({ diff --git a/packages/tx/test/eip4844.spec.ts b/packages/tx/test/eip4844.spec.ts index 53ea0bffa7..0e338d7129 100644 --- a/packages/tx/test/eip4844.spec.ts +++ b/packages/tx/test/eip4844.spec.ts @@ -26,7 +26,7 @@ describe('EIP4844 addSignature tests', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -91,7 +91,7 @@ describe('EIP4844 constructor tests - valid scenarios', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -130,7 +130,7 @@ describe('fromTxData using from a json', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -202,7 +202,7 @@ describe('EIP4844 constructor tests - invalid scenarios', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -259,7 +259,7 @@ describe('Network wrapper tests', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -503,7 +503,7 @@ describe('hash() and signature verification', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, @@ -554,7 +554,7 @@ describe('Network wrapper deserialization test', () => { let common: Common beforeAll(async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', hardfork: Hardfork.Cancun, diff --git a/packages/util/src/kzg.ts b/packages/util/src/kzg.ts index f0929f872c..54ae45d685 100644 --- a/packages/util/src/kzg.ts +++ b/packages/util/src/kzg.ts @@ -2,7 +2,7 @@ * Interface for an externally provided kzg library used when creating blob transactions */ export interface Kzg { - loadTrustedSetup(filePath: string): void + loadTrustedSetup(filePath?: string): void blobToKzgCommitment(blob: Uint8Array): Uint8Array computeBlobKzgProof(blob: Uint8Array, commitment: Uint8Array): Uint8Array verifyKzgProof( @@ -35,7 +35,7 @@ export let kzg: Kzg = { * @param kzgLib a KZG implementation (defaults to c-kzg) * @param trustedSetupPath the full path (e.g. "/home/linux/devnet4.txt") to a kzg trusted setup text file */ -export function initKZG(kzgLib: Kzg, trustedSetupPath: string) { +export function initKZG(kzgLib: Kzg, trustedSetupPath?: string) { kzg = kzgLib kzg.loadTrustedSetup(trustedSetupPath) } diff --git a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts index 320d80f312..bac39aa401 100644 --- a/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4844-blobs.spec.ts @@ -31,7 +31,7 @@ describe('EIP4844 tests', () => { try { //initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) } catch { // no-op } diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 228113d021..2b664cef1c 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -881,7 +881,7 @@ it('Validate SELFDESTRUCT does not charge new account gas when calling CALLER an describe('EIP 4844 transaction tests', () => { it('should work', async () => { const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const genesisJson = require('../../../block/test/testdata/4844-hardfork.json') const common = Common.fromGethGenesis(genesisJson, { diff --git a/packages/vm/test/tester/index.ts b/packages/vm/test/tester/index.ts index 1ad81fcdd5..f7c8bc1722 100755 --- a/packages/vm/test/tester/index.ts +++ b/packages/vm/test/tester/index.ts @@ -102,7 +102,7 @@ async function runTests() { * Run-time configuration */ const kzg = await createKZG() - initKZG(kzg, '') + initKZG(kzg) const runnerArgs: { forkConfigVM: string forkConfigTestSuite: string From 1408e29f65cc79a935dc6dece6180f6775820bfb Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Thu, 29 Feb 2024 17:02:43 -0500 Subject: [PATCH 75/75] client: add tx preimages to preimage test cases --- packages/client/test/rpc/engine/preimages.spec.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/client/test/rpc/engine/preimages.spec.ts b/packages/client/test/rpc/engine/preimages.spec.ts index 522e04f285..e5c8350a96 100644 --- a/packages/client/test/rpc/engine/preimages.spec.ts +++ b/packages/client/test/rpc/engine/preimages.spec.ts @@ -175,6 +175,9 @@ describe(`valid verkle network setup`, async () => { '0x2600000000000000000000000000000000000000', '0x2700000000000000000000000000000000000000', // txs + '0x7e454a14b8e7528465eef86f0dc1da4f235d9d79', + '0x6177843db3138ae69679a54b95cf345ed759450d', + '0x687704db07e902e9a8b3754031d168d46e3d586e', ], }, { @@ -203,7 +206,7 @@ describe(`valid verkle network setup`, async () => { ], }, { - name: 'block 4 no txs with just withdrawals', + name: 'block 4 with kaustinen block13 txs and withdrawals', blockData: { transactions: blocks.block13.execute.transactions, blockNumber: '0x04', @@ -224,8 +227,14 @@ describe(`valid verkle network setup`, async () => { '0x4500000000000000000000000000000000000000', '0x4600000000000000000000000000000000000000', '0x4700000000000000000000000000000000000000', + // txs + '0x687704db07e902e9a8b3754031d168d46e3d586e', + '0xdfd66120239099c0a9ad623a5af2b26ea6b4fb8d', + '0xbbbbde4ca27f83fc18aa108170547ff57675936a', + '0x6177843db3138ae69679a54b95cf345ed759450d', + '0x2971704d406f9efef2f4a36ea2a40aa994922fb9', + '0xad692144cd452a8a85bf683b2a80bb22aab2f9ed', ], - // no txs }, ] as const