Skip to content

Commit

Permalink
Run client with stateful verkle (#3800)
Browse files Browse the repository at this point in the history
* add stateful verkle flags

* Add vkt state root generator

* lint

* Add full support for running in stateful verkle mode

* disable stateless verkle by default

* fix params

* fix typing bug

* fix tests and skip kaust6 tests

* Update packages/client/bin/cli.ts

* client: move over kaustinen7 genesis date to separate folder

* statemanager: add hasStateRoot method to verkle stateful state manager

* common: add 4762 for verkle

* address feedback

* Add cli test for verkle execution

* spell check

---------

Co-authored-by: Gabriel Rocheleau <[email protected]>
  • Loading branch information
acolytec3 and gabrocheleau authored Nov 20, 2024
1 parent 90fbe6f commit 723005a
Show file tree
Hide file tree
Showing 17 changed files with 1,212 additions and 62 deletions.
15 changes: 13 additions & 2 deletions packages/blockchain/src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ import type {
} from './types.js'
import type { HeaderData } from '@ethereumjs/block'
import type { CliqueConfig } from '@ethereumjs/common'
import type { BigIntLike, DB, DBObject, GenesisState } from '@ethereumjs/util'
import type {
BigIntLike,
DB,
DBObject,
GenesisState,
VerkleExecutionWitness,
} from '@ethereumjs/util'
import type { Debugger } from 'debug'

/**
Expand Down Expand Up @@ -1325,8 +1331,13 @@ export class Blockchain implements BlockchainInterface {
header.extraData = concatBytes(new Uint8Array(32), new Uint8Array(65))
}
}

return createBlock(
{ header, withdrawals: common.isActivatedEIP(4895) ? [] : undefined },
{
header,
withdrawals: common.isActivatedEIP(4895) ? [] : undefined,
executionWitness: common.isActivatedEIP(6800) ? ({} as VerkleExecutionWitness) : undefined,
},
{ common },
)
}
Expand Down
67 changes: 47 additions & 20 deletions packages/client/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'
import * as http from 'http'
import { Level } from 'level'
import { KZG as microEthKZG } from 'micro-eth-signer/kzg'
import * as verkle from 'micro-eth-signer/verkle'
import { homedir } from 'os'
import * as path from 'path'
import * as promClient from 'prom-client'
Expand All @@ -59,6 +60,7 @@ import { getLogger } from '../src/logging.js'
import { Event } from '../src/types.js'
import { parseMultiaddrs } from '../src/util/index.js'
import { setupMetrics } from '../src/util/metrics.js'
import { generateVKTStateRoot } from '../src/util/vkt.js'

import { helpRPC, startRPCServers } from './startRPC.js'

Expand Down Expand Up @@ -452,7 +454,12 @@ const args: ClientOpts = yargs
.option('statelessVerkle', {
describe: 'Run verkle+ hardforks using stateless verkle stateManager (experimental)',
boolean: true,
default: true,
default: false,
})
.option('statefulVerkle', {
describe: 'Run verkle+ hardforks using stateful verkle stateManager (experimental)',
boolean: true,
default: false,
})
.option('engineNewpayloadMaxExecute', {
describe:
Expand Down Expand Up @@ -599,26 +606,36 @@ async function startExecutionFrom(client: EthereumClient) {
timestamp: startExecutionBlock.header.timestamp,
})

if (
client.config.execCommon.hardforkGteHardfork(startExecutionHardfork, Hardfork.Osaka) &&
client.config.statelessVerkle
) {
// for stateless verkle sync execution witnesses are available and hence we can blindly set the vmHead
// to startExecutionParent's hash
try {
await client.chain.blockchain.setIteratorHead('vm', startExecutionParent.hash())
await client.chain.update(false)
logger.info(
`vmHead set to ${client.chain.headers.height} for starting stateless execution at hardfork=${startExecutionHardfork}`,
)
} catch (err: any) {
logger.error(`Error setting vmHead for starting stateless execution: ${err}`)
if (client.config.execCommon.hardforkGteHardfork(startExecutionHardfork, Hardfork.Verkle)) {
if (client.config.statelessVerkle) {
// for stateless verkle sync execution witnesses are available and hence we can blindly set the vmHead
// to startExecutionParent's hash
try {
await client.chain.blockchain.setIteratorHead('vm', startExecutionParent.hash())
await client.chain.update(false)
logger.info(
`vmHead set to ${client.chain.headers.height} for starting stateless execution at hardfork=${startExecutionHardfork}`,
)
} catch (err: any) {
logger.error(`Error setting vmHead for starting stateless execution: ${err}`)
process.exit()
}
} else if (client.config.statefulVerkle) {
try {
await client.chain.blockchain.setIteratorHead('vm', startExecutionParent.hash())
await client.chain.update(false)
logger.info(
`vmHead set to ${client.chain.headers.height} for starting stateful execution at hardfork=${startExecutionHardfork}`,
)
} catch (err: any) {
logger.error(`Error setting vmHead for starting stateful execution: ${err}`)
process.exit()
}
} else {
// we need parent state availability to set the vmHead to the parent
logger.error(`Stateful execution reset not implemented at hardfork=${startExecutionHardfork}`)
process.exit()
}
} else {
// we need parent state availability to set the vmHead to the parent
logger.error(`Stateful execution reset not implemented at hardfork=${startExecutionHardfork}`)
process.exit()
}
}

Expand All @@ -642,6 +659,14 @@ async function startClient(
validateConsensus = true
}

let stateRoot
if (config.statefulVerkle) {
if (genesisMeta.genesisState === undefined) {
throw new Error('genesisState is required to compute stateRoot')
}
stateRoot = await generateVKTStateRoot(genesisMeta.genesisState, config.chainCommon)
}

blockchain = await createBlockchain({
db: new LevelDB(dbs.chainDB),
...genesisMeta,
Expand All @@ -651,7 +676,7 @@ async function startClient(
validateConsensus,
consensusDict,
genesisState: genesisMeta.genesisState,
genesisStateRoot: genesisMeta.genesisStateRoot,
genesisStateRoot: stateRoot,
})
config.chainCommon.setForkHashes(blockchain.genesisBlock.hash())
}
Expand Down Expand Up @@ -981,6 +1006,7 @@ async function run() {
cryptoFunctions.ecdsaRecover = ecdsaRecover
}
cryptoFunctions.kzg = kzg
cryptoFunctions.verkle = verkle
// Configure accounts for mining and prefunding in a local devnet
const accounts: Account[] = []
if (typeof args.unlock === 'string') {
Expand Down Expand Up @@ -1164,6 +1190,7 @@ async function run() {
txLookupLimit: args.txLookupLimit,
pruneEngineCache: args.pruneEngineCache,
statelessVerkle: args.ignoreStatelessInvalidExecs === true ? true : args.statelessVerkle,
statefulVerkle: args.statefulVerkle,
startExecution: args.startExecutionFrom !== undefined ? true : args.startExecution,
engineNewpayloadMaxExecute:
args.ignoreStatelessInvalidExecs === true || args.skipEngineExec === true
Expand Down
Loading

0 comments on commit 723005a

Please sign in to comment.