UNPKG

deth

Version:

Ethereum node focused on Developer Experience

101 lines (100 loc) 3.98 kB
import Account from 'ethereumjs-account'; import { assert } from 'ts-essentials'; import { keccak256 } from 'ethereumjs-util'; import { CheckpointMap } from './CheckpointMap'; import { bufferToHash } from '../../primitives'; const EMPTY_BUFFER = Buffer.from(''); /** * Holds account, code, storage state in memory. * Pretends to maintain trie like structure by generating fake state roots and load them as snapshots when needed */ export class DethStateManger { constructor(accountsState = new CheckpointMap(), codeState = new CheckpointMap(), storageState = new CheckpointMap(), savedAccountsState = new CheckpointMap(), savedCodeState = new CheckpointMap(), savedStorageState = new CheckpointMap(), saveIndex = 0) { this.accountsState = accountsState; this.codeState = codeState; this.storageState = storageState; this.savedAccountsState = savedAccountsState; this.savedCodeState = savedCodeState; this.savedStorageState = savedStorageState; this.saveIndex = saveIndex; } copy() { return new DethStateManger(this.accountsState.copy(), this.codeState.copy(), this.storageState.copy(), this.savedAccountsState.copy(), this.savedCodeState.copy(), this.savedStorageState.copy(), this.saveIndex); } getAccount(address) { var _a; const account = (_a = this.accountsState.get(address), (_a !== null && _a !== void 0 ? _a : new Account())); return new Account(account.serialize()); } putAccount(address, account) { this.accountsState.set(address, account); } putContractCode(address, code) { const codeHashAsBuffer = keccak256(code); const codeHash = bufferToHash(codeHashAsBuffer); const account = this.getAccount(address); account.codeHash = codeHashAsBuffer; this.putAccount(address, account); this.codeState.set(codeHash, code); } getContractCode(address) { const account = this.getAccount(address); return this.codeState.get(bufferToHash(account.codeHash)) || EMPTY_BUFFER; } getContractStorage(address, key) { var _a, _b; const s = (_a = this.storageState.get(address), (_a !== null && _a !== void 0 ? _a : {})); return _b = s[key], (_b !== null && _b !== void 0 ? _b : EMPTY_BUFFER); } putContractStorage(address, key, value) { var _a; const s = (_a = this.storageState.get(address), (_a !== null && _a !== void 0 ? _a : {})); const newState = { ...s, [key]: value }; this.storageState.set(address, newState); } clearContractStorage(address) { this.storageState.set(address, {}); } checkpoint() { this.accountsState.checkpoint(); this.codeState.checkpoint(); this.storageState.checkpoint(); } commit() { this.accountsState.commit(); this.codeState.commit(); this.storageState.commit(); } revert() { this.accountsState.revert(); this.codeState.revert(); this.storageState.revert(); } getStateRoot() { const i = this.saveIndex++; const hash = bufferToHash(keccak256(i)); this.savedAccountsState.set(hash, this.accountsState.copy()); this.savedCodeState.set(hash, this.codeState.copy()); this.savedStorageState.set(hash, this.storageState.copy()); return hash; } setStateRoot(root) { { const s = this.savedAccountsState.get(root); assert(s, `state root ${root.toString()} doesnt exist`); this.accountsState = s; } { const s = this.savedCodeState.get(root); this.codeState = s; } { const s = this.savedStorageState.get(root); this.storageState = s; } } isAccountEmpty(address) { // @todo fix, it's simplified implementation return !!this.accountsState.get(address); } }