deth
Version:
Ethereum node focused on Developer Experience
119 lines (118 loc) • 5.18 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_util_1 = require("ethereumjs-util");
const ethereumjs_tx_1 = require("ethereumjs-tx");
const model_1 = require("../model");
const primitives_1 = require("../primitives");
const initializeVM_1 = require("./initializeVM");
const getLatestBlock_1 = require("./getLatestBlock");
const putBlock_1 = require("./putBlock");
const runIsolatedTransaction_1 = require("./runIsolatedTransaction");
const DethStateManger_1 = require("./storage/DethStateManger");
const DethBlockchain_1 = require("./storage/DethBlockchain");
// eslint-disable-next-line
const promisified_1 = __importDefault(require("ethereumts-vm/dist/state/promisified"));
const BlockchainAdapter_1 = require("./storage/BlockchainAdapter");
const StateManagerAdapter_1 = require("./storage/StateManagerAdapter");
const SnapshotObject_1 = require("./storage/SnapshotObject");
/**
* TestVM is a wrapper around ethereumts-vm (our fork). It provides a promise-based
* interface and abstracts away weird ethereumjs specific details
*/
class TestVM {
constructor(options) {
this.options = options;
this.pendingTransactions = [];
this.transactions = new Map();
this.receipts = new Map();
this.snapshots = [];
this.state = new SnapshotObject_1.SnapshotObject({
stateManger: new DethStateManger_1.DethStateManger(),
blockchain: new DethBlockchain_1.DethBlockchain(),
}, (t) => ({
blockchain: t.blockchain.copy(),
stateManger: t.stateManger.copy(),
}));
}
async init() {
this.vm = await initializeVM_1.initializeVM(this.options, this.state.value.stateManger, this.state.value.blockchain);
}
// @todo this requires better typings (whole step hooks mechanism)
installStepHook(hook) {
this.vm.on('step', hook);
}
makeSnapshot() {
return this.state.makeSnapshot();
}
revertToSnapshot(id) {
this.state.revert(id);
this.hotswapStateStorageForVm();
}
// change internals of VM to point to new blockchain and state machine
hotswapStateStorageForVm() {
const blockchainAdapter = new BlockchainAdapter_1.BlockchainAdapter(this.state.value.blockchain);
this.vm.blockchain = blockchainAdapter;
const stateManagerAdapter = new StateManagerAdapter_1.StateManagerAdapter(this.state.value.stateManger);
this.vm.stateManager = stateManagerAdapter;
this.vm.pStateManager = new promisified_1.default(stateManagerAdapter);
}
async getBlockNumber() {
const block = await getLatestBlock_1.getLatestBlock(this.vm);
return primitives_1.bufferToQuantity(block.header.number);
}
async getLatestBlock() {
const block = await getLatestBlock_1.getLatestBlock(this.vm);
return model_1.toBlockResponse(block);
}
async addPendingTransaction(signedTransaction) {
const transaction = new ethereumjs_tx_1.Transaction(signedTransaction, { common: this.vm._common });
this.pendingTransactions.push(transaction);
return primitives_1.bufferToHash(transaction.hash());
}
async mineBlock(clockSkew) {
const transactions = this.pendingTransactions;
this.pendingTransactions = [];
const { receipts, responses } = await putBlock_1.putBlock(this.vm, transactions, this.options, clockSkew);
for (const receipt of receipts) {
this.receipts.set(receipt.transactionHash, receipt);
}
for (const response of responses) {
this.transactions.set(response.hash, response);
}
}
getTransaction(hash) {
return this.transactions.get(hash);
}
getTransactionReceipt(hash) {
return this.receipts.get(hash);
}
async getNonce(address) {
const account = await this.getAccount(address);
return primitives_1.bufferToQuantity(account.nonce);
}
async getBalance(address) {
const account = await this.getAccount(address);
return primitives_1.bufferToQuantity(account.balance);
}
async getAccount(address) {
return this.state.value.stateManger.getAccount(address);
}
async getCode(address) {
const code = this.state.value.stateManger.getContractCode(address);
return primitives_1.bufferToHexData(code);
}
async runIsolatedTransaction(transaction, clockSkew) {
return runIsolatedTransaction_1.runIsolatedTransaction(this.vm, transaction, this.options, clockSkew);
}
async getBlock(hashOrNumber) {
const query = hashOrNumber.length === 66 ? ethereumjs_util_1.toBuffer(hashOrNumber) : new ethereumjs_util_1.BN(hashOrNumber.substr(2), 'hex');
const block = await new Promise((resolve, reject) => {
this.vm.blockchain.getBlock(query, (err, block) => (err != null ? reject(err) : resolve(block)));
});
return model_1.toBlockResponse(block);
}
}
exports.TestVM = TestVM;