Skip to content

Commit

Permalink
EVM/Monorepo: Verkle Decoupling (#3462)
Browse files Browse the repository at this point in the history
* EVM: Replace direct StatelessVerkleStateManager (SVSM) cast with verkle-extended interface usage

* Add experimental AccessWitnessInterface to Common, use interface for AccessWitness implementation in StateManager

* Use AccessWitnessInterface in EVM

* Add verkle module to Util, replace EVM function calls, remove @ethereumjs/verkle dependency

* Rebuild package-lock.json

* Move VerkleCrypto type from verkle-cryptography-wasm to Util

* Make verkleCrypto passing in mandatory in StatelessVerkleStateManager, remove async create constructor, move verkle-cryptography-wasm to dev dependenciew

* Replace additional StatelessVerkleStateManager create() constructor instantiations, add verkle-cryptography-wasm to Client package.json

* Rebuild package-lock.json

* Move verkle helper functionality to Util verkle module, fully remove @ethereumjs/verkle usages

* Update VerkleExecutionWitness, VerkleProof type imports moved to Util

* Remove @ethereumjs/verkle dependency from VM

* Rebuild package-lock.json

* Additional import fix

* Yet another fix

* Merge remote-tracking branch 'origin/master' into verkle-statemanager-interface-and-evm-dependency-removal
  • Loading branch information
holgerd77 authored Jun 19, 2024
1 parent b570ca1 commit 1acacb8
Show file tree
Hide file tree
Showing 27 changed files with 371 additions and 136 deletions.
10 changes: 4 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/block/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import type {
JsonBlock,
JsonRpcBlock,
RequestsBytes,
VerkleExecutionWitness,
WithdrawalsBytes,
} from './types.js'
import type { Common } from '@ethereumjs/common'
Expand All @@ -53,6 +52,7 @@ import type {
EthersProvider,
PrefixedHexString,
RequestBytes,
VerkleExecutionWitness,
WithdrawalBytes,
} from '@ethereumjs/util'

Expand Down
4 changes: 2 additions & 2 deletions packages/block/src/from-beacon-payload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { bigIntToHex } from '@ethereumjs/util'

import type { ExecutionPayload, VerkleExecutionWitness } from './types.js'
import type { PrefixedHexString } from '@ethereumjs/util'
import type { ExecutionPayload } from './types.js'
import type { PrefixedHexString, VerkleExecutionWitness } from '@ethereumjs/util'

type BeaconWithdrawal = {
index: PrefixedHexString
Expand Down
40 changes: 1 addition & 39 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
JsonRpcWithdrawal,
PrefixedHexString,
RequestBytes,
VerkleExecutionWitness,
WithdrawalBytes,
WithdrawalData,
WithdrawalRequestV1,
Expand Down Expand Up @@ -78,45 +79,6 @@ export interface BlockOptions {
executionWitness?: VerkleExecutionWitness
}

export interface VerkleProof {
commitmentsByPath: PrefixedHexString[]
d: PrefixedHexString
depthExtensionPresent: PrefixedHexString
ipaProof: {
cl: PrefixedHexString[]
cr: PrefixedHexString[]
finalEvaluation: PrefixedHexString
}
otherStems: PrefixedHexString[]
}

export interface VerkleStateDiff {
stem: PrefixedHexString
suffixDiffs: {
currentValue: PrefixedHexString | null
newValue: PrefixedHexString | null
suffix: number | string
}[]
}

/**
* Experimental, object format could eventual change.
* An object that provides the state and proof necessary for verkle stateless execution
* */
export interface VerkleExecutionWitness {
/**
* An array of state diffs.
* Each item corresponding to state accesses or state modifications of the block.
* In the current design, it also contains the resulting state of the block execution (post-state).
*/
stateDiff: VerkleStateDiff[]
/**
* The verkle proof for the block.
* Proves that the provided stateDiff belongs to the canonical verkle tree.
*/
verkleProof: VerkleProof
}

/**
* A block header's data.
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/block/test/from-beacon-payload.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ 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'

import type { BeaconPayloadJson, VerkleExecutionWitness } from '../src/index.js'
import type { BeaconPayloadJson } from '../src/index.js'
import type { VerkleExecutionWitness } from '@ethereumjs/util'

describe('[fromExecutionPayloadJson]: 4844 devnet 5', () => {
let common: Common
Expand Down
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"level": "^8.0.0",
"memory-level": "^1.0.0",
"prom-client": "^15.1.0",
"verkle-cryptography-wasm": "^0.4.2",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.5",
"yargs": "^17.7.1"
Expand Down
5 changes: 4 additions & 1 deletion packages/client/src/execution/vmexecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'
import { writeFileSync } from 'fs'
import { loadVerkleCrypto } from 'verkle-cryptography-wasm'

import { Event } from '../types.js'
import { debugCodeReplayBlock } from '../util/debug.js'
Expand Down Expand Up @@ -190,8 +191,10 @@ export class VMExecution extends Execution {
return
}
this.config.logger.info(`Setting up verkleVM`)
const stateManager = await StatelessVerkleStateManager.create({
const verkleCrypto = await loadVerkleCrypto()
const stateManager = new StatelessVerkleStateManager({
initialStateRoot: this.config.initialVerkleStateRoot,
verkleCrypto,
})
this.verkleVM = await VM.create({
common: this.config.execCommon,
Expand Down
3 changes: 2 additions & 1 deletion packages/client/test/rpc/engine/kaustinen6.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import genesisJSON from '../../testdata/geth-genesis/kaustinen6.json'
import { getRpcClient, setupChain } from '../helpers.js'

import type { Chain } from '../../../src/blockchain/index.js'
import type { BeaconPayloadJson, VerkleExecutionWitness } from '@ethereumjs/block'
import type { BeaconPayloadJson } from '@ethereumjs/block'
import type { Common } from '@ethereumjs/common'
import type { VerkleExecutionWitness } from '@ethereumjs/util'
import type { HttpClient } from 'jayson/promise'
const genesisVerkleStateRoot = '0x1fbf85345a3cbba9a6d44f991b721e55620a22397c2a93ee8d5011136ac300ee'
const genesisVerkleBlockHash = '0x3fe165c03e7a77d1e3759362ebeeb16fd964cb411ce11fbe35c7032fab5b9a8a'
Expand Down
65 changes: 65 additions & 0 deletions packages/common/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,64 @@ export type AccessListBytesItem = [Uint8Array, Uint8Array[]]
export type AccessListBytes = AccessListBytesItem[]
export type AccessList = AccessListItem[]

/**
* Verkle related
*
* Experimental (do not implement)
*/
export type AccessEventFlags = {
stemRead: boolean
stemWrite: boolean
chunkRead: boolean
chunkWrite: boolean
chunkFill: boolean
}

/**
* Verkle related
*
* Experimental (do not implement)
*/
export interface AccessWitnessInterface {
touchAndChargeProofOfAbsence(address: Address): bigint
touchAndChargeMessageCall(address: Address): bigint
touchAndChargeValueTransfer(caller: Address, target: Address): bigint
touchAndChargeContractCreateInit(address: Address): bigint
touchAndChargeContractCreateCompleted(address: Address): bigint
touchTxOriginAndComputeGas(origin: Address): bigint
touchTxTargetAndComputeGas(target: Address, { sendsValue }: { sendsValue?: boolean }): bigint
touchCodeChunksRangeOnReadAndChargeGas(contact: Address, startPc: number, endPc: number): bigint
touchCodeChunksRangeOnWriteAndChargeGas(contact: Address, startPc: number, endPc: number): bigint
touchAddressOnWriteAndComputeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array
): bigint
touchAddressOnReadAndComputeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array
): bigint
touchAddressAndChargeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
{ isWrite }: { isWrite?: boolean }
): bigint
touchAddress(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
{ isWrite }: { isWrite?: boolean }
): AccessEventFlags
shallowCopy(): AccessWitnessInterface
merge(accessWitness: AccessWitnessInterface): void
}

/*
* Generic StateManager interface corresponding with the @ethereumjs/statemanager package
*
*/
export interface StateManagerInterface {
getAccount(address: Address): Promise<Account | undefined>
putAccount(address: Address, account?: Account): Promise<void>
Expand All @@ -85,6 +143,13 @@ export interface StateManagerInterface {
hasStateRoot(root: Uint8Array): Promise<boolean> // only used in client
shallowCopy(downlevelCaches?: boolean): StateManagerInterface
getAppliedKey?(address: Uint8Array): Uint8Array

/*
* The following optional methods are Verkle related
*
* Experimental (do not implement)
*/
checkChunkWitnessPresent?(contract: Address, programCounter: number): Promise<boolean>
}

export interface EVMStateManagerInterface extends StateManagerInterface {
Expand Down
1 change: 0 additions & 1 deletion packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
"@ethereumjs/statemanager": "^2.3.0",
"@ethereumjs/tx": "^5.3.0",
"@ethereumjs/util": "^9.0.3",
"@ethereumjs/verkle": "^0.0.2",
"@types/debug": "^4.1.9",
"debug": "^4.3.3",
"ethereum-cryptography": "^2.1.3",
Expand Down
9 changes: 3 additions & 6 deletions packages/evm/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ import type { EVM } from './evm.js'
import type { Journal } from './journal.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, StatelessVerkleStateManager } from '@ethereumjs/statemanager'
import type { AccessWitnessInterface, Common, EVMStateManagerInterface } from '@ethereumjs/common'
import type { Address, PrefixedHexString } from '@ethereumjs/util'
const { debug: createDebugLogger } = debugDefault

Expand Down Expand Up @@ -68,7 +67,7 @@ export interface Env {
containerCode?: Uint8Array /** Full container code for EOF1 contracts */
blobVersionedHashes: Uint8Array[] /** Versioned hashes for blob transactions */
createdAddresses?: Set<string>
accessWitness?: AccessWitness
accessWitness?: AccessWitnessInterface
chargeCodeAccesses?: boolean
}

Expand Down Expand Up @@ -272,9 +271,7 @@ export class Interpreter {
const contract = this._runState.interpreter.getAddress()

if (
!(await (
this._runState.stateManager as StatelessVerkleStateManager
).checkChunkWitnessPresent(contract, programCounter))
!(await this._runState.stateManager.checkChunkWitnessPresent!(contract, programCounter))
) {
throw Error(`Invalid witness with missing codeChunk for pc=${programCounter}`)
}
Expand Down
6 changes: 3 additions & 3 deletions packages/evm/src/message.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Address, BIGINT_0 } from '@ethereumjs/util'

import type { PrecompileFunc } from './precompiles/index.js'
import type { AccessWitness } from '@ethereumjs/statemanager'
import type { AccessWitnessInterface } from '@ethereumjs/common'
import type { PrefixedHexString } from '@ethereumjs/util'

const defaults = {
Expand Down Expand Up @@ -39,7 +39,7 @@ interface MessageOpts {
authcallOrigin?: Address
gasRefund?: bigint
blobVersionedHashes?: Uint8Array[]
accessWitness?: AccessWitness
accessWitness?: AccessWitnessInterface
}

export class Message {
Expand Down Expand Up @@ -75,7 +75,7 @@ export class Message {
* List of versioned hashes if message is a blob transaction in the outer VM
*/
blobVersionedHashes?: Uint8Array[]
accessWitness?: AccessWitness
accessWitness?: AccessWitnessInterface

constructor(opts: MessageOpts) {
this.to = opts.to
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/src/opcodes/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ import {
bytesToHex,
concatBytes,
ecrecover,
getTreeIndexesForStorageSlot,
hexToBytes,
publicToAddress,
setLengthLeft,
setLengthRight,
} from '@ethereumjs/util'
import { getTreeIndexesForStorageSlot } from '@ethereumjs/verkle'
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { ERROR } from '../exceptions.js'
Expand Down
10 changes: 4 additions & 6 deletions packages/evm/src/opcodes/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@ import { Hardfork } from '@ethereumjs/common'
import {
Account,
Address,
BALANCE_LEAF_KEY,
BIGINT_0,
BIGINT_1,
BIGINT_3,
BIGINT_31,
BIGINT_32,
bigIntToBytes,
setLengthLeft,
} from '@ethereumjs/util'
import {
BALANCE_LEAF_KEY,
CODE_HASH_LEAF_KEY,
CODE_SIZE_LEAF_KEY,
VERSION_LEAF_KEY,
bigIntToBytes,
getTreeIndexesForStorageSlot,
} from '@ethereumjs/verkle'
setLengthLeft,
} from '@ethereumjs/util'

import { ERROR } from '../exceptions.js'

Expand Down
5 changes: 2 additions & 3 deletions packages/evm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import type { AsyncDynamicGasHandler, SyncDynamicGasHandler } from './opcodes/ga
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 { AccessWitnessInterface, Common, EVMStateManagerInterface } from '@ethereumjs/common'
import type { Account, Address, AsyncEventEmitter, PrefixedHexString } from '@ethereumjs/util'

export type DeleteOpcode = {
Expand Down Expand Up @@ -124,7 +123,7 @@ export interface EVMRunCallOpts extends EVMRunOpts {
*/
message?: Message

accessWitness?: AccessWitness
accessWitness?: AccessWitnessInterface
}

interface NewContractEvent {
Expand Down
7 changes: 3 additions & 4 deletions packages/statemanager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,16 @@
"@ethereumjs/rlp": "^5.0.2",
"@ethereumjs/trie": "^6.2.0",
"@ethereumjs/util": "^9.0.3",
"@ethereumjs/verkle": "^0.0.2",
"debug": "^4.3.3",
"ethereum-cryptography": "^2.1.3",
"js-sdsl": "^4.1.4",
"lru-cache": "10.1.0",
"verkle-cryptography-wasm": "^0.4.2"
"lru-cache": "10.1.0"
},
"devDependencies": {
"@ethereumjs/block": "^5.2.0",
"@ethereumjs/genesis": "^0.2.2",
"@types/debug": "^4.1.9",
"rustbn-wasm": "^0.4.0"
"rustbn-wasm": "^0.4.0",
"verkle-cryptography-wasm": "^0.4.2"
}
}
Loading

0 comments on commit 1acacb8

Please sign in to comment.