ethereumjs-vm
Advanced tools
Comparing version 1.4.1 to 2.0.0
@@ -31,5 +31,3 @@ const inherits = require('util').inherits | ||
function createHookedVm(opts, hooks){ | ||
function createHookedVm (opts, hooks) { | ||
var codeStore = new FallbackAsyncStore(hooks.fetchAccountCode.bind(hooks)) | ||
@@ -45,9 +43,8 @@ | ||
function createAccountStorageTrie(address, cb){ | ||
function createAccountStorageTrie (address, cb) { | ||
var addressHex = ethUtil.addHexPrefix(address.toString('hex')) | ||
var storageTrie = new FallbackStorageTrie({ | ||
fetchStorage: function(key, cb){ | ||
fetchStorage: function (key, cb) { | ||
hooks.fetchAccountStorage(addressHex, key, cb) | ||
}, | ||
} | ||
}) | ||
@@ -57,15 +54,15 @@ cb(null, storageTrie) | ||
function loadAccount(address, cb){ | ||
function loadAccount (address, cb) { | ||
var addressHex = ethUtil.addHexPrefix(address.toString('hex')) | ||
async.parallel({ | ||
nonce: hooks.fetchAccountNonce.bind(hooks, addressHex), | ||
balance: hooks.fetchAccountBalance.bind(hooks, addressHex), | ||
}, function(err, results){ | ||
balance: hooks.fetchAccountBalance.bind(hooks, addressHex) | ||
}, function (err, results) { | ||
if (err) return cb(err) | ||
results._exists = results.nonce !== '0x0' || results.balance != '0x0' || results._code != '0x' | ||
// console.log('fetch account results:', results) | ||
results._exists = results.nonce !== '0x0' || results.balance !== '0x0' || results._code !== '0x' | ||
// console.log('fetch account results:', results) | ||
var account = new Account(results) | ||
// not used but needs to be anything but the default (ethUtil.SHA3_NULL) | ||
// code lookups are handled by `codeStore` | ||
// not used but needs to be anything but the default (ethUtil.SHA3_NULL) | ||
// code lookups are handled by `codeStore` | ||
account.codeHash = ZERO_BUFFER.slice() | ||
@@ -75,3 +72,2 @@ cb(null, account) | ||
} | ||
} | ||
@@ -86,12 +82,12 @@ | ||
function fromWeb3Provider(provider, blockNumber, opts){ | ||
function fromWeb3Provider (provider, blockNumber, opts) { | ||
return createHookedVm(opts, { | ||
fetchAccountBalance: createRpcFunction(provider, 'eth_getBalance', blockNumber), | ||
fetchAccountNonce: createRpcFunction(provider, 'eth_getTransactionCount', blockNumber), | ||
fetchAccountCode: createRpcFunction(provider, 'eth_getCode', blockNumber), | ||
fetchAccountStorage: createRpcFunction(provider, 'eth_getStorageAt', blockNumber), | ||
fetchAccountNonce: createRpcFunction(provider, 'eth_getTransactionCount', blockNumber), | ||
fetchAccountCode: createRpcFunction(provider, 'eth_getCode', blockNumber), | ||
fetchAccountStorage: createRpcFunction(provider, 'eth_getStorageAt', blockNumber) | ||
}) | ||
function createRpcFunction(provider, method, blockNumber){ | ||
return function sendRpcRequest(){ | ||
function createRpcFunction (provider, method, blockNumber) { | ||
return function sendRpcRequest () { | ||
// prepare arguments | ||
@@ -101,8 +97,8 @@ var args = [].slice.call(arguments) | ||
args.push(blockNumber) | ||
// send rpc payload | ||
// send rpc payload | ||
provider.sendAsync({ | ||
id: 1, | ||
method: method, | ||
params: args, | ||
}, function(err, res){ | ||
params: args | ||
}, function (err, res) { | ||
if (err) return cb(err) | ||
@@ -125,3 +121,3 @@ cb(null, res.result) | ||
function FallbackStorageTrie(opts) { | ||
function FallbackStorageTrie (opts) { | ||
const self = this | ||
@@ -132,12 +128,12 @@ FakeMerklePatriciaTree.call(self) | ||
FallbackStorageTrie.prototype.get = function(key, cb){ | ||
FallbackStorageTrie.prototype.get = function (key, cb) { | ||
const self = this | ||
var _super = FakeMerklePatriciaTree.prototype.get.bind(self) | ||
_super(key, function(err, value){ | ||
_super(key, function (err, value) { | ||
if (err) return cb(err) | ||
if (value) return cb(null, value) | ||
// if value not in tree, try network | ||
// if value not in tree, try network | ||
var keyHex = key.toString('hex') | ||
self._fetchStorage(keyHex, function(err, rawValue){ | ||
self._fetchStorage(keyHex, function (err, rawValue) { | ||
if (err) return cb(err) | ||
@@ -159,3 +155,3 @@ var value = ethUtil.toBuffer(rawValue) | ||
function FallbackAsyncStore(fetchFn){ | ||
function FallbackAsyncStore (fetchFn) { | ||
// console.log('FallbackAsyncStore - new') | ||
@@ -167,6 +163,6 @@ const self = this | ||
FallbackAsyncStore.prototype.get = function(address, cb){ | ||
FallbackAsyncStore.prototype.get = function (address, cb) { | ||
// console.log('FallbackAsyncStore - get', arguments) | ||
const self = this | ||
var addressHex = '0x'+address.toString('hex') | ||
var addressHex = '0x' + address.toString('hex') | ||
var code = self.cache[addressHex] | ||
@@ -177,6 +173,6 @@ if (code !== undefined) { | ||
// console.log('FallbackAsyncStore - fetch init') | ||
self.fetch(addressHex, function(err, value){ | ||
self.fetch(addressHex, function (err, value) { | ||
// console.log('FallbackAsyncStore - fetch return', arguments) | ||
if (err) return cb(err) | ||
value = ethUtil.toBuffer(value); | ||
value = ethUtil.toBuffer(value) | ||
self.cache[addressHex] = value | ||
@@ -188,8 +184,8 @@ cb(null, value) | ||
FallbackAsyncStore.prototype.set = function(address, code, cb){ | ||
FallbackAsyncStore.prototype.set = function (address, code, cb) { | ||
// console.log('FallbackAsyncStore - set', arguments) | ||
const self = this | ||
var addressHex = '0x'+address.toString('hex') | ||
var addressHex = '0x' + address.toString('hex') | ||
self.cache[addressHex] = code | ||
cb() | ||
} | ||
} |
@@ -23,12 +23,12 @@ const util = require('util') | ||
* @constructor | ||
* @param {Trie} [trie] A merkle-patricia-tree instance for the state tree | ||
* @param {Blockchain} [blockchain] A blockchain object for storing/retrieving blocks | ||
* @param {Object} [opts] | ||
* @param {Trie} [opts.state] A merkle-patricia-tree instance for the state tree | ||
* @param {Blockchain} [opts.blockchain] A blockchain object for storing/retrieving blocks | ||
* @param {Boolean} [opts.activatePrecompiles] Create entries in the state tree for the precompiled contracts | ||
* @param {Boolean} [opts.enableHomestead] Force enable Homestead irrelevant to block number | ||
*/ | ||
function VM (trie, blockchain, opts) { | ||
function VM (opts = {}) { | ||
this.stateManager = new StateManager({ | ||
trie: trie, | ||
blockchain: blockchain | ||
trie: opts.state, | ||
blockchain: opts.blockchain | ||
}) | ||
@@ -51,3 +51,3 @@ | ||
for (var i = 1; i <= 4; i++) { | ||
this.trie.put(new Buffer('000000000000000000000000000000000000000' + i, 'hex'), new Account().serialize()); | ||
this.trie.put(new Buffer('000000000000000000000000000000000000000' + i, 'hex'), new Account().serialize()) | ||
} | ||
@@ -54,0 +54,0 @@ } |
@@ -432,3 +432,3 @@ const async = require('async') | ||
if (!jumpIsValid(runState, dest)) { | ||
trap(ERROR.INVALID_JUMP) | ||
trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) | ||
} | ||
@@ -445,3 +445,3 @@ | ||
if (i && !jumpIsValid(runState, dest)) { | ||
trap(ERROR.INVALID_JUMP) | ||
trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) | ||
} | ||
@@ -462,4 +462,4 @@ | ||
PUSH: function (runState) { | ||
var numToPush = runState.opCode - 0x5f | ||
var loaded = utils.unpad(runState.code.slice(runState.programCounter, runState.programCounter + numToPush)) | ||
const numToPush = runState.opCode - 0x5f | ||
const loaded = utils.unpad(runState.code.slice(runState.programCounter, runState.programCounter + numToPush)) | ||
runState.programCounter += numToPush | ||
@@ -470,7 +470,5 @@ return loaded | ||
const stackPos = runState.opCode - 0x7f | ||
if (stackPos > runState.stack.length) { | ||
trap(ERROR.STACK_UNDERFLOW) | ||
} | ||
// dupilcated stack items point to the same Buffer | ||
@@ -707,2 +705,9 @@ return runState.stack[runState.stack.length - stackPos] | ||
function describeLocation (runState) { | ||
var hash = utils.sha3(runState.code).toString('hex') | ||
var address = runState.address.toString('hex') | ||
var pc = runState.programCounter - 1 | ||
return hash + '/' + address + ':' + pc | ||
} | ||
function subGas (runState, amount) { | ||
@@ -740,9 +745,13 @@ runState.gasLeft.isub(amount) | ||
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)) | ||
const newMemoryWordCount = Math.ceil((offset + length) / 32) | ||
if (newMemoryWordCount <= runState.memoryWordCount) return | ||
runState.memoryWordCount = newMemoryWordCount | ||
const words = new BN(newMemoryWordCount) | ||
const fee = new BN(fees.memoryGas.v) | ||
const quadCoeff = new BN(fees.quadCoeffDiv.v) | ||
// words * 3 + words ^2 / 512 | ||
const cost = words.mul(fee).add(words.mul(words).div(quadCoeff)) | ||
if (cost.cmp(runState.highestMemCost) === 1) { | ||
@@ -749,0 +758,0 @@ subGas(runState, cost.sub(runState.highestMemCost)) |
{ | ||
"name": "ethereumjs-vm", | ||
"version": "1.4.1", | ||
"version": "2.0.0", | ||
"description": "an ethereum VM implementation", | ||
@@ -22,4 +22,4 @@ "main": "index.js", | ||
"level": "^1.4.0", | ||
"leveldown": "^1.4.2", | ||
"levelup": "^1.3.0", | ||
"leveldown": "^1.4.6", | ||
"levelup": "^1.3.2", | ||
"memdown": "^1.1.0", | ||
@@ -26,0 +26,0 @@ "minimist": "^1.1.1", |
# SYNOPSIS | ||
[![NPM Package](https://img.shields.io/npm/v/ethereumjs-vm.svg?style=flat-square)](https://www.npmjs.org/package/ethereumjs-vm) | ||
@@ -38,3 +39,3 @@ [![Build Status](https://img.shields.io/travis/ethereumjs/ethereumjs-vm.svg?branch=master&style=flat-square)](https://travis-ci.org/ethereumjs/ethereumjs-vm) | ||
# API | ||
- [`new VM([StateTrie], [blockchain], [opts])`](#new-vmstatetrie-blockchain) | ||
- [`new VM([opts])`](#new-vmstatetrie-blockchain) | ||
- [`VM` methods](#vm-methods) | ||
@@ -55,2 +56,4 @@ - [`vm.runBlockchain([blockchain], [cb])`](#vmrunblockchainblockchain-cb) | ||
- `opts` | ||
- `state` - the state trie | ||
- `blockchain` - an instance of ethereumjs-blockchain | ||
- `enableHomestead` - a boolean that overrides the homestead settings based on blocknumber | ||
@@ -57,0 +60,0 @@ - `activatePrecompiles` - create entries in the state tree for the precompiled contracts |
@@ -19,3 +19,6 @@ const async = require('async') | ||
blockchain.ethash.cacheDB = cacheDB | ||
var vm = new VM(state, blockchain) | ||
var vm = new VM({ | ||
state: state, | ||
blockchain: blockchain | ||
}) | ||
var genesisBlock = new Block() | ||
@@ -22,0 +25,0 @@ |
const tape = require('tape') | ||
const createHookedVm = require('../lib/hooked') | ||
tape('hooked-vm', function(test){ | ||
tape('hooked-vm', function (test) { | ||
var contractAddressHex = '0x1234000000000000000000000000000000001234' | ||
@@ -11,15 +10,15 @@ var contractAddress = new Buffer(contractAddressHex.slice(2), 'hex') | ||
var contractCode = new Buffer([ | ||
0x30, // ADDRESS of contract being run | ||
0x31, // BALANCE of address on stack | ||
0x30, // ADDRESS of contract being run | ||
0x31, // BALANCE of address on stack | ||
// return the last thing on the stack | ||
0x60, //PUSH1 | ||
0x60, //(data1) <-- MSTORE offset top| [prev] | ||
0x90, //SWAP1 top| [prev, data1] | ||
0x81, //DUP2 top| [data1, prev, data1] | ||
0x52, //MSTORE (offset:data1, word:prev) top| [data1] -> offset:data1, word:prev | ||
0x60, //PUSH1 | ||
0x20, //(data2) <-- RETURN length top| [data2, data1] | ||
0x90, //SWAP1 top| [data1, data2] | ||
0xf3, //RETURN (offset:data1, length:data2) top| [] -> offset:data1, length:data2 | ||
0x60, // PUSH1 | ||
0x60, // (data1) <-- MSTORE offset top| [prev] | ||
0x90, // SWAP1 top| [prev, data1] | ||
0x81, // DUP2 top| [data1, prev, data1] | ||
0x52, // MSTORE (offset:data1, word:prev) top| [data1] -> offset:data1, word:prev | ||
0x60, // PUSH | ||
0x20, // (data2) <-- RETURN length top| [data2, data1] | ||
0x90, // SWAP1 top| [data1, data2] | ||
0xf3 // RETURN (offset:data1, length:data2) top| [] -> offset:data1, length:data2 | ||
]) | ||
@@ -31,4 +30,4 @@ | ||
nonce: '0x00', | ||
code: '0x'+contractCode.toString('hex'), | ||
storage: {}, | ||
code: '0x' + contractCode.toString('hex'), | ||
storage: {} | ||
} | ||
@@ -38,3 +37,3 @@ } | ||
var vm = createHookedVm({ | ||
enableHomestead: true, | ||
enableHomestead: true | ||
}, hooksForBlockchainState(blockchainState)) | ||
@@ -47,45 +46,42 @@ | ||
// }) | ||
vm.runCode({ | ||
code: contractCode, | ||
address: contractAddress, | ||
gasLimit: new Buffer('ffffffffff'), | ||
}, function(err, results){ | ||
gasLimit: new Buffer('ffffffffff') | ||
}, function (err, results) { | ||
// console.log(arguments) | ||
test.ifError(err, 'Should run code without error') | ||
test.ifError(results.exceptionError, 'Should run code without vm error') | ||
test.equal('0x'+results.return.toString('hex'), contractBalanceHex, 'Should return correct balance of contract') | ||
test.equal('0x' + results.return.toString('hex'), contractBalanceHex, 'Should return correct balance of contract') | ||
test.end() | ||
}) | ||
}) | ||
function hooksForBlockchainState(blockchainState){ | ||
function hooksForBlockchainState (blockchainState) { | ||
return { | ||
fetchAccountBalance: function(addressHex, cb){ | ||
fetchAccountBalance: function (addressHex, cb) { | ||
var value = blockchainState[addressHex].balance | ||
// console.log('fetchAccountBalance', addressHex, '->', value) | ||
// console.log('fetchAccountBalance', addressHex, '->', value) | ||
cb(null, value) | ||
}, | ||
fetchAccountNonce: function(addressHex, cb){ | ||
fetchAccountNonce: function (addressHex, cb) { | ||
var value = blockchainState[addressHex].nonce | ||
// console.log('fetchAccountNonce', addressHex, '->', value) | ||
// console.log('fetchAccountNonce', addressHex, '->', value) | ||
cb(null, value) | ||
}, | ||
fetchAccountCode: function(addressHex, cb){ | ||
fetchAccountCode: function (addressHex, cb) { | ||
var value = blockchainState[addressHex].code | ||
// console.log('fetchAccountCode', addressHex, '->', value) | ||
// console.log('fetchAccountCode', addressHex, '->', value) | ||
cb(null, value) | ||
}, | ||
fetchAccountStorage: function(addressHex, keyHex, cb){ | ||
var value = blockchainState[addressHex].storage[key] | ||
// console.log('fetchAccountStorage', addressHex, keyHex, '->', value) | ||
fetchAccountStorage: function (addressHex, keyHex, cb) { | ||
var value = blockchainState[addressHex].storage[keyHex] | ||
// console.log('fetchAccountStorage', addressHex, keyHex, '->', value) | ||
cb(null, value) | ||
}, | ||
} | ||
} | ||
} | ||
} |
@@ -8,9 +8,8 @@ const async = require('async') | ||
module.exports = function runStateTest (options, testData, t, cb) { | ||
var state = new Trie() | ||
var block, vm, result | ||
const state = new Trie() | ||
let block, vm, result | ||
async.series([ | ||
function (done) { | ||
vm = new VM(state) | ||
vm = new VM({state: state}) | ||
testUtil.setupPreConditions(state, testData, done) | ||
@@ -17,0 +16,0 @@ }, |
@@ -10,10 +10,9 @@ const async = require('async') | ||
module.exports = function runStateTest (options, testData, t, cb) { | ||
var sstream = false | ||
var state = new Trie() | ||
var results | ||
var account | ||
let state = new Trie() | ||
let results | ||
let account | ||
async.series([ | ||
function (done) { | ||
var acctData = testData.pre[testData.exec.address] | ||
let acctData = testData.pre[testData.exec.address] | ||
account = new Account() | ||
@@ -26,3 +25,3 @@ account.nonce = testUtil.format(acctData.nonce) | ||
state.get(new Buffer(testData.exec.address, 'hex'), function (err, data) { | ||
var a = new Account(data) | ||
let a = new Account(data) | ||
account.stateRoot = a.stateRoot | ||
@@ -34,8 +33,13 @@ // console.log(account.toJSON(true)) | ||
function (done) { | ||
var block = testUtil.makeBlockFromEnv(testData.env) | ||
var vm = new VM(state) | ||
var runCodeData = testUtil.makeRunCodeData(testData.exec, account, block) | ||
let block = testUtil.makeBlockFromEnv(testData.env) | ||
let vm = new VM({state: state}) | ||
let runCodeData = testUtil.makeRunCodeData(testData.exec, account, block) | ||
if (options.vmtrace) { | ||
sstream = testUtil.enableVMtracing(vm, options.vmtrace) | ||
vm.on('step', (op) => { | ||
const string = `${op.opcode.name} ${op.gasLeft.toString()}` | ||
console.log(string) | ||
op.stack.forEach((item) => { | ||
console.log(item.toString('hex')) | ||
}) | ||
}) | ||
} | ||
@@ -51,4 +55,4 @@ | ||
function (done) { | ||
if (sstream) { | ||
sstream.push(null) | ||
if (options.vmtrace) { | ||
console.log(results.runState.gasLeft.toString()) | ||
} | ||
@@ -55,0 +59,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
1415821
46
43652
209
1