Skip to content

Commit

Permalink
common: refactor verkleCrypto into customCrypto from common (#3790)
Browse files Browse the repository at this point in the history
* common: refactor verkleCrypto into customCrypto from common

* vm: type issue

* remove obsolete `await loadVerkleCrypto` references

* fix code stem and code chunk suffix generation

* fix suffix counts

* fix tests

* Update packages/statemanager/src/statelessVerkleStateManager.ts

Co-authored-by: Jochem Brouwer <[email protected]>

---------

Co-authored-by: acolytec3 <[email protected]>
Co-authored-by: Jochem Brouwer <[email protected]>
  • Loading branch information
3 people authored Nov 8, 2024
1 parent 253e271 commit 287f960
Show file tree
Hide file tree
Showing 22 changed files with 174 additions and 198 deletions.
5 changes: 1 addition & 4 deletions packages/client/src/execution/vmexecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
import { createVM, runBlock, runTx } from '@ethereumjs/vm'
import { writeFileSync } from 'fs'
import * as mcl from 'mcl-wasm'
import * as verkle from 'micro-eth-signer/verkle'
import { initRustBN } from 'rustbn-wasm'

import { Event } from '../types.js'
Expand All @@ -42,7 +41,6 @@ import type { ExecutionOptions } from './execution.js'
import type { Block } from '@ethereumjs/block'
import type { PrefixedHexString } from '@ethereumjs/util'
import type { RunBlockOpts, TxReceipt, VM } from '@ethereumjs/vm'
const loadVerkleCrypto = () => Promise.resolve(verkle)

export enum ExecStatus {
VALID = 'VALID',
Expand Down Expand Up @@ -202,9 +200,8 @@ export class VMExecution extends Execution {
return
}
this.config.logger.info(`Setting up verkleVM`)
const verkleCrypto = await loadVerkleCrypto()
const stateManager = new StatelessVerkleStateManager({
verkleCrypto,
common: this.config.execCommon,
})
await mcl.init(mcl.BLS12_381)
const rustBN = await initRustBN()
Expand Down
2 changes: 2 additions & 0 deletions packages/client/test/rpc/engine/kaustinen6.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '@ethereumjs/block'
import { hexToBytes } from '@ethereumjs/util'
import { readFileSync } from 'fs'
import * as verkle from 'micro-eth-signer'
import * as td from 'testdouble'
import { assert, describe, it } from 'vitest'

Expand Down Expand Up @@ -80,6 +81,7 @@ describe(`valid verkle network setup`, async () => {
const { server, chain, common } = await setupChain(kaustinen6Data, 'post-merge', {
engine: true,
genesisStateRoot: genesisVerkleStateRoot,
customCrypto: { verkleCrypto: verkle },
})
const rpc = getRPCClient(server)
it('genesis should be correctly setup', async () => {
Expand Down
9 changes: 8 additions & 1 deletion packages/common/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { ConsensusAlgorithm, ConsensusType, Hardfork } from './enums.js'
import type { BigIntLike, ECDSASignature, KZG, PrefixedHexString } from '@ethereumjs/util'
import type {
BigIntLike,
ECDSASignature,
KZG,
PrefixedHexString,
VerkleCrypto,
} from '@ethereumjs/util'

export interface ChainName {
[chainId: string]: string
Expand Down Expand Up @@ -89,6 +95,7 @@ export interface CustomCrypto {
ecdsaSign?: (msg: Uint8Array, pk: Uint8Array) => { signature: Uint8Array; recid: number }
ecdsaRecover?: (sig: Uint8Array, recId: number, hash: Uint8Array) => Uint8Array
kzg?: KZG
verkleCrypto?: VerkleCrypto
}

export interface BaseOpts {
Expand Down
22 changes: 11 additions & 11 deletions packages/evm/test/verkle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@ import {
} from '@ethereumjs/util'
import { createVerkleTree } from '@ethereumjs/verkle'
import * as verkle from 'micro-eth-signer/verkle'
import { assert, beforeAll, describe, it } from 'vitest'
import { assert, describe, it } from 'vitest'

import { VerkleAccessWitness, createEVM } from '../src/index.js'

import type { VerkleCrypto } from '@ethereumjs/util'
const loadVerkleCrypto = () => Promise.resolve(verkle)

describe('verkle tests', () => {
let verkleCrypto: VerkleCrypto
beforeAll(async () => {
verkleCrypto = await loadVerkleCrypto()
})
it('should execute bytecode and update the state', async () => {
// This tests executes some very simple bytecode that stores the value 1 in slot 2
const common = new Common({ chain: Mainnet, eips: [6800], hardfork: Hardfork.Cancun })
const common = new Common({
chain: Mainnet,
customCrypto: { verkleCrypto: verkle },
eips: [6800],
hardfork: Hardfork.Cancun,
})
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto })
const sm = new StatefulVerkleStateManager({ common, trie })
const address = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
const account = createAccount({ nonce: 3n, balance: 0xffffffffn })
await sm.putAccount(address, account)
const evm = await createEVM({ common, stateManager: sm })
// Initialize verkleAccess Witness manually (in real context, it is done by the VM, but we are bypassing that here)
evm.verkleAccessWitness = new VerkleAccessWitness({ verkleCrypto })
evm.verkleAccessWitness = new VerkleAccessWitness({
verkleCrypto: verkle,
})
const code = hexToBytes('0x6001600255') // PUSH1 01 PUSH1 02 SSTORE
const res = await evm.runCall({
code,
Expand Down
19 changes: 12 additions & 7 deletions packages/statemanager/src/statefulVerkleStateManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Common, Mainnet, VerkleAccessedStateType } from '@ethereumjs/common'
import { VerkleAccessedStateType } from '@ethereumjs/common'
import { RLP } from '@ethereumjs/rlp'
import {
Account,
Expand Down Expand Up @@ -41,6 +41,7 @@ import type { Caches } from './cache/caches.js'
import type { StatefulVerkleStateManagerOpts, VerkleState } from './types.js'
import type {
AccountFields,
Common,
StateManagerInterface,
StorageDump,
StorageRange,
Expand Down Expand Up @@ -80,7 +81,6 @@ export class StatefulVerkleStateManager implements StateManagerInterface {
protected readonly DEBUG: boolean = false

private keccakFunction: Function

constructor(opts: StatefulVerkleStateManagerOpts) {
// Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables
// Additional window check is to prevent vite browser bundling (and potentially other) to break
Expand All @@ -89,23 +89,28 @@ export class StatefulVerkleStateManager implements StateManagerInterface {

this._checkpointCount = 0

if (opts.common?.isActivatedEIP(6800) === false)
if (opts.common.isActivatedEIP(6800) === false) {
throw new Error('EIP-6800 required for verkle state management')
}

if (opts.common.customCrypto.verkleCrypto === undefined) {
throw new Error('verkle crypto required')
}

this.common = opts.common ?? new Common({ chain: Mainnet, eips: [6800] })
this.common = opts.common
this._trie =
opts.trie ??
new VerkleTree({
verkleCrypto: opts.verkleCrypto,
verkleCrypto: opts.common.customCrypto.verkleCrypto,
db: new MapDB<Uint8Array, Uint8Array>(),
useRootPersistence: false,
cacheSize: 0,
})
this._debug = debugDefault('statemanager:verkle:stateful')
this.originalStorageCache = new OriginalStorageCache(this.getStorage.bind(this))
this._caches = opts.caches
this.keccakFunction = opts.common?.customCrypto.keccak256 ?? keccak256
this.verkleCrypto = opts.verkleCrypto
this.keccakFunction = opts.common.customCrypto.keccak256 ?? keccak256
this.verkleCrypto = opts.common.customCrypto.verkleCrypto
}

/**
Expand Down
20 changes: 14 additions & 6 deletions packages/statemanager/src/statelessVerkleStateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type { StatelessVerkleStateManagerOpts, VerkleState } from './index.js'
import type { MerkleStateManager } from './merkleStateManager.js'
import type {
AccountFields,
Common,
StateManagerInterface,
VerkleAccessWitnessInterface,
VerkleAccessedStateWithAddress,
Expand Down Expand Up @@ -76,6 +77,8 @@ export class StatelessVerkleStateManager implements StateManagerInterface {

protected _debug: Debugger

public readonly common: Common

/**
* StateManager is run in DEBUG mode (default: false)
* Taken from DEBUG environment variable
Expand Down Expand Up @@ -112,14 +115,19 @@ export class StatelessVerkleStateManager implements StateManagerInterface {

this._caches = opts.caches

this.keccakFunction = opts.common?.customCrypto.keccak256 ?? keccak256

this._debug = debugDefault('statemanager:verkle:stateless')
if (opts.common.isActivatedEIP(6800) === false) {
throw new Error('EIP-6800 required for stateless verkle state management')
}

if (opts.verkleCrypto === undefined) {
if (opts.common.customCrypto.verkleCrypto === undefined) {
throw new Error('verkle crypto required')
}
this.verkleCrypto = opts.verkleCrypto

this.common = opts.common
this.keccakFunction = opts.common.customCrypto.keccak256 ?? keccak256
this.verkleCrypto = opts.common.customCrypto.verkleCrypto

this._debug = debugDefault('statemanager:verkle:stateless')

// Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables
// Additional window check is to prevent vite browser bundling (and potentially other) to break
Expand Down Expand Up @@ -211,7 +219,7 @@ export class StatelessVerkleStateManager implements StateManagerInterface {
shallowCopy(downlevelCaches = true): StatelessVerkleStateManager {
const stateManager = new StatelessVerkleStateManager({
caches: this._caches?.shallowCopy(downlevelCaches),
verkleCrypto: this.verkleCrypto,
common: this.common,
})
return stateManager
}
Expand Down
5 changes: 2 additions & 3 deletions packages/statemanager/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { type PrefixedHexString } from '@ethereumjs/util'
import type { Caches } from './index.js'
import type { Common } from '@ethereumjs/common'
import type { MerklePatriciaTrie } from '@ethereumjs/mpt'
import type { VerkleCrypto } from '@ethereumjs/util'
import type { VerkleTree } from '@ethereumjs/verkle'
/**
* Basic state manager options (not to be used directly)
Expand Down Expand Up @@ -69,12 +68,12 @@ export interface MerkleStateManagerOpts extends BaseStateManagerOpts {
* Options dictionary.
*/
export interface StatelessVerkleStateManagerOpts extends BaseStateManagerOpts {
verkleCrypto: VerkleCrypto
common: Common // Common required since it provides verkleCrypto through customCrypto
caches?: Caches
}

export interface StatefulVerkleStateManagerOpts extends BaseStateManagerOpts {
verkleCrypto: VerkleCrypto
common: Common // Common required since it provides verkleCrypto through customCrypto
trie?: VerkleTree
caches?: Caches
}
Expand Down
51 changes: 34 additions & 17 deletions packages/statemanager/test/statefulVerkleStateManager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Common, Mainnet } from '@ethereumjs/common'
import {
Account,
VerkleLeafType,
Expand All @@ -11,22 +12,22 @@ import {
} from '@ethereumjs/util'
import { createVerkleTree } from '@ethereumjs/verkle'
import * as verkle from 'micro-eth-signer/verkle'
import { assert, beforeAll, describe, it } from 'vitest'
import { assert, describe, it } from 'vitest'

import { Caches } from '../src/index.js'
import { StatefulVerkleStateManager } from '../src/statefulVerkleStateManager.js'

import type { PrefixedHexString, VerkleCrypto } from '@ethereumjs/util'
const loadVerkleCrypto = () => Promise.resolve(verkle)
import type { PrefixedHexString } from '@ethereumjs/util'

describe('Verkle Tree API tests', () => {
let verkleCrypto: VerkleCrypto
beforeAll(async () => {
verkleCrypto = await loadVerkleCrypto()
})
it('should put/get/delete an account (with no storage/code from the trie)', async () => {
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto })
const common = new Common({
chain: Mainnet,
eips: [6800],
customCrypto: { verkleCrypto: verkle },
})
const sm = new StatefulVerkleStateManager({ common, trie })
const address = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
const account = createAccount({ nonce: 3n, balance: 0xfffn })
await sm.putAccount(address, account)
Expand All @@ -40,7 +41,12 @@ describe('Verkle Tree API tests', () => {

it('should return same stateRoot when putting and then deleting account', async () => {
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto })
const common = new Common({
chain: Mainnet,
eips: [6800],
customCrypto: { verkleCrypto: verkle },
})
const sm = new StatefulVerkleStateManager({ common, trie })

const address1 = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
const account1 = createAccount({ nonce: 3n, balance: 0xfffn })
Expand All @@ -61,7 +67,12 @@ describe('Verkle Tree API tests', () => {

it('should put and get code', async () => {
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto })
const common = new Common({
chain: Mainnet,
eips: [6800],
customCrypto: { verkleCrypto: verkle },
})
const sm = new StatefulVerkleStateManager({ common, trie })
const address = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
const code = hexToBytes('0x6001') // PUSH 01
await sm.putCode(address, code)
Expand Down Expand Up @@ -90,7 +101,12 @@ describe('Verkle Tree API tests', () => {
const zeroSlot = setLengthLeft(bigIntToBytes(0n), 32)
const zeroSlotValue = hexToBytes('0x1')
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto })
const common = new Common({
chain: Mainnet,
eips: [6800],
customCrypto: { verkleCrypto: verkle },
})
const sm = new StatefulVerkleStateManager({ common, trie })
const address = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
await sm.putAccount(address, new Account(0n, 1n))
await sm.putStorage(address, zeroSlot, zeroSlotValue)
Expand All @@ -100,19 +116,20 @@ describe('Verkle Tree API tests', () => {
})

describe('caching functionality works', () => {
let verkleCrypto: VerkleCrypto
beforeAll(async () => {
verkleCrypto = await loadVerkleCrypto()
})
it('should cache accounts and then write to trie', async () => {
const trie = await createVerkleTree()
const sm = new StatefulVerkleStateManager({ trie, verkleCrypto, caches: new Caches() })
const common = new Common({
chain: Mainnet,
eips: [6800],
customCrypto: { verkleCrypto: verkle },
})
const sm = new StatefulVerkleStateManager({ common, trie, caches: new Caches() })
const address = createAddressFromString('0x9e5ef720fa2cdfa5291eb7e711cfd2e62196f4b3')
const account = createAccount({ nonce: 3n, balance: 0xfffn })
await sm.putAccount(address, account)

// Confirm account doesn't exist in trie
const stem = getVerkleStem(verkleCrypto, address, 0)
const stem = getVerkleStem(verkle, address, 0)
const accountData = await sm['_trie'].get(stem, [
VerkleLeafType.BasicData,
VerkleLeafType.CodeHash,
Expand Down
Loading

0 comments on commit 287f960

Please sign in to comment.