UNPKG

vaporyjs-vm

Version:
1,714 lines (1,514 loc) 1.25 MB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ (function (Buffer){ var VM = require('../index.js') // create a new VM instance var vm = new VM() var code = '7f4e616d65526567000000000000000000000000000000000000000000000000003055307f4e616d6552656700000000000000000000000000000000000000000000000000557f436f6e666967000000000000000000000000000000000000000000000000000073661005d2720d855f1d9976f88bb10c1a3398c77f5573661005d2720d855f1d9976f88bb10c1a3398c77f7f436f6e6669670000000000000000000000000000000000000000000000000000553360455560df806100c56000396000f3007f726567697374657200000000000000000000000000000000000000000000000060003514156053576020355415603257005b335415603e5760003354555b6020353360006000a233602035556020353355005b60007f756e72656769737465720000000000000000000000000000000000000000000060003514156082575033545b1560995733335460006000a2600033545560003355005b60007f6b696c6c00000000000000000000000000000000000000000000000000000000600035141560cb575060455433145b1560d25733ff5b6000355460005260206000f3' code = Buffer.from(code, 'hex') vm.on('step', function (data) { console.log(data.opcode.name) }) vm.runCode({ code: code, gasLimit: Buffer.from('ffffffff', 'hex') }, function (err, results) { console.log('returned: ' + results.return.toString('hex')) console.log('gasUsed: ' + results.gasUsed.toString()) }) }).call(this,require("buffer").Buffer) },{"../index.js":2,"buffer":130}],2:[function(require,module,exports){ module.exports = require('./lib/index.js') },{"./lib/index.js":7}],3:[function(require,module,exports){ (function (Buffer){ const assert = require('assert') const utils = require('vaporyjs-util') const byteSize = 256 /** * Represents a Bloom * @constructor * @param {Buffer} bitvector */ var Bloom = module.exports = function (bitvector) { if (!bitvector) { this.bitvector = utils.zeros(byteSize) } else { assert(bitvector.length === byteSize, 'bitvectors must be 2048 bits long') this.bitvector = bitvector } } /** * adds an element to a bit vector of a 64 byte bloom filter * @method add * @param {Buffer} element */ Bloom.prototype.add = function (e) { e = utils.sha3(e) var mask = 2047 // binary 11111111111 for (var i = 0; i < 3; i++) { var first2bytes = e.readUInt16BE(i * 2) var loc = mask & first2bytes var byteLoc = loc >> 3 var bitLoc = 1 << loc % 8 this.bitvector[byteSize - byteLoc - 1] |= bitLoc } } /** * checks if an element is in the blooom * @method check * @param {Buffer} element */ Bloom.prototype.check = function (e) { e = utils.sha3(e) var mask = 511 // binary 111111111 var match = true for (var i = 0; i < 3 && match; i++) { var first2bytes = e.readUInt16BE(i * 2) var loc = mask & first2bytes var byteLoc = loc >> 3 var bitLoc = 1 << loc % 8 match = (this.bitvector[byteSize - byteLoc - 1] & bitLoc) } return Boolean(match) } /** * checks if multple topics are in a bloom * @method check * @param {Buffer} element */ Bloom.prototype.multiCheck = function (topics) { var self = this var match = true topics.forEach(function (t) { if (!Buffer.isBuffer(t)) { t = Buffer.from(t, 'hex') } match && self.check(t) }) return match } /** * bitwise or blooms together * @method or * @param {Bloom} bloom */ Bloom.prototype.or = function (bloom) { if (bloom) { for (var i = 0; i <= byteSize; i++) { this.bitvector[i] = this.bitvector[i] | bloom.bitvector[i] } } } }).call(this,require("buffer").Buffer) },{"assert":128,"buffer":130,"vaporyjs-util":65}],4:[function(require,module,exports){ (function (Buffer){ const Tree = require('functional-red-black-tree') const Account = require('vaporyjs-account') const async = require('async') var Cache = module.exports = function (trie) { this._cache = Tree() this._checkpoints = [] this._deletes = [] this._trie = trie } Cache.prototype.put = function (key, val, fromTrie) { var modified = !fromTrie key = key.toString('hex') var it = this._cache.find(key) if (it.node) { this._cache = it.update({ val: val, modified: modified }) } else { this._cache = this._cache.insert(key, { val: val, modified: modified }) } } // returns the queried account or an empty account Cache.prototype.get = function (key) { var account = this.lookup(key) return account || new Account() } // returns the queried account or undefined Cache.prototype.lookup = function (key) { key = key.toString('hex') var it = this._cache.find(key) if (it.node) { return new Account(it.value.val) } } Cache.prototype.getOrLoad = function (key, cb) { var self = this var account = this.lookup(key) key = key.toString('hex') if (account) { var raw = account && account.isEmpty() ? null : account.raw cb(null, account, raw) } else { this._trie.get(Buffer.from(key, 'hex'), function (err, raw) { var account = new Account(raw) self._cache = self._cache.insert(key, { val: account, modified: false }) cb(err, account, raw) }) } } Cache.prototype.flush = function (cb) { var it = this._cache.begin var self = this var next = true async.whilst(function () { return next }, function (done) { if (it.value.modified) { it.value.modified = false it.value.val = it.value.val.serialize() self._trie.put(Buffer.from(it.key, 'hex'), it.value.val, function () { next = it.hasNext it.next() done() }) } else { next = it.hasNext it.next() done() } }, function () { async.eachSeries(self._deletes, function (address, done) { self._trie.del(address, done) }, function () { self._deletes = [] cb() }) }) } Cache.prototype.checkpoint = function () { this._checkpoints.push(this._cache) } Cache.prototype.revert = function () { this._cache = this._checkpoints.pop(this._cache) } Cache.prototype.commit = function () { this._checkpoints.pop() } Cache.prototype.clear = function () { this._deletes = [] this._cache = Tree() } Cache.prototype.del = function (key) { this._deletes.push(key) key = key.toString('hex') this._cache = this._cache.remove(key) } }).call(this,require("buffer").Buffer) },{"async":29,"buffer":130,"vaporyjs-account":58,"functional-red-black-tree":66}],5:[function(require,module,exports){ exports.ERROR = { OUT_OF_GAS: 'out of gas', STACK_UNDERFLOW: 'stack underflow', INVALID_JUMP: 'invalid JUMP', INVALID_OPCODE: 'invalid opcode' } },{}],6:[function(require,module,exports){ (function (Buffer){ var utils = require('vaporyjs-util') module.exports = { getBlock: function (n, cb) { var hash = utils.sha3(Buffer.from(utils.bufferToInt(n).toString())) var block = { hash: function () { return hash } } cb(null, block) } } }).call(this,require("buffer").Buffer) },{"buffer":130,"vaporyjs-util":65}],7:[function(require,module,exports){ require('es6-shim') const util = require('util') const async = require('async') const BN = require('bn.js') const common = require('vapory-common') const StateManager = require('./stateManager.js') var AsyncEventEmitter = require('async-eventemitter') // require the percomiled contracts const num01 = require('./precompiled/01-ecrecover.js') const num02 = require('./precompiled/02-sha256.js') const num03 = require('./precompiled/03-repemd160.js') const num04 = require('./precompiled/04-identity.js') module.exports = VM VM.deps = { vapUtil: require('vaporyjs-util'), Account: require('vaporyjs-account'), Trie: require('@vaporyjs/merkle-patricia-tree'), rlp: require('@vaporyjs/rlp') } /** * @constructor */ function VM (trie, blockchain) { this.stateManager = new StateManager({ trie: trie, blockchain: blockchain }) // temporary // this is here for a gradual transition to StateManager this.blockchain = this.stateManager.blockchain this.trie = this.stateManager.trie // precompiled contracts this._precomiled = {} this._precomiled['0000000000000000000000000000000000000001'] = num01 this._precomiled['0000000000000000000000000000000000000002'] = num02 this._precomiled['0000000000000000000000000000000000000003'] = num03 this._precomiled['0000000000000000000000000000000000000004'] = num04 AsyncEventEmitter.call(this) } util.inherits(VM, AsyncEventEmitter) VM.prototype.runCode = require('./runCode.js') VM.prototype.runJIT = require('./runJit.js') VM.prototype.runBlock = require('./runBlock.js') VM.prototype.runTx = require('./runTx.js') VM.prototype.runCall = require('./runCall.js') VM.prototype.runBlockchain = require('./runBlockchain.js') VM.prototype.copy = function () { var trie = this.trie.copy() return new VM(trie, this.blockchain) } /** * Loads precomiled contracts into the state */ VM.prototype.loadCompiled = function (address, src, cb) { this.trie.db.put(address, src, cb) } VM.prototype.populateCache = function (addresses, cb) { this.stateManager.warmCache(addresses, cb) } // VM.prototype.createTraceStream = function () { // var rs = new Readable({ // objectMode: true // }) // var step = 0 // var next // rs._read = function () { // if (next) { // next() // } // } // this.onStep = function (info, done) { // var logObj = { // step: step, // pc: new BN(info.pc).toString(), // depth: info.depth, // opcode: info.opcode, // gas: info.gasLeft.toString(), // memory: (Buffer.from(info.memory)).toString('hex'), // storage: [], // address: info.address.toString('hex') // } // step++ // logObj.stack = info.stack.map(function (item) { // return vapUtil.pad(item, 32).toString('hex') // }) // var stream = info.storageTrie.createReadStream() // stream.on('data', function(data) { // logObj.storage.push([vapUtil.unpad(data.key).toString('hex'), rlp.decode(data.value).toString('hex')]) // }) // stream.on('end', function() { // var notFull = rs.push(logObj) // if (notFull) { // done() // } else { // next = done // } // }) // done() // } // return rs // } },{"./precompiled/01-ecrecover.js":11,"./precompiled/02-sha256.js":12,"./precompiled/03-repemd160.js":13,"./precompiled/04-identity.js":14,"./runBlock.js":15,"./runBlockchain.js":16,"./runCall.js":17,"./runCode.js":18,"./runJit.js":19,"./runTx.js":20,"./stateManager.js":21,"async":29,"async-eventemitter":26,"bn.js":30,"es6-shim":55,"vapory-common":56,"vaporyjs-account":58,"vaporyjs-util":65,"@vaporyjs/merkle-patricia-tree":103,"rlp":121,"util":296}],8:[function(require,module,exports){ const BN = require('bn.js') const pow32 = new BN('010000000000000000000000000000000000000000000000000000000000000000', 16) const pow31 = new BN('0100000000000000000000000000000000000000000000000000000000000000', 16) const pow30 = new BN('01000000000000000000000000000000000000000000000000000000000000', 16) const pow29 = new BN('010000000000000000000000000000000000000000000000000000000000', 16) const pow28 = new BN('0100000000000000000000000000000000000000000000000000000000', 16) const pow27 = new BN('01000000000000000000000000000000000000000000000000000000', 16) const pow26 = new BN('010000000000000000000000000000000000000000000000000000', 16) const pow25 = new BN('0100000000000000000000000000000000000000000000000000', 16) const pow24 = new BN('01000000000000000000000000000000000000000000000000', 16) const pow23 = new BN('010000000000000000000000000000000000000000000000', 16) const pow22 = new BN('0100000000000000000000000000000000000000000000', 16) const pow21 = new BN('01000000000000000000000000000000000000000000', 16) const pow20 = new BN('010000000000000000000000000000000000000000', 16) const pow19 = new BN('0100000000000000000000000000000000000000', 16) const pow18 = new BN('01000000000000000000000000000000000000', 16) const pow17 = new BN('010000000000000000000000000000000000', 16) const pow16 = new BN('0100000000000000000000000000000000', 16) const pow15 = new BN('01000000000000000000000000000000', 16) const pow14 = new BN('010000000000000000000000000000', 16) const pow13 = new BN('0100000000000000000000000000', 16) const pow12 = new BN('01000000000000000000000000', 16) const pow11 = new BN('010000000000000000000000', 16) const pow10 = new BN('0100000000000000000000', 16) const pow9 = new BN('01000000000000000000', 16) const pow8 = new BN('010000000000000000', 16) const pow7 = new BN('0100000000000000', 16) const pow6 = new BN('01000000000000', 16) const pow5 = new BN('010000000000', 16) const pow4 = new BN('0100000000', 16) const pow3 = new BN('01000000', 16) const pow2 = new BN('010000', 16) const pow1 = new BN('0100', 16) module.exports = function (a) { if (a.cmp(pow1) === -1) { return 0 } else if (a.cmp(pow2) === -1) { return 1 } else if (a.cmp(pow3) === -1) { return 2 } else if (a.cmp(pow4) === -1) { return 3 } else if (a.cmp(pow5) === -1) { return 4 } else if (a.cmp(pow6) === -1) { return 5 } else if (a.cmp(pow7) === -1) { return 6 } else if (a.cmp(pow8) === -1) { return 7 } else if (a.cmp(pow9) === -1) { return 8 } else if (a.cmp(pow10) === -1) { return 9 } else if (a.cmp(pow11) === -1) { return 10 } else if (a.cmp(pow12) === -1) { return 11 } else if (a.cmp(pow13) === -1) { return 12 } else if (a.cmp(pow14) === -1) { return 13 } else if (a.cmp(pow15) === -1) { return 14 } else if (a.cmp(pow16) === -1) { return 15 } else if (a.cmp(pow17) === -1) { return 16 } else if (a.cmp(pow18) === -1) { return 17 } else if (a.cmp(pow19) === -1) { return 18 } else if (a.cmp(pow20) === -1) { return 19 } else if (a.cmp(pow21) === -1) { return 20 } else if (a.cmp(pow22) === -1) { return 21 } else if (a.cmp(pow23) === -1) { return 22 } else if (a.cmp(pow24) === -1) { return 23 } else if (a.cmp(pow25) === -1) { return 24 } else if (a.cmp(pow26) === -1) { return 25 } else if (a.cmp(pow27) === -1) { return 26 } else if (a.cmp(pow28) === -1) { return 27 } else if (a.cmp(pow29) === -1) { return 28 } else if (a.cmp(pow30) === -1) { return 29 } else if (a.cmp(pow31) === -1) { return 30 } else if (a.cmp(pow32) === -1) { return 31 } else { return 32 } } },{"bn.js":30}],9:[function(require,module,exports){ (function (Buffer){ const async = require('async') const fees = require('vapory-common') const utils = require('vaporyjs-util') const BN = utils.BN const rlp = utils.rlp const constants = require('./constants.js') const logTable = require('./logTable.js') const ERROR = constants.ERROR const MAX_INT = 9007199254740991 // the opcode functions module.exports = { STOP: function (runState) { runState.stopped = true }, ADD: function (a, b, runState) { return Buffer.from( new BN(a) .add(new BN(b)) .mod(utils.TWO_POW256) .toArray()) }, MUL: function (a, b, runState) { return Buffer.from( new BN(a) .mul(new BN(b)).mod(utils.TWO_POW256) .toArray() ) }, SUB: function (a, b, runState) { return utils.toUnsigned( new BN(a) .sub(new BN(b)) ) }, DIV: function (a, b, runState) { a = new BN(a) b = new BN(b) var r if (b.toString() === '0') { r = [0] } else { r = a.div(b).toArray() } return Buffer.from(r) }, SDIV: function (a, b, runState) { a = utils.fromSigned(a) b = utils.fromSigned(b) var r if (b.toString() === '0') { r = Buffer.from([0]) } else { r = utils.toUnsigned(a.div(b)) } return r }, MOD: function (a, b, runState) { a = new BN(a) b = new BN(b) var r if (b.toString() === '0') { r = [0] } else { r = a.mod(b).toArray() } return Buffer.from(r) }, SMOD: function (a, b, runState) { a = utils.fromSigned(a) b = utils.fromSigned(b) var r if (b.toString() === '0') { r = Buffer.from([0]) } else { r = a.abs().mod(b.abs()) if (a.sign) { r = r.neg() } r = utils.toUnsigned(r) } return r }, ADDMOD: function (a, b, c, runState) { a = new BN(a).add(new BN(b)) c = new BN(c) var r if (c.toString() === '0') { r = [0] } else { r = a.mod(c).toArray() } return Buffer.from(r) }, MULMOD: function (a, b, c, runState) { a = new BN(a).mul(new BN(b)) c = new BN(c) var r if (c.toString() === '0') { r = [0] } else { r = a.mod(c).toArray() } return Buffer.from(r) }, EXP: function (base, exponent, runState) { base = new BN(base) exponent = new BN(exponent) var m = BN.red(utils.TWO_POW256) var result base = base.toRed(m) if (exponent.cmpn(0) !== 0) { var bytes = 1 + logTable(exponent) subGas(runState, new BN(bytes).muln(fees.expByteGas.v)) result = Buffer.from(base.redPow(exponent).toArray()) } else { result = Buffer.from([1]) } return result }, SIGNEXTEND: function (k, runState) { k = new BN(k) var extendOnes = false if (k.cmpn(31) <= 0) { var val = Buffer.from(32) utils.pad(runState.stack.pop(), 32).copy(val) if (val[31 - k] & 0x80) { extendOnes = true } // 31-k-1 since k-th byte shouldn't be modified for (var i = 30 - k; i >= 0; i--) { val[i] = extendOnes ? 0xff : 0 } return val } }, // 0x10 range - bit ops LT: function (a, b, runState) { return Buffer.from([ new BN(a) .cmp(new BN(b)) === -1 ]) }, GT: function (a, b, runState) { return Buffer.from([ new BN(a) .cmp(new BN(b)) === 1 ]) }, SLT: function (a, b, runState) { runState.stack.push( Buffer.from([ utils.fromSigned(a) .cmp(utils.fromSigned(b)) === -1 ]) ) }, SGT: function (a, b, runState) { return Buffer.from([ utils.fromSigned(a) .cmp(utils.fromSigned(b)) === 1 ]) }, EQ: function (a, b, runState) { a = utils.unpad(a) b = utils.unpad(b) return Buffer.from([a.toString('hex') === b.toString('hex')]) }, ISZERO: function (a, runState) { a = utils.bufferToInt(a) return Buffer.from([!a]) }, AND: function (a, b, runState) { return Buffer.from(( new BN(a) .and( new BN(b) ) ) .toArray()) }, OR: function (a, b, runState) { return Buffer.from(( new BN(a) .or( new BN(b) ) ) .toArray()) }, XOR: function (a, b, runState) { return Buffer.from(( new BN(a) .xor( new BN(b) ) ) .toArray()) }, NOT: function (a, runState) { return Buffer.from(utils.TWO_POW256.subn(1).sub(new BN(a)) .toArray()) }, BYTE: function (pos, word, runState) { pos = utils.bufferToInt(pos) word = utils.pad(word, 32) var byte if (pos < 32) { byte = utils.intToBuffer(word[pos]) } else { byte = Buffer.from([0]) } return byte }, // 0x20 range - crypto SHA3: function (offset, length, runState) { offset = utils.bufferToInt(offset) length = utils.bufferToInt(length) var data = memLoad(runState, offset, length) // copy fee subGas(runState, new BN(fees.sha3WordGas.v * Math.ceil(length / 32))) return utils.sha3(data) }, // 0x30 range - closure state ADDRESS: function (runState) { return runState.address }, BALANCE: function (address, runState, cb) { var stateManager = runState.stateManager address = address.slice(-20) // shortcut if current account if (address.toString('hex') === runState.address.toString('hex')) { cb(null, runState.contract.balance) return } // otherwise load account then return balance stateManager.getAccountBalance(address, cb) }, ORIGIN: function (runState) { return runState.origin }, CALLER: function (runState) { return runState.caller }, CALLVALUE: function (runState) { return Buffer.from(runState.callValue.toArray()) }, CALLDATALOAD: function (pos, runState) { pos = utils.bufferToInt(pos) var loaded = runState.callData.slice(pos, pos + 32) loaded = loaded.length ? loaded : Buffer.from([0]) // pad end if (loaded.length < 32) { var dif = 32 - loaded.length var pad = Buffer.from(dif) pad.fill(0) loaded = Buffer.concat([loaded, pad], 32) } return loaded }, CALLDATASIZE: function (runState) { if (runState.callData.length === 1 && runState.callData[0] === 0) { return Buffer.from([0]) } else { return utils.intToBuffer(runState.callData.length) } }, CALLDATACOPY: function (memOffset, dataOffsetBuf, dataLength, runState) { memOffset = utils.bufferToInt(memOffset) dataLength = utils.bufferToInt(dataLength) var dataOffset = utils.bufferToInt(dataOffsetBuf) memStore(runState, memOffset, runState.callData, dataOffset, dataLength) // sub the COPY fee subGas(runState, new BN(Number(fees.copyGas.v) * Math.ceil(dataLength / 32))) }, CODESIZE: function (runState) { return utils.intToBuffer(runState.code.length) }, CODECOPY: function (memOffset, codeOffset, length, runState) { memOffset = utils.bufferToInt(memOffset) codeOffset = utils.bufferToInt(codeOffset) length = utils.bufferToInt(length) memStore(runState, memOffset, runState.code, codeOffset, length) // sub the COPY fee subGas(runState, new BN(fees.copyGas.v * Math.ceil(length / 32))) }, EXTCODESIZE: function (address, runState, cb) { var stateManager = runState.stateManager address = address.slice(-20) stateManager.getContractCode(address, function (err, code) { cb(err, utils.intToBuffer(code.length)) }) }, EXTCODECOPY: function (address, memOffset, codeOffset, length, runState, cb) { var stateManager = runState.stateManager address = address.slice(-20) memOffset = utils.bufferToInt(memOffset) codeOffset = utils.bufferToInt(codeOffset) length = utils.bufferToInt(length) subMemUsage(runState, memOffset, length) // copy fee var fee = new BN(Number(fees.copyGas.v) * Math.ceil(length / 32)) subGas(runState, fee) stateManager.getContractCode(address, function (err, code) { code = err ? Buffer.from([0]) : code memStore(runState, memOffset, code, codeOffset, length, false) cb(err) }) }, GASPRICE: function (runState) { runState.stack.push(runState.gasPrice) }, // '0x40' range - block operations BLOCKHASH: function (number, runState, cb) { var stateManager = runState.stateManager number = utils.bufferToInt(number) var diff = utils.bufferToInt(runState.block.header.number) - utils.bufferToInt(number) // block lookups must be within the past 256 blocks if (diff > 256 || diff <= 0) { cb(null, Buffer.from([0])) return } stateManager.getBlockHash(number, function (err, blockHash) { if (err) { // if we are at a low block height and request a blockhash before the genesis block cb(null, Buffer.from([0])) } else { cb(null, blockHash) } }) }, COINBASE: function (runState) { return runState.block.header.coinbase }, TIMESTAMP: function (runState) { return runState.block.header.timestamp }, NUMBER: function (runState) { return runState.block.header.number }, DIFFICULTY: function (runState) { return runState.block.header.difficulty }, GASLIMIT: function (runState) { return runState.block.header.gasLimit }, // 0x50 range - 'storage' and execution POP: function () {}, MLOAD: function (pos, runState) { pos = utils.bufferToInt(pos) var loaded = utils.unpad(memLoad(runState, pos, 32)) return loaded }, MSTORE: function (offset, word, runState) { offset = utils.bufferToInt(offset) word = utils.pad(word, 32) memStore(runState, offset, word, 0, 32) }, MSTORE8: function (offset, byte, runState) { offset = utils.bufferToInt(offset) // grab the last byte byte = byte.slice(byte.length - 1) memStore(runState, offset, byte, 0, 1) }, SLOAD: function (key, runState, cb) { var stateManager = runState.stateManager key = utils.pad(key, 32) stateManager.getContractStorage(runState.address, key, function (err, value) { var loaded = rlp.decode(value) loaded = loaded.length ? loaded : Buffer.from([0]) cb(err, loaded) }) }, SSTORE: function (key, val, runState, cb) { var stateManager = runState.stateManager var address = runState.address key = utils.pad(key, 32) var value = utils.unpad(val) // format input if (value.length === 0) { // deleting a value // set empty buffer to empty string value = '' } else { value = rlp.encode(value) } stateManager.getContractStorage(runState.address, key, function (err, found) { try { if (value === '' && !found) { subGas(runState, new BN(fees.sstoreResetGas.v)) } else if (value === '' && found) { subGas(runState, new BN(fees.sstoreResetGas.v)) runState.gasRefund.iadd(new BN(fees.sstoreRefundGas.v)) } else if (value !== '' && !found) { subGas(runState, new BN(fees.sstoreSetGas.v)) } else if (value !== '' && found) { subGas(runState, new BN(fees.sstoreResetGas.v)) } } catch (e) { cb(e.error) return } stateManager.putContractStorage(address, key, value, function () { runState.contract = stateManager.cache.get(address) cb(err) }) }) }, JUMP: function (dest, runState) { dest = utils.bufferToInt(dest) if (!jumpIsValid(runState, dest)) { trap(ERROR.INVALID_JUMP) } runState.programCounter = dest }, JUMPI: function (c, i, runState) { c = utils.bufferToInt(c) i = utils.bufferToInt(i) var dest = i ? c : runState.programCounter if (i && !jumpIsValid(runState, dest)) { trap(ERROR.INVALID_JUMP) } runState.programCounter = dest }, PC: function (runState) { return utils.intToBuffer(runState.programCounter - 1) }, MSIZE: function (runState) { return utils.intToBuffer(runState.memoryWordCount * 32) }, GAS: function (runState) { return Buffer.from(runState.gasLeft.toArray()) }, JUMPDEST: function (runState) {}, PUSH: function (runState) { var numToPush = runState.opCode - 0x5f var loaded = utils.unpad(runState.code.slice(runState.programCounter, runState.programCounter + numToPush)) runState.programCounter += numToPush return loaded }, DUP: function (runState) { const stackPos = runState.opCode - 0x7f if (stackPos > runState.stack.length) { trap(ERROR.STACK_UNDERFLOW) } // dupilcated stack items point to the same Buffer return runState.stack[runState.stack.length - stackPos] }, SWAP: function (runState) { var stackPos = runState.opCode - 0x8f // check the stack to make sure we have enough items on teh stack var swapIndex = runState.stack.length - stackPos - 1 if (swapIndex < 0) { trap(ERROR.STACK_UNDERFLOW) } // preform the swap var newTop = runState.stack[swapIndex] runState.stack[swapIndex] = runState.stack.pop() return newTop }, LOG: function (memOffset, memLength) { var args = Array.prototype.slice.call(arguments, 0) args.pop() // pop off callback var runState = args.pop() var topics = args.slice(2) topics = topics.map(function (a) { return utils.pad(a, 32) }) memOffset = utils.bufferToInt(memOffset) memLength = utils.bufferToInt(memLength) const numOfTopics = runState.opCode - 0xa0 const mem = memLoad(runState, memOffset, memLength) subGas(runState, new BN(numOfTopics * fees.logTopicGas.v + memLength * fees.logDataGas.v)) // add address var log = [runState.address] log.push(topics) // add data log.push(mem) runState.logs.push(log) }, // '0xf0' range - closures CREATE: function (value, offset, length, runState, done) { value = new BN(value) offset = utils.bufferToInt(offset) length = utils.bufferToInt(length) // set up config var options = { value: value } var localOpts = { inOffset: offset, inLength: length } checkCallMemCost(runState, options, localOpts) makeCall(runState, options, localOpts, done) }, CALL: function (gasLimit, toAddress, value, inOffset, inLength, outOffset, outLength, runState, done) { var stateManager = runState.stateManager gasLimit = new BN(gasLimit) toAddress = utils.pad(toAddress, 20) value = new BN(value) inOffset = utils.bufferToInt(inOffset) inLength = utils.bufferToInt(inLength) outOffset = utils.bufferToInt(outOffset) outLength = utils.bufferToInt(outLength) var data = memLoad(runState, inOffset, inLength) var options = { gasLimit: gasLimit, value: value, to: toAddress, data: data } var localOpts = { inOffset: inOffset, inLength: inLength, outOffset: outOffset, outLength: outLength } // add stipend if (value.cmpn(0) !== 0) { runState.gasLeft.iadd(new BN(fees.callStipend.v)) subGas(runState, new BN(fees.callValueTransferGas.v)) options.gasLimit.iadd(new BN(fees.callStipend.v)) } checkCallMemCost(runState, options, localOpts) stateManager.getAccount(toAddress, function (err, account, exists) { if (err) { done(err) return } if (!exists) { // can't wrap because we are in a callback runState.gasLeft.isub(new BN(fees.callNewAccountGas.v)) } makeCall(runState, options, localOpts, done) }) }, CALLCODE: function (gas, toAddress, value, inOffset, inLength, outOffset, outLength, runState, done) { var stateManager = runState.stateManager gas = new BN(gas) toAddress = utils.pad(toAddress, 20) value = new BN(value) inOffset = utils.bufferToInt(inOffset) inLength = utils.bufferToInt(inLength) outOffset = utils.bufferToInt(outOffset) outLength = utils.bufferToInt(outLength) const options = { gasLimit: gas, value: value, to: runState.address } const localOpts = { inOffset: inOffset, inLength: inLength, outOffset: outOffset, outLength: outLength } // add stipend if (value.cmpn(0) !== 0) { runState.gasLeft.isub(new BN(fees.callValueTransferGas.v)).iadd(new BN(fees.callStipend.v)) options.gasLimit.iadd(new BN(fees.callStipend.v)) } checkCallMemCost(runState, options, localOpts) // load the code stateManager.getAccount(toAddress, function (err, account) { if (err) return done(err) if (account.isPrecompiled(toAddress)) { options.compiled = true options.code = runState._precomiled[toAddress.toString('hex')] makeCall(runState, options, localOpts, done) } else { stateManager.getContractCode(toAddress, function (err, code, compiled) { if (err) return done(err) options.code = code options.compiled = compiled makeCall(runState, options, localOpts, done) }) } }) }, RETURN: function (offset, length, runState) { offset = utils.bufferToInt(offset) length = utils.bufferToInt(length) runState.returnValue = memLoad(runState, offset, length) }, // '0x70', range - other SUICIDE: function (suicideToAddress, runState, cb) { var stateManager = runState.stateManager var contract = runState.contract var contractAddress = runState.address suicideToAddress = utils.pad(suicideToAddress, 20) // only add to refund if this is the first suicide for the address if (!runState.suicides[contractAddress.toString('hex')]) { runState.gasRefund = runState.gasRefund.add(new BN(fees.suicideRefundGas.v)) } runState.suicideTo = suicideToAddress runState.suicides[contractAddress.toString('hex')] = suicideToAddress runState.stopped = true stateManager.getAccount(suicideToAddress, function (err, toAccount) { // update balances if (err) { cb(err) return } var newBalance = Buffer.from(new BN(contract.balance).add(new BN(toAccount.balance)).toArray()) async.series([ stateManager.putAccountBalance.bind(stateManager, suicideToAddress, newBalance), stateManager.putAccountBalance.bind(stateManager, contractAddress, new BN(0)) ], cb) }) } } function subGas (runState, amount) { runState.gasLeft.isub(amount) if (runState.gasLeft.cmpn(0) === -1) { trap(ERROR.OUT_OF_GAS) } } function trap (err) { function VmError (error) { this.error = error } throw new VmError(err) } /** * Subtracts the amount needed for memory usage from `runState.gasLeft` * @method subMemUsage * @param {Number} offset * @param {Number} length * @return {String} */ function subMemUsage (runState, offset, length) { // abort if no usage if (!length) return // hacky: if the dataOffset is larger than the largest safeInt then just // load 0's because if tx.data did have that amount of data then the fee // would be high than the maxGasLimit in the block if (offset > MAX_INT || length > MAX_INT) { trap(ERROR.OUT_OF_GAS) } var newMemoryWordCount = Math.ceil((offset + length) / 32) runState.memoryWordCount = Math.max(newMemoryWordCount, runState.memoryWordCount) var words = new BN(newMemoryWordCount) var fee = new BN(fees.memoryGas.v) var quadCoeff = new BN(fees.quadCoeffDiv.v) var cost = words.mul(fee).add(words.mul(words).div(quadCoeff)) if (cost.cmp(runState.highestMemCost) === 1) { subGas(runState, cost.sub(runState.highestMemCost)) runState.highestMemCost = cost } } /** * Loads bytes from memory and returns them as a buffer. If an error occurs * a string is instead returned. The function also subtracts the amount of * gas need for memory expansion. * @method memLoad * @param {Number} offset where to start reading from * @param {Number} length how far to read * @return {Buffer|String} */ function memLoad (runState, offset, length) { // check to see if we have enougth gas for the mem read subMemUsage(runState, offset, length) var loaded = runState.memory.slice(offset, offset + length) // fill the remaining lenth with zeros for (var i = loaded.length; i < length; i++) { loaded.push(0) } return Buffer.from(loaded) } /** * Stores bytes to memory. If an error occurs a string is instead returned. * The function also subtracts the amount of gas need for memory expansion. * @method memStore * @param {Number} offset where to start reading from * @param {Number} length how far to read * @return {Buffer|String} */ function memStore (runState, offset, val, valOffset, length, skipSubMem) { if (skipSubMem !== false) { subMemUsage(runState, offset, length) } for (var i = 0; i < length; i++) { runState.memory[offset + i] = val[valOffset + i] } } // checks if a jump is valid given a destination function jumpIsValid (runState, dest) { return runState.validJumps.indexOf(dest) !== -1 } // checks to see if we have enough gas left for the memory reads and writes // required by the CALLs function checkCallMemCost (runState, callOptions, localOpts) { // calculates the gase need for reading the input from memory callOptions.data = memLoad(runState, localOpts.inOffset, localOpts.inLength) // calculates the gas need for saving the output in memory if (localOpts.outLength) { subMemUsage(runState, localOpts.outOffset, localOpts.outLength) } if (!callOptions.gasLimit) { callOptions.gasLimit = runState.gasLeft } if (runState.gasLeft.cmp(callOptions.gasLimit) === -1) { trap(ERROR.OUT_OF_GAS) } } // sets up and calls runCall function makeCall (runState, callOptions, localOpts, cb) { callOptions.caller = runState.address callOptions.origin = runState.origin callOptions.gasPrice = runState.gasPrice callOptions.block = runState.block callOptions.populateCache = false callOptions.suicides = runState.suicides // increment the runState.depth callOptions.depth = runState.depth + 1 // check if account has enough vapor if (runState.depth >= fees.stackLimit.v || new BN(runState.contract.balance).cmp(callOptions.value) === -1) { runState.stack.push(Buffer.from([0])) cb() } else { // if creating a new contract then increament the nonce if (!callOptions.to) { runState.contract.nonce = new BN(runState.contract.nonce).addn(1) } runState.stateManager.cache.put(runState.address, runState.contract) runState._vm.runCall(callOptions, parseCallResults) } function parseCallResults (err, results) { // concat the runState.logs if (results.vm.logs) { runState.logs = runState.logs.concat(results.vm.logs) } // add gasRefund if (results.vm.gasRefund) { runState.gasRefund = runState.gasRefund.add(results.vm.gasRefund) } // this should always be safe runState.gasLeft.isub(results.gasUsed) if (!results.vm.exceptionError) { // save results to memory if (results.vm.return) { for (var i = 0; i < Math.min(localOpts.outLength, results.vm.return.length); i++) { runState.memory[localOpts.outOffset + i] = results.vm.return[i] } } // update stateRoot on current contract runState.stateManager.getAccount(runState.address, function (err, account) { runState.contract = account // push the created address to the stack if (results.createdAddress) { cb(err, results.createdAddress) } else { cb(err, Buffer.from([results.vm.exception])) } }) } else { // creation failed so don't increament the nonce if (results.vm.createdAddress) { runState.contract.nonce = new BN(runState.contract.nonce).sub(new BN(1)) } cb(err, Buffer.from([results.vm.exception])) } } } }).call(this,require("buffer").Buffer) },{"./constants.js":5,"./logTable.js":8,"async":29,"buffer":130,"vapory-common":56,"vaporyjs-util":65}],10:[function(require,module,exports){ const codes = { // 0x0 range - arithmetic ops // name, baseCost, off stack, on stack, dynamic 0x00: ['STOP', 0, 0, 0, false], 0x01: ['ADD', 3, 2, 1, false], 0x02: ['MUL', 5, 2, 1, false], 0x03: ['SUB', 3, 2, 1, false], 0x04: ['DIV', 5, 2, 1, false], 0x05: ['SDIV', 5, 2, 1, false], 0x06: ['MOD', 5, 2, 1, false], 0x07: ['SMOD', 5, 2, 1, false], 0x08: ['ADDMOD', 8, 3, 1, false], 0x09: ['MULMOD', 8, 3, 1, false], 0x0a: ['EXP', 10, 2, 1, false], 0x0b: ['SIGNEXTEND', 5, 1, 1, false], // 0x10 range - bit ops 0x10: ['LT', 3, 2, 1, false], 0x11: ['GT', 3, 2, 1, false], 0x12: ['SLT', 3, 2, 1, false], 0x13: ['SGT', 3, 2, 1, false], 0x14: ['EQ', 3, 2, 1, false], 0x15: ['ISZERO', 3, 1, 1, false], 0x16: ['AND', 3, 2, 1, false], 0x17: ['OR', 3, 2, 1, false], 0x18: ['XOR', 3, 2, 1, false], 0x19: ['NOT', 3, 1, 1, false], 0x1a: ['BYTE', 3, 2, 1, false], // 0x20 range - crypto 0x20: ['SHA3', 30, 2, 1, false], // 0x30 range - closure state 0x30: ['ADDRESS', 2, 0, 1, true], 0x31: ['BALANCE', 20, 1, 1, true], 0x32: ['ORIGIN', 2, 0, 1, true], 0x33: ['CALLER', 2, 0, 1, true], 0x34: ['CALLVALUE', 2, 0, 1, true], 0x35: ['CALLDATALOAD', 3, 1, 1, true], 0x36: ['CALLDATASIZE', 2, 0, 1, true], 0x37: ['CALLDATACOPY', 3, 3, 0, true], 0x38: ['CODESIZE', 2, 0, 1, false], 0x39: ['CODECOPY', 3, 3, 0, false], 0x3a: ['GASPRICE', 2, 0, 1, false], 0x3b: ['EXTCODESIZE', 20, 1, 1, true], 0x3c: ['EXTCODECOPY', 20, 4, 0, true], // '0x40' range - block operations 0x40: ['BLOCKHASH', 20, 1, 1, true], 0x41: ['COINBASE', 2, 0, 1, true], 0x42: ['TIMESTAMP', 2, 0, 1, true], 0x43: ['NUMBER', 2, 0, 1, true], 0x44: ['DIFFICULTY', 2, 0, 1, true], 0x45: ['GASLIMIT', 2, 0, 1, true], // 0x50 range - 'storage' and execution 0x50: ['POP', 2, 1, 0, false], 0x51: ['MLOAD', 3, 1, 1, false], 0x52: ['MSTORE', 3, 2, 0, false], 0x53: ['MSTORE8', 3, 2, 0, false], 0x54: ['SLOAD', 50, 1, 1, true], 0x55: ['SSTORE', 0, 2, 0, true], 0x56: ['JUMP', 8, 1, 0, false], 0x57: ['JUMPI', 10, 2, 0, false], 0x58: ['PC', 2, 0, 1, false], 0x59: ['MSIZE', 2, 0, 1, false], 0x5a: ['GAS', 2, 0, 1, false], 0x5b: ['JUMPDEST', 1, 0, 0, false], // 0x60, range 0x60: ['PUSH', 3, 0, 1, false], 0x61: ['PUSH', 3, 0, 1, false], 0x62: ['PUSH', 3, 0, 1, false], 0x63: ['PUSH', 3, 0, 1, false], 0x64: ['PUSH', 3, 0, 1, false], 0x65: ['PUSH', 3, 0, 1, false], 0x66: ['PUSH', 3, 0, 1, false], 0x67: ['PUSH', 3, 0, 1, false], 0x68: ['PUSH', 3, 0, 1, false], 0x69: ['PUSH', 3, 0, 1, false], 0x6a: ['PUSH', 3, 0, 1, false], 0x6b: ['PUSH', 3, 0, 1, false], 0x6c: ['PUSH', 3, 0, 1, false], 0x6d: ['PUSH', 3, 0, 1, false], 0x6e: ['PUSH', 3, 0, 1, false], 0x6f: ['PUSH', 3, 0, 1, false], 0x70: ['PUSH', 3, 0, 1, false], 0x71: ['PUSH', 3, 0, 1, false], 0x72: ['PUSH', 3, 0, 1, false], 0x73: ['PUSH', 3, 0, 1, false], 0x74: ['PUSH', 3, 0, 1, false], 0x75: ['PUSH', 3, 0, 1, false], 0x76: ['PUSH', 3, 0, 1, false], 0x77: ['PUSH', 3, 0, 1, false], 0x78: ['PUSH', 3, 0, 1, false], 0x79: ['PUSH', 3, 0, 1, false], 0x7a: ['PUSH', 3, 0, 1, false], 0x7b: ['PUSH', 3, 0, 1, false], 0x7c: ['PUSH', 3, 0, 1, false], 0x7d: ['PUSH', 3, 0, 1, false], 0x7e: ['PUSH', 3, 0, 1, false], 0x7f: ['PUSH', 3, 0, 1, false], 0x80: ['DUP', 3, 0, 1, false], 0x81: ['DUP', 3, 0, 1, false], 0x82: ['DUP', 3, 0, 1, false], 0x83: ['DUP', 3, 0, 1, false], 0x84: ['DUP', 3, 0, 1, false], 0x85: ['DUP', 3, 0, 1, false], 0x86: ['DUP', 3, 0, 1, false], 0x87: ['DUP', 3, 0, 1, false], 0x88: ['DUP', 3, 0, 1, false], 0x89: ['DUP', 3, 0, 1, false], 0x8a: ['DUP', 3, 0, 1, false], 0x8b: ['DUP', 3, 0, 1, false], 0x8c: ['DUP', 3, 0, 1, false], 0x8d: ['DUP', 3, 0, 1, false], 0x8e: ['DUP', 3, 0, 1, false], 0x8f: ['DUP', 3, 0, 1, false], 0x90: ['SWAP', 3, 0, 0, false], 0x91: ['SWAP', 3, 0, 0, false], 0x92: ['SWAP', 3, 0, 0, false], 0x93: ['SWAP', 3, 0, 0, false], 0x94: ['SWAP', 3, 0, 0, false], 0x95: ['SWAP', 3, 0, 0, false], 0x96: ['SWAP', 3, 0, 0, false], 0x97: ['SWAP', 3, 0, 0, false], 0x98: ['SWAP', 3, 0, 0, false], 0x99: ['SWAP', 3, 0, 0, false], 0x9a: ['SWAP', 3, 0, 0, false], 0x9b: ['SWAP', 3, 0, 0, false], 0x9c: ['SWAP', 3, 0, 0, false], 0x9d: ['SWAP', 3, 0, 0, false], 0x9e: ['SWAP', 3, 0, 0, false], 0x9f: ['SWAP', 3, 0, 0, false], 0xa0: ['LOG', 375, 2, 0, false], 0xa1: ['LOG', 375, 3, 0, false], 0xa2: ['LOG', 375, 4, 0, false], 0xa3: ['LOG', 375, 5, 0, false], 0xa4: ['LOG', 375, 6, 0, false], // '0xf0' range - closures 0xf0: ['CREATE', 32000, 3, 1, true], 0xf1: ['CALL', 40, 7, 1, true], 0xf2: ['CALLCODE', 40, 7, 1, true], 0xf3: ['RETURN', 0, 2, 0, false], // '0x70', range - other 0xff: ['SUICIDE', 0, 1, 0, false] } module.exports = function (op, full) { var code = codes[op] ? codes[op] : ['INVALID', 0] var opcode = code[0] if (full) { if (opcode === 'LOG') { opcode += op - 0xa0 } if (opcode === 'PUSH') { opcode += op - 0x5f } if (opcode === 'DUP') { opcode += op - 0x7f } if (opcode === 'SWAP') { opcode += op - 0x8f } } return {name: opcode, fee: code[1], in: code[2], out: code[3], dynamic: code[4], async: code[5]} } },{}],11:[function(require,module,exports){ (function (Buffer){ const utils = require('vaporyjs-util') const BN = require('bn.js') const fees = require('vapory-common') const ecdsa = require('secp256k1') const gasCost = new BN(fees.ecrecoverGas.v) module.exports = function (opts) { /** * ecrecover * @param {Buffer} msgHash [description] * @param {Buffer} v [description] * @param {Buffer} r [description] * @param {Buffer} s [description] * @return {Buffer} public key otherwise null */ function ecrecover(msgHash, v, r, s) { var sig = Buffer.concat([utils.pad(r, 32), utils.pad(s, 32)], 64) var recid = utils.bufferToInt(v) - 27 var senderPubKey try{ senderPubKey = ecdsa.recover(msgHash, { signature: sig, recovery: recid }, false) }catch(e){} if (senderPubKey && senderPubKey.toString('hex') !== '') { return senderPubKey } else { return null } } var results = {} if (opts.gasLimit.cmp(gasCost) === -1) { results.gasUsed = opts.gasLimit results.exception = 0 // 0 means VM fail (in this case because of OOG) results.exceptionError = 'out of gas' return results } results.gasUsed = gasCost buf = Buffer.from(128) buf.fill(0) data = Buffer.concat([opts.data, buf]) msgHash = data.slice(0, 32) v = data.slice(32, 64) r = data.slice(64, 96) s = data.slice(96, 128) publicKey = ecrecover(msgHash, v, r, s) if (!publicKey) return results results.return = utils.pad(utils.pubToAddress(publicKey), 32) return results } }).call(this,require("buffer").Buffer) },{"bn.js":30,"buffer":130,"vapory-common":56,"vaporyjs-util":65,"secp256k1":122}],12:[function(require,module,exports){ (function (Buffer){ const crypto = require('crypto') const BN = require('bn.js') const error = require('../constants.js').ERROR const fees = require('vapory-common') module.exports = function (opts) { var sha256 = crypto.createHash('SHA256') var data = opts.data var results = {} var gasCost = fees.sha256Gas.v results.gasUsed = gasCost var dataGas = Math.ceil(data.length / 32) * fees.sha256WordGas.v results.gasUsed += dataGas results.gasUsed = new BN(results.gasUsed) if (opts.gasLimit.cmp(new BN(gasCost + dataGas)) === -1) { results.gasUsed = opts.gasLimit results.exceptionError = error.OUT_OF_GAS results.exception = 0 // 0 means VM fail (in this case because of OOG) return results } hashStr = sha256.update(data).digest('hex') results.return = Buffer.from(hashStr, 'hex') results.exception = 1; return results; } }).call(this,require("buffer").Buffer) },{"../constants.js":5,"bn.js":30,"buffer":130,"crypto":134,"vapory-common":56}],13:[function(require,module,exports){ (function (Buffer){ const vapUtil = require('vaporyjs-util') const crypto = require('crypto') const BN = require('bn.js') const error = require('../constants.js').ERROR const fees = require('vapory-common') module.exports = function(opts){ var results = {} var ripemd160 = crypto.createHash('RSA-RIPEMD160') var data = opts.data var gasCost = fees.ripemd160Gas.v if (opts.gasLimit.cmp(new BN(gasCost)) === -1) { results.gasUsed = opts.gasLimit results.exception = 0 // 0 means VM fail (in this case because of OOG) results.exceptionError = error.OUT_OF_GAS return results } results.gasUsed = gasCost var dataGas2 = Math.ceil(opts.data.length / 32) * fees.ripemd160WordGas.v // console.log('data: ' + data.toString('hex')) if (opts.gasLimit.cmp(new BN(gasCost + dataGas2)) === -1) { results.gasUsed = opts.gasLimit results.exceptionError = error.OUT_OF_GAS results.exception = 0 // 0 means VM fail (in this case because of OOG) return results } results.gasUsed += dataGas2 results.gasUsed = new BN(results.gasUsed) hashStr = vapUtil.pad(ripemd160.update(data).digest('bin'), 32) // nb: bin results.exception = 1 results['return'] = Buffer.from(hashStr, 'hex') return results } }).call(this,require("buffer").Buffer) },{"../constants.js":5,"bn.js":30,"buffer":130,"crypto":134,"vapory-common":56,"vaporyjs-util":65}],14:[function(require,module,exports){ const BN = require('bn.js') const fees = require('vapory-common') const error = require('../constants.js').ERROR module.exports = function(opts){ var data = opts.data var results = {} results.gasUsed = new BN(Math.ceil(data.length / 32) * fees.identityWordGas.v + fees.identityGas.v) results.exception = 1 results.return = opts.data if (opts.gasLimit.cmp(new BN(results.gasUsed)) === -1) { results.gasUsed = opts.gasLimit results.exceptionError = error.OUT_OF_GAS results.exception = 0 // 0 means VM fail (in this case because of OOG) return results } return results } },{"../constants.js":5,"bn.js":30,"vapory-common":56}],15:[function(require,module,exports){ (function (Buffer){ const async = require('async') const vapUtil = require('vaporyjs-util') const Bloom = require('./bloom.js') const common = require('vapory-common') const rlp = vapUtil.rlp const Trie = require('@vaporyjs/merkle-patricia-tree') const BN = vapUtil.BN const minerReward = new BN(common.minerReward.v) const niblingReward = new BN(common.niblingReward.v) const ommerReward = new BN(common.ommerReward.v) /** * process the transaction in a block and pays the miners * @param opts * @param opts.block {Block} the block we are processing * @param opts.blockchain {Blockchain} the current blockchain * @param opts.generate {Boolean} [gen=false] whether to generate the stat