Skip to content

Commit 9856f66

Browse files
holgerd77jochem-brouwergabrocheleau
authored
VM/SM: Bundle Optimizations (Default wo Caches+EVMMockBlockchain, SM Code put() Fix, VerkleSM out, runTx()+Code Opts) (#3601)
* Use shallowCopy() Caches copy() optimization also for VerkleSM to avoid Caches bundling on non-Caches default * Fix default state manager missing direct code write when used without caches * Do not initialize caches for default VM state manager * Remove copy test not making sense any more under generalized cache/no-cache conditions * Some more solid/qualified EVM dummy blockchain + interface naming to allow for exporting * Use EVMMockBlockchain(Interface) as default for the VM, adjust some tests * Move @ethereumjs/blockchain to dev dependencies in VM * Rebuild package-lock.json * Adjust/fix some client tests * Lint fix * Add Verkle SM methods as optional methods to interface, replace VerkleSM imports and castings in VM * Also align client (no real effect yet, but generally try to work more on the interfaces and not the classes directly) * Initialize runTx() default block with simpler constructor to avoid drawing all txs in * Fully switch to DEFAULT_HEADER in VM.runTx() to avoid drawing in block code * Opcode list size optimization * More optimizations * Precompile code optimizations * More optimizations (precompile index.ts file) * Some more * Some doc compatification * Add CSpell checker to CI and fix typos (#3590) * monorepo: add cspell, add ALL unknown words to valid words * cspell: split unknown words in ts/md * filter out wrong words in cspell-ts.json * cspell ignore hex values * fix typos in all packages * cspell: use cache * cspell: update commands * cspell: update md/ts words * Typo fixes for README/CHANGELOG files * cspell: ensure all relevant monorepo md files are checked * ci: add cspell job * cspell: update command * temp add bogus to markdown * remove bogus spell * update ci name * fix remaining typos + add words to cspell dict * Update packages/client/CHANGELOG.md * Update packages/util/CHANGELOG.md * address review * Remove almost all `cspell:ignore` (#3599) * remove almost all cspell:ignore * more spell changes * cspell: fix problems * evm: fix quadCoefficient * cspell: fixes * remove disable line --------- Co-authored-by: Gabriel Rocheleau <contact@rockwaterweb.com> * Fix spell check * Remove accidentally committed examples/test.ts file --------- Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com> Co-authored-by: Gabriel Rocheleau <contact@rockwaterweb.com>
1 parent 4a8761a commit 9856f66

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+726
-800
lines changed

Diff for: package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: packages/block/src/block/constructors.ts

+12
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ export function createBlock(blockData: BlockData = {}, opts?: BlockOptions) {
119119
)
120120
}
121121

122+
/**
123+
* Simple static constructor if only an empty block is needed
124+
* (tree shaking advantages since it does not draw all the tx constructors in)
125+
*
126+
* @param headerData
127+
* @param opts
128+
*/
129+
export function createEmptyBlock(headerData: HeaderData, opts?: BlockOptions) {
130+
const header = createBlockHeader(headerData, opts)
131+
return new Block(header)
132+
}
133+
122134
/**
123135
* Static constructor to create a block from an array of Bytes values
124136
*

Diff for: packages/block/test/block.spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
createBlockFromBytesArray,
2121
createBlockFromRLPSerializedBlock,
2222
createBlockFromRPC,
23+
createEmptyBlock,
2324
paramsBlock,
2425
} from '../src/index.js'
2526

@@ -46,6 +47,9 @@ describe('[Block]: block functions', () => {
4647
'should use custom parameters provided',
4748
)
4849

50+
const emptyBlock = createEmptyBlock({}, { common })
51+
assert.ok(bytesToHex(emptyBlock.hash()), 'block should initialize')
52+
4953
// test default freeze values
5054
// also test if the options are carried over to the constructor
5155
block = createBlock({})

Diff for: packages/client/src/execution/vmexecution.ts

+24-56
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export class VMExecution extends Execution {
221221
}
222222

223223
async transitionToVerkle(merkleStateRoot: Uint8Array, assignToVM: boolean = true): Promise<void> {
224-
if (this.vm.stateManager instanceof StatelessVerkleStateManager) {
224+
if (typeof this.vm.stateManager.initVerkleExecutionWitness === 'function') {
225225
return
226226
}
227227

@@ -230,15 +230,19 @@ export class VMExecution extends Execution {
230230
await this.setupMerkleVM()
231231
}
232232
const merkleVM = this.merkleVM!
233-
const merkleStateManager = merkleVM.stateManager as DefaultStateManager
233+
const merkleStateManager = merkleVM.stateManager
234234

235235
if (this.verkleVM === undefined) {
236236
await this.setupVerkleVM()
237237
}
238238
const verkleVM = this.verkleVM!
239-
const verkleStateManager = verkleVM.stateManager as StatelessVerkleStateManager
239+
const verkleStateManager = verkleVM.stateManager
240240

241-
const verkleStateRoot = await verkleStateManager.getTransitionStateRoot(
241+
// TODO: can we please implement this in a different way and not introduce a method
242+
// *inside* one state manager which takes another state manager?
243+
// That bloats the interface too much, this should be minimally a separate util method
244+
// or fully move to client
245+
const verkleStateRoot = await (verkleStateManager as any).getTransitionStateRoot(
242246
merkleStateManager,
243247
merkleStateRoot,
244248
)
@@ -416,7 +420,8 @@ export class VMExecution extends Execution {
416420
vm = this.verkleVM
417421
}
418422

419-
const needsStatelessExecution = vm.stateManager instanceof StatelessVerkleStateManager
423+
const needsStatelessExecution =
424+
typeof this.vm.stateManager.initVerkleExecutionWitness === 'function'
420425
if (needsStatelessExecution && block.executionWitness === undefined) {
421426
throw Error(`Verkle blocks need executionWitness for stateless execution`)
422427
} else {
@@ -576,7 +581,7 @@ export class VMExecution extends Execution {
576581
this.config.logger.warn(
577582
`Setting execution head to hash=${short(jumpToHash)} number=${jumpToNumber}`,
578583
)
579-
await this.vm.blockchain.setIteratorHead('vm', jumpToHash)
584+
await this.chain.blockchain.setIteratorHead('vm', jumpToHash)
580585
})
581586
}
582587

@@ -595,19 +600,9 @@ export class VMExecution extends Execution {
595600
this.running = true
596601
let numExecuted: number | null | undefined = undefined
597602

598-
const { blockchain } = this.vm
599-
if (typeof blockchain.getIteratorHead !== 'function') {
600-
throw new Error('cannot get iterator head: blockchain has no getIteratorHead function')
601-
}
602-
let startHeadBlock = await blockchain.getIteratorHead()
603+
let startHeadBlock = await this.chain.blockchain.getIteratorHead()
603604
await this.checkAndReset(startHeadBlock)
604-
605-
if (typeof blockchain.getCanonicalHeadBlock !== 'function') {
606-
throw new Error(
607-
'cannot get iterator head: blockchain has no getCanonicalHeadBlock function',
608-
)
609-
}
610-
let canonicalHead = await blockchain.getCanonicalHeadBlock()
605+
let canonicalHead = await this.chain.blockchain.getCanonicalHeadBlock()
611606

612607
this.config.logger.debug(
613608
`Running execution startHeadBlock=${startHeadBlock?.header.number} canonicalHead=${canonicalHead?.header.number} loop=${loop}`,
@@ -637,14 +632,14 @@ export class VMExecution extends Execution {
637632
headBlock = undefined
638633
parentState = undefined
639634
errorBlock = undefined
640-
this.vmPromise = blockchain
635+
this.vmPromise = this.chain.blockchain
641636
.iterator(
642637
'vm',
643638
async (block: Block, reorg: boolean) => {
644639
// determine starting state for block run
645640
// if we are just starting or if a chain reorg has happened
646641
if (headBlock === undefined || reorg) {
647-
headBlock = await blockchain.getBlock(block.header.parentHash)
642+
headBlock = await this.chain.blockchain.getBlock(block.header.parentHash)
648643
parentState = headBlock.header.stateRoot
649644

650645
if (reorg) {
@@ -664,11 +659,6 @@ export class VMExecution extends Execution {
664659
// run block, update head if valid
665660
try {
666661
const { number, timestamp } = block.header
667-
if (typeof blockchain.getTotalDifficulty !== 'function') {
668-
throw new Error(
669-
'cannot get iterator head: blockchain has no getTotalDifficulty function',
670-
)
671-
}
672662

673663
const hardfork = this.config.execCommon.getHardforkBy({
674664
blockNumber: number,
@@ -692,7 +682,7 @@ export class VMExecution extends Execution {
692682
}
693683
if (
694684
(!this.config.execCommon.gteHardfork(Hardfork.Osaka) &&
695-
this.vm.stateManager instanceof StatelessVerkleStateManager) ||
685+
typeof this.vm.stateManager.initVerkleExecutionWitness === 'function') ||
696686
(this.config.execCommon.gteHardfork(Hardfork.Osaka) &&
697687
this.vm.stateManager instanceof DefaultStateManager)
698688
) {
@@ -800,7 +790,7 @@ export class VMExecution extends Execution {
800790
backStepToHash ?? 'na',
801791
)} hasParentStateRoot=${short(backStepToRoot ?? 'na')}:\n${error}`,
802792
)
803-
await this.vm.blockchain.setIteratorHead('vm', backStepToHash)
793+
await this.chain.blockchain.setIteratorHead('vm', backStepToHash)
804794
} else {
805795
this.config.logger.error(
806796
`${errorMsg}, couldn't back step to vmHead number=${backStepTo} hash=${short(
@@ -855,14 +845,7 @@ export class VMExecution extends Execution {
855845

856846
numExecuted = await this.vmPromise
857847
if (numExecuted !== null) {
858-
let endHeadBlock
859-
if (typeof this.vm.blockchain.getIteratorHead === 'function') {
860-
endHeadBlock = await this.vm.blockchain.getIteratorHead('vm')
861-
} else {
862-
throw new Error(
863-
'cannot get iterator head: blockchain has no getIteratorHead function',
864-
)
865-
}
848+
const endHeadBlock = await this.chain.blockchain.getIteratorHead('vm')
866849

867850
if (typeof numExecuted === 'number' && numExecuted > 0) {
868851
const firstNumber = startHeadBlock.header.number
@@ -891,12 +874,7 @@ export class VMExecution extends Execution {
891874
)
892875
}
893876
startHeadBlock = endHeadBlock
894-
if (typeof this.vm.blockchain.getCanonicalHeadBlock !== 'function') {
895-
throw new Error(
896-
'cannot get iterator head: blockchain has no getCanonicalHeadBlock function',
897-
)
898-
}
899-
canonicalHead = await this.vm.blockchain.getCanonicalHeadBlock()
877+
canonicalHead = await this.chain.blockchain.getCanonicalHeadBlock()
900878
}
901879
}
902880

@@ -917,19 +895,12 @@ export class VMExecution extends Execution {
917895
this.STATS_INTERVAL,
918896
)
919897

920-
const { blockchain } = this.vm
921898
if (this.running || !this.started) {
922899
return false
923900
}
924901

925-
if (typeof blockchain.getIteratorHead !== 'function') {
926-
throw new Error('cannot get iterator head: blockchain has no getIteratorHead function')
927-
}
928-
const vmHeadBlock = await blockchain.getIteratorHead()
929-
if (typeof blockchain.getCanonicalHeadBlock !== 'function') {
930-
throw new Error('cannot get iterator head: blockchain has no getCanonicalHeadBlock function')
931-
}
932-
const canonicalHead = await blockchain.getCanonicalHeadBlock()
902+
const vmHeadBlock = await this.chain.blockchain.getIteratorHead()
903+
const canonicalHead = await this.chain.blockchain.getCanonicalHeadBlock()
933904

934905
const infoStr = `vmHead=${vmHeadBlock.header.number} canonicalHead=${
935906
canonicalHead.header.number
@@ -984,7 +955,7 @@ export class VMExecution extends Execution {
984955
async executeBlocks(first: number, last: number, txHashes: string[]) {
985956
this.config.logger.info('Preparing for block execution (debug mode, no services started)...')
986957

987-
const block = await this.vm.blockchain.getBlock(first)
958+
const block = await this.chain.blockchain.getBlock(first)
988959
const startExecutionHardfork = this.config.execCommon.getHardforkBy({
989960
blockNumber: block.header.number,
990961
timestamp: block.header.timestamp,
@@ -1000,13 +971,10 @@ export class VMExecution extends Execution {
1000971
const vm = await this.vm.shallowCopy(false)
1001972

1002973
for (let blockNumber = first; blockNumber <= last; blockNumber++) {
1003-
const block = await vm.blockchain.getBlock(blockNumber)
1004-
const parentBlock = await vm.blockchain.getBlock(block.header.parentHash)
974+
const block = await this.chain.blockchain.getBlock(blockNumber)
975+
const parentBlock = await this.chain.blockchain.getBlock(block.header.parentHash)
1005976
// Set the correct state root
1006977
const root = parentBlock.header.stateRoot
1007-
if (typeof vm.blockchain.getTotalDifficulty !== 'function') {
1008-
throw new Error('cannot get iterator head: blockchain has no getTotalDifficulty function')
1009-
}
1010978
vm.common.setHardforkBy({
1011979
blockNumber,
1012980
timestamp: block.header.timestamp,

Diff for: packages/client/src/miner/miner.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { Config } from '../config.js'
1212
import type { VMExecution } from '../execution/index.js'
1313
import type { FullEthereumService } from '../service/index.js'
1414
import type { FullSynchronizer } from '../sync/index.js'
15-
import type { CliqueConsensus } from '@ethereumjs/blockchain'
15+
import type { Blockchain, CliqueConsensus } from '@ethereumjs/blockchain'
1616
import type { CliqueConfig } from '@ethereumjs/common'
1717
import type { Miner as EthashMiner, Solution } from '@ethereumjs/ethash'
1818

@@ -244,10 +244,9 @@ export class Miner {
244244
const [signerAddress, signerPrivKey] = this.config.accounts[0]
245245
cliqueSigner = signerPrivKey
246246
// Determine if signer is INTURN (2) or NOTURN (1)
247-
inTurn = await (vmCopy.blockchain.consensus as CliqueConsensus).cliqueSignerInTurn(
248-
signerAddress,
249-
number,
250-
)
247+
inTurn = await (
248+
(vmCopy.blockchain as Blockchain).consensus as CliqueConsensus
249+
).cliqueSignerInTurn(signerAddress, number)
251250
difficulty = inTurn ? 2 : 1
252251
}
253252

Diff for: packages/client/src/miner/pendingBlock.ts

-3
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ export class PendingBlock {
104104
const { timestamp, mixHash, parentBeaconBlockRoot, coinbase } = headerData
105105
let { gasLimit } = parentBlock.header
106106

107-
if (typeof vm.blockchain.getTotalDifficulty !== 'function') {
108-
throw new Error('cannot get iterator head: blockchain has no getTotalDifficulty function')
109-
}
110107
vm.common.setHardforkBy({
111108
blockNumber: number,
112109
timestamp,

Diff for: packages/client/test/miner/miner.spec.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { wait } from '../integration/util.js'
2222

2323
import type { FullSynchronizer } from '../../src/sync/index.js'
2424
import type { Block } from '@ethereumjs/block'
25-
import type { CliqueConsensus } from '@ethereumjs/blockchain'
25+
import type { Blockchain, CliqueConsensus } from '@ethereumjs/blockchain'
2626
import type { VM } from '@ethereumjs/vm'
2727

2828
const A = {
@@ -242,7 +242,9 @@ describe('assembleBlocks() -> with a single tx', async () => {
242242
await txPool.add(txA01)
243243

244244
// disable consensus to skip PoA block signer validation
245-
;(vm.blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [A.address] // stub
245+
;((vm.blockchain as Blockchain).consensus as CliqueConsensus).cliqueActiveSigners = () => [
246+
A.address,
247+
] // stub
246248

247249
chain.putBlocks = (blocks: Block[]) => {
248250
it('should include tx in new block', () => {
@@ -280,7 +282,9 @@ describe('assembleBlocks() -> with a hardfork mismatching tx', async () => {
280282
})
281283

282284
// disable consensus to skip PoA block signer validation
283-
;(vm.blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [A.address] // stub
285+
;((vm.blockchain as Blockchain).consensus as CliqueConsensus).cliqueActiveSigners = () => [
286+
A.address,
287+
] // stub
284288

285289
chain.putBlocks = (blocks: Block[]) => {
286290
it('should not include tx', () => {

0 commit comments

Comments
 (0)