deth
Version:
Ethereum node focused on Developer Experience
107 lines (106 loc) • 4.52 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ethereumjs_account_1 = __importDefault(require("ethereumjs-account"));
const ts_essentials_1 = require("ts-essentials");
const ethereumjs_util_1 = require("ethereumjs-util");
const CheckpointMap_1 = require("./CheckpointMap");
const primitives_1 = require("../../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
*/
class DethStateManger {
constructor(accountsState = new CheckpointMap_1.CheckpointMap(), codeState = new CheckpointMap_1.CheckpointMap(), storageState = new CheckpointMap_1.CheckpointMap(), savedAccountsState = new CheckpointMap_1.CheckpointMap(), savedCodeState = new CheckpointMap_1.CheckpointMap(), savedStorageState = new CheckpointMap_1.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 ethereumjs_account_1.default()));
return new ethereumjs_account_1.default(account.serialize());
}
putAccount(address, account) {
this.accountsState.set(address, account);
}
putContractCode(address, code) {
const codeHashAsBuffer = ethereumjs_util_1.keccak256(code);
const codeHash = primitives_1.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(primitives_1.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 = primitives_1.bufferToHash(ethereumjs_util_1.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);
ts_essentials_1.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);
}
}
exports.DethStateManger = DethStateManger;