UNPKG

@synthesizer-libs/statemanager

Version:
121 lines 4.65 kB
import { Account, bytesToHex } from '@synthesizer-libs/util'; import { keccak256 } from 'ethereum-cryptography/keccak.js'; import { OriginalStorageCache } from './cache/originalStorageCache.js'; import { modifyAccountFields } from './util.js'; /** * Simple and dependency-free state manager for basic state access use cases * where a merkle-patricia or verkle tree backed state manager is too heavy-weight. * * This state manager comes with the basic state access logic for * accounts, storage and code (put* and get* methods) as well as a simple * implementation of checkpointing but lacks methods implementations of * state root related logic as well as some other non-core functions. * * Functionality provided is sufficient to be used for simple EVM use * cases and the state manager is used as default there. * * For a more full fledged and MPT-backed state manager implementation * have a look at the `@synthesizer-libs/statemanager` package. */ export class SimpleStateManager { constructor(opts = {}) { this.accountStack = []; this.codeStack = []; this.storageStack = []; this.checkpointSync(); this.originalStorageCache = new OriginalStorageCache(this.getStorage.bind(this)); this.common = opts.common; } topAccountStack() { return this.accountStack[this.accountStack.length - 1]; } topCodeStack() { return this.codeStack[this.codeStack.length - 1]; } topStorageStack() { return this.storageStack[this.storageStack.length - 1]; } // Synchronous version of checkpoint() to allow to call from constructor checkpointSync() { const newTopA = new Map(this.topAccountStack()); for (const [address, account] of newTopA) { const accountCopy = account !== undefined ? Object.assign(Object.create(Object.getPrototypeOf(account)), account) : undefined; newTopA.set(address, accountCopy); } this.accountStack.push(newTopA); this.codeStack.push(new Map(this.topCodeStack())); this.storageStack.push(new Map(this.topStorageStack())); } async getAccount(address) { return this.topAccountStack().get(address.toString()); } async putAccount(address, account) { this.topAccountStack().set(address.toString(), account); } async deleteAccount(address) { this.topAccountStack().set(address.toString(), undefined); } async modifyAccountFields(address, accountFields) { await modifyAccountFields(this, address, accountFields); } async getCode(address) { return this.topCodeStack().get(address.toString()) ?? new Uint8Array(0); } async putCode(address, value) { this.topCodeStack().set(address.toString(), value); if ((await this.getAccount(address)) === undefined) { await this.putAccount(address, new Account()); } await this.modifyAccountFields(address, { codeHash: (this.common?.customCrypto.keccak256 ?? keccak256)(value), }); } async getCodeSize(address) { const contractCode = await this.getCode(address); return contractCode.length; } async getStorage(address, key) { return (this.topStorageStack().get(`${address.toString()}_${bytesToHex(key)}`) ?? new Uint8Array(0)); } async putStorage(address, key, value) { this.topStorageStack().set(`${address.toString()}_${bytesToHex(key)}`, value); } async clearStorage() { } async checkpoint() { this.checkpointSync(); } async commit() { this.accountStack.splice(-2, 1); this.codeStack.splice(-2, 1); this.storageStack.splice(-2, 1); } async revert() { this.accountStack.pop(); this.codeStack.pop(); this.storageStack.pop(); } async flush() { } clearCaches() { } shallowCopy() { const copy = new SimpleStateManager({ common: this.common }); for (let i = 0; i < this.accountStack.length; i++) { copy.accountStack.push(new Map(this.accountStack[i])); copy.codeStack.push(new Map(this.codeStack[i])); copy.storageStack.push(new Map(this.storageStack[i])); } return copy; } // State root functionality not implemented getStateRoot() { throw new Error('Method not implemented.'); } setStateRoot() { throw new Error('Method not implemented.'); } hasStateRoot() { throw new Error('Method not implemented.'); } } //# sourceMappingURL=simpleStateManager.js.map