Skip to content

Commit

Permalink
statemanager: cache and other refactors (#3569)
Browse files Browse the repository at this point in the history
* Revert "statemanager: refactor logic into capabilities (#3554)"

This reverts commit d7d1dab.

* statemanager: refactor modifyAccountFields

* statemanager: adjust return statements

* statemanager: refactor separate caches into caches class

* statemanager: fix shallow copy logic

* client: fix vmexecution statemanager cache opts

* statemanager: refactor some capabilities to caches methods

* statemanager: fix tests

* statemanager: refactor caches into optional opt passed in directly to the sm

* statemanager: adjust tests with refactored caches

* client: adjust vm execution with update cache

* vm: fix vm tests

* vm: adjust test runners with non-default caches

* statemanager: simplify handling of deactivate

* statemanager: remove redundant checks

* statemanager: remove non null asesertion

* statemanager: remove cache opt from key naming

* statemanager: refactor rpc state manager to use caches

* statemanager: fix rpc state manager tests

* client: vmexecution cache stats refactor

* statemanageR: updategetproof json-rpc call format

* statemanager: remove deactivate from caches

* client: remove deactivate from vm execution instantiation

---------

Co-authored-by: acolytec3 <17355484+acolytec3@users.noreply.github.com>
  • Loading branch information
gabrocheleau and acolytec3 authored Aug 12, 2024
1 parent 837a83f commit 45e0a6d
Show file tree
Hide file tree
Showing 30 changed files with 635 additions and 585 deletions.
54 changes: 27 additions & 27 deletions packages/client/src/execution/vmexecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import {
DBSetHashToNumber,
DBSetTD,
} from '@ethereumjs/blockchain'
import { CacheType, ConsensusType, Hardfork } from '@ethereumjs/common'
import { ConsensusType, Hardfork } from '@ethereumjs/common'
import { MCLBLS, RustBN254 } from '@ethereumjs/evm'
import { getGenesis } from '@ethereumjs/genesis'
import { DefaultStateManager, StatelessVerkleStateManager } from '@ethereumjs/statemanager'
import {
CacheType,
Caches,
DefaultStateManager,
StatelessVerkleStateManager,
} from '@ethereumjs/statemanager'
import { createTrie } from '@ethereumjs/trie'
import {
BIGINT_0,
Expand Down Expand Up @@ -35,7 +40,6 @@ import { ReceiptsManager } from './receipt.js'

import type { ExecutionOptions } from './execution.js'
import type { Block } from '@ethereumjs/block'
import type { Trie } from '@ethereumjs/trie'
import type { PrefixedHexString } from '@ethereumjs/util'
import type { RunBlockOpts, TxReceipt } from '@ethereumjs/vm'

Expand Down Expand Up @@ -160,21 +164,20 @@ export class VMExecution extends Execution {
const stateManager = new DefaultStateManager({
trie,
prefixStorageTrieKeys: this.config.prefixStorageTrieKeys,
accountCacheOpts: {
deactivate: false,
type: CacheType.LRU,
size: this.config.accountCache,
},
storageCacheOpts: {
deactivate: false,
type: CacheType.LRU,
size: this.config.storageCache,
},
codeCacheOpts: {
deactivate: false,
type: CacheType.LRU,
size: this.config.codeCache,
},
caches: new Caches({
account: {
type: CacheType.LRU,
size: this.config.accountCache,
},
storage: {
type: CacheType.LRU,
size: this.config.storageCache,
},
code: {
type: CacheType.LRU,
size: this.config.codeCache,
},
}),
common: this.config.chainCommon,
})

Expand Down Expand Up @@ -1059,25 +1062,22 @@ export class VMExecution extends Execution {

stats() {
if (this._statsVM instanceof DefaultStateManager) {
const sm = this._statsVM.stateManager as any
const disactivatedStats = { size: 0, reads: 0, hits: 0, writes: 0 }
const sm = this._statsVM.stateManager as DefaultStateManager
const deactivatedStats = { size: 0, reads: 0, hits: 0, writes: 0 }
let stats
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
stats = !sm._accountCacheSettings.deactivate ? sm._accountCache.stats() : disactivatedStats
stats = sm['_caches']?.account?.stats() ?? deactivatedStats
this.config.logger.info(
`Account cache stats size=${stats.size} reads=${stats.reads} hits=${stats.hits} writes=${stats.writes}`,
)
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
stats = !sm._storageCacheSettings.deactivate ? sm._storageCache.stats() : disactivatedStats
stats = sm['_caches']?.storage?.stats() ?? deactivatedStats
this.config.logger.info(
`Storage cache stats size=${stats.size} reads=${stats.reads} hits=${stats.hits} writes=${stats.writes}`,
)
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
stats = !sm._codeCacheSettings.deactivate ? sm._codeCache.stats() : disactivatedStats
stats = sm['_caches']?.code?.stats() ?? deactivatedStats
this.config.logger.info(
`Code cache stats size=${stats.size} reads=${stats.reads} hits=${stats.hits} writes=${stats.writes}`,
)
const tStats = (sm._trie as Trie).database().stats()
const tStats = sm['_trie'].database().stats()
this.config.logger.info(
`Trie cache stats size=${tStats.size} reads=${tStats.cache.reads} hits=${tStats.cache.hits} ` +
`writes=${tStats.cache.writes} readsDB=${tStats.db.reads} hitsDB=${tStats.db.hits} writesDB=${tStats.db.writes}`,
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ import type { EthProtocol } from '../../net/protocol/index.js'
import type { FullEthereumService, Service } from '../../service/index.js'
import type { RpcTx } from '../types.js'
import type { Block, JsonRpcBlock } from '@ethereumjs/block'
import type { Proof } from '@ethereumjs/common'
import type { Log } from '@ethereumjs/evm'
import type { Proof } from '@ethereumjs/statemanager'
import type {
FeeMarketEIP1559Transaction,
LegacyTransaction,
Expand Down
31 changes: 0 additions & 31 deletions packages/common/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,35 +169,4 @@ export interface StateManagerInterface {
*/
clearCaches(): void
shallowCopy(downlevelCaches?: boolean): StateManagerInterface

/*
* Cache properties
*/
_accountCache?: Cache
_storageCache?: Cache
_codeCache?: Cache

_accountCacheSettings?: CacheSettings
_storageCacheSettings?: CacheSettings
_codeCacheSettings?: CacheSettings
}

/**
* Cache related
*/
export enum CacheType {
LRU = 'lru',
ORDERED_MAP = 'ordered_map',
}

export type CacheSettings = {
deactivate: boolean
type: CacheType
size: number
}

interface Cache {
checkpoint(): void
commit(): void
revert(): void
}
6 changes: 3 additions & 3 deletions packages/statemanager/src/cache/account.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CacheType } from '@ethereumjs/common'
import { bytesToUnprefixedHex } from '@ethereumjs/util'
import { OrderedMap } from '@js-sdsl/ordered-map'
import debugDefault from 'debug'
import { LRUCache } from 'lru-cache'

import { Cache } from './cache.js'
import { CacheType } from './types.js'

import type { CacheOpts } from './types.js'
import type { Account, Address } from '@ethereumjs/util'
Expand Down Expand Up @@ -68,14 +68,14 @@ export class AccountCache extends Cache {
put(
address: Address,
account: Account | undefined,
couldBeParitalAccount: boolean = false,
couldBePartialAccount: boolean = false,
): void {
const addressHex = bytesToUnprefixedHex(address.bytes)
this._saveCachePreState(addressHex)
const elem = {
accountRLP:
account !== undefined
? couldBeParitalAccount
? couldBePartialAccount
? account.serializeWithPartialInfo()
: account.serialize()
: undefined,
Expand Down
89 changes: 89 additions & 0 deletions packages/statemanager/src/cache/caches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { AccountCache } from './account.js'
import { CodeCache } from './code.js'
import { StorageCache } from './storage.js'
import { CacheType, type CachesStateManagerOpts } from './types.js'

import type { CacheOpts } from './types.js'
import type { Address } from '@ethereumjs/util'

export class Caches {
account?: AccountCache
code?: CodeCache
storage?: StorageCache

settings: Record<'account' | 'code' | 'storage', CacheOpts>

constructor(opts: CachesStateManagerOpts = {}) {
const accountSettings = {
type: opts.account?.type ?? CacheType.ORDERED_MAP,
size: opts.account?.size ?? 100000,
}

const codeSettings = {
type: opts.code?.type ?? CacheType.ORDERED_MAP,
size: opts.code?.size ?? 20000,
}

const storageSettings = {
type: opts.storage?.type ?? CacheType.ORDERED_MAP,
size: opts.storage?.size ?? 20000,
}

this.settings = {
account: accountSettings,
code: codeSettings,
storage: storageSettings,
}

if (this.settings.account.size !== 0) {
this.account = new AccountCache({
size: this.settings.account.size,
type: this.settings.account.type,
})
}

if (this.settings.code.size !== 0) {
this.code = new CodeCache({
size: this.settings.code.size,
type: this.settings.code.type,
})
}

if (this.settings.storage.size !== 0) {
this.storage = new StorageCache({
size: this.settings.storage.size,
type: this.settings.storage.type,
})
}
}

checkpoint() {
this.account?.checkpoint()
this.storage?.checkpoint()
this.code?.checkpoint()
}

clear() {
this.account?.clear()
this.storage?.clear()
this.code?.clear()
}

commit() {
this.account?.commit()
this.storage?.commit()
this.code?.commit()
}

deleteAccount(address: Address) {
this.code?.del(address)
this.account?.del(address)
this.storage?.clearStorage(address)
}

revert() {
this.account?.revert()
this.storage?.revert()
this.code?.revert()
}
}
2 changes: 1 addition & 1 deletion packages/statemanager/src/cache/code.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CacheType } from '@ethereumjs/common'
import { bytesToUnprefixedHex } from '@ethereumjs/util'
import { OrderedMap } from '@js-sdsl/ordered-map'
import debugDefault from 'debug'
import { LRUCache } from 'lru-cache'

import { Cache } from './cache.js'
import { CacheType } from './types.js'

import type { CacheOpts } from './types.js'
import type { Address } from '@ethereumjs/util'
Expand Down
1 change: 1 addition & 0 deletions packages/statemanager/src/cache/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './account.js'
export * from './caches.js'
export * from './code.js'
export * from './originalStorageCache.js'
export * from './storage.js'
Expand Down
2 changes: 1 addition & 1 deletion packages/statemanager/src/cache/storage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CacheType } from '@ethereumjs/common'
import { bytesToUnprefixedHex, hexToBytes } from '@ethereumjs/util'
import { OrderedMap } from '@js-sdsl/ordered-map'
import debugDefault from 'debug'
import { LRUCache } from 'lru-cache'

import { Cache } from './cache.js'
import { CacheType } from './types.js'

import type { CacheOpts } from './types.js'
import type { Address } from '@ethereumjs/util'
Expand Down
32 changes: 31 additions & 1 deletion packages/statemanager/src/cache/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
import type { CacheType } from '@ethereumjs/common'
export enum CacheType {
LRU = 'lru',
ORDERED_MAP = 'ordered_map',
}

export interface CacheOpts {
/**
* Size of the cache (only for LRU cache)
*
* Default: 100000 (account cache) / 20000 (storage cache) / 20000 (code cache)
*
* Note: the cache/trie interplay mechanism is designed in a way that
* the theoretical number of max modified accounts between two flush operations
* should be smaller than the cache size, otherwise the cache will "forget" the
* old modifications resulting in an incomplete set of trie-flushed accounts.
*/
size: number
/**
* Cache type to use.
*
* Available options:
*
* ORDERED_MAP: Cache with no fixed upper bound and dynamic allocation,
* use for dynamic setups like testing or similar.
*
* LRU: LRU cache with pre-allocation of memory and a fixed size.
* Use for larger and more persistent caches.
*/
type: CacheType
}

export interface CachesStateManagerOpts {
account?: Partial<CacheOpts>
code?: Partial<CacheOpts>
storage?: Partial<CacheOpts>
}
Loading

0 comments on commit 45e0a6d

Please sign in to comment.