vaporyjs-vm
Version:
an vapory VM implementation
1,714 lines (1,514 loc) • 1.25 MB
JavaScript
(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