ethereumjs-vm
Advanced tools
Comparing version 2.5.1 to 2.6.0
@@ -9,2 +9,51 @@ # Changelog | ||
## [2.6.0] - 2019-02-07 | ||
**Petersburg Support** | ||
Support for the `Petersburg` (aka `constantinopleFix`) hardfork by integrating | ||
`Petersburg` ready versions of associated libraries, see also | ||
PR [#433](https://github.com/ethereumjs/ethereumjs-vm/pull/433): | ||
- `ethereumjs-common` (chain and HF logic and helper functionality) [v1.1.0](https://github.com/ethereumjs/ethereumjs-common/releases/tag/v1.1.0) | ||
- `ethereumjs-blockchain` [v3.4.0](https://github.com/ethereumjs/ethereumjs-blockchain/releases/tag/v3.4.0) | ||
- `ethereumjs-block` [v2.2.0](https://github.com/ethereumjs/ethereumjs-block/releases) | ||
To instantiate the VM with `Petersburg` HF rules set the `opts.hardfork` | ||
constructor parameter to `petersburg`. This will run the VM on the new | ||
Petersburg rules having removed the support for | ||
[EIP 1283](https://eips.ethereum.org/EIPS/eip-1283). | ||
**Goerli Readiness** | ||
The VM is now also ready to execute on blocks from the final version of the | ||
[Goerli](https://github.com/goerli/testnet) cross-client testnet and can | ||
therefore be instantiated with `opts.chain` set to `goerli`. | ||
**Bug Fixes** | ||
- Fixed mixed `sync`/`async` functions in `cache`, | ||
PR [#422](https://github.com/ethereumjs/ethereumjs-vm/pull/422) | ||
- Fixed a bug in `setStateroot` and caching by clearing the `stateManager` cache | ||
after setting the state root such that stale values are not returned, | ||
PR [#420](https://github.com/ethereumjs/ethereumjs-vm/pull/420) | ||
- Fixed cache access on the hooked VM (*deprecated*), | ||
PR [#434](https://github.com/ethereumjs/ethereumjs-vm/pull/434) | ||
**Refactoring** | ||
Following changes might be relevant for you if you are hotfixing/monkey-patching | ||
on parts of the VM: | ||
- Moved `bloom` to its own directory, | ||
PR [#429](https://github.com/ethereumjs/ethereumjs-vm/pull/429) | ||
- Moved `opcodes`, `opFns` and `logTable` to `lib/vm`, | ||
PR [#425](https://github.com/ethereumjs/ethereumjs-vm/pull/425) | ||
- Converted `Bloom` to `ES6` class, | ||
PR [#428](https://github.com/ethereumjs/ethereumjs-vm/pull/428) | ||
- Converted `Cache` to `ES6` class, added unit tests, | ||
PR [427](https://github.com/ethereumjs/ethereumjs-vm/pull/427) | ||
[2.6.0]: https://github.com/ethereumjs/ethereumjs-vm/compare/v2.5.1...v2.6.0 | ||
## [2.5.1] - 2019-01-19 | ||
@@ -11,0 +60,0 @@ |
'use strict'; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var Buffer = require('safe-buffer').Buffer; | ||
@@ -8,142 +12,242 @@ var Tree = require('functional-red-black-tree'); | ||
var Cache = module.exports = function (trie) { | ||
this._cache = Tree(); | ||
this._checkpoints = []; | ||
this._trie = trie; | ||
}; | ||
module.exports = function () { | ||
function Cache(trie) { | ||
_classCallCheck(this, Cache); | ||
Cache.prototype.put = function (key, val, fromTrie) { | ||
var modified = !fromTrie; | ||
this._update(key, val, modified, false); | ||
}; | ||
// returns the queried account or an empty account | ||
Cache.prototype.get = function (key) { | ||
var account = this.lookup(key); | ||
if (!account) { | ||
account = new Account(); | ||
this._cache = Tree(); | ||
this._checkpoints = []; | ||
this._trie = trie; | ||
} | ||
return account; | ||
}; | ||
// returns the queried account or undefined | ||
Cache.prototype.lookup = function (key) { | ||
key = key.toString('hex'); | ||
/** | ||
* Puts account to cache under its address. | ||
* @param {Buffer} key - Address of account | ||
* @param {Account} val - Account | ||
* @param {bool} [fromTrie] | ||
*/ | ||
var it = this._cache.find(key); | ||
if (it.node) { | ||
var account = new Account(it.value.val); | ||
return account; | ||
} | ||
}; | ||
Cache.prototype._lookupAccount = function (address, cb) { | ||
var self = this; | ||
self._trie.get(address, function (err, raw) { | ||
if (err) return cb(err); | ||
var account = new Account(raw); | ||
cb(null, account); | ||
}); | ||
}; | ||
_createClass(Cache, [{ | ||
key: 'put', | ||
value: function put(key, val) { | ||
var fromTrie = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
Cache.prototype.getOrLoad = function (key, cb) { | ||
var self = this; | ||
var account = this.lookup(key); | ||
if (account) { | ||
cb(null, account); | ||
} else { | ||
self._lookupAccount(key, function (err, account) { | ||
if (err) return cb(err); | ||
self._update(key, account, false, false); | ||
cb(null, account); | ||
}); | ||
} | ||
}; | ||
var modified = !fromTrie; | ||
this._update(key, val, modified, false); | ||
} | ||
Cache.prototype.warm = function (addresses, cb) { | ||
var self = this; | ||
// shim till async supports iterators | ||
var accountArr = []; | ||
addresses.forEach(function (val) { | ||
if (val) accountArr.push(val); | ||
}); | ||
/** | ||
* Returns the queried account or an empty account. | ||
* @param {Buffer} key - Address of account | ||
*/ | ||
async.eachSeries(accountArr, function (addressHex, done) { | ||
var address = Buffer.from(addressHex, 'hex'); | ||
self._lookupAccount(address, function (err, account) { | ||
if (err) return done(err); | ||
self._update(address, account, false, false); | ||
done(); | ||
}); | ||
}, cb); | ||
}; | ||
}, { | ||
key: 'get', | ||
value: function get(key) { | ||
var account = this.lookup(key); | ||
if (!account) { | ||
account = new Account(); | ||
} | ||
return account; | ||
} | ||
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 && 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(); | ||
/** | ||
* Returns the queried account or undefined. | ||
* @param {buffer} key - Address of account | ||
*/ | ||
}, { | ||
key: 'lookup', | ||
value: function lookup(key) { | ||
key = key.toString('hex'); | ||
var it = this._cache.find(key); | ||
if (it.node) { | ||
var account = new Account(it.value.val); | ||
return account; | ||
} | ||
} | ||
/** | ||
* Looks up address in underlying trie. | ||
* @param {Buffer} address - Address of account | ||
* @param {Function} cb - Callback with params (err, account) | ||
*/ | ||
}, { | ||
key: '_lookupAccount', | ||
value: function _lookupAccount(address, cb) { | ||
this._trie.get(address, function (err, raw) { | ||
if (err) return cb(err); | ||
var account = new Account(raw); | ||
cb(null, account); | ||
}); | ||
} else if (it.value && it.value.deleted) { | ||
it.value.modified = false; | ||
it.value.deleted = false; | ||
it.value.val = new Account().serialize(); | ||
self._trie.del(Buffer.from(it.key, 'hex'), function () { | ||
next = it.hasNext; | ||
it.next(); | ||
done(); | ||
} | ||
/** | ||
* Looks up address in cache, if not found, looks it up | ||
* in the underlying trie. | ||
* @param {Buffer} key - Address of account | ||
* @param {Function} cb - Callback with params (err, account) | ||
*/ | ||
}, { | ||
key: 'getOrLoad', | ||
value: function getOrLoad(key, cb) { | ||
var _this = this; | ||
var account = this.lookup(key); | ||
if (account) { | ||
async.nextTick(cb, null, account); | ||
} else { | ||
this._lookupAccount(key, function (err, account) { | ||
if (err) return cb(err); | ||
_this._update(key, account, false, false); | ||
cb(null, account); | ||
}); | ||
} | ||
} | ||
/** | ||
* Warms cache by loading their respective account from trie | ||
* and putting them in cache. | ||
* @param {Array} addresses - Array of addresses | ||
* @param {Function} cb - Callback | ||
*/ | ||
}, { | ||
key: 'warm', | ||
value: function warm(addresses, cb) { | ||
var _this2 = this; | ||
// shim till async supports iterators | ||
var accountArr = []; | ||
addresses.forEach(function (val) { | ||
if (val) accountArr.push(val); | ||
}); | ||
} else { | ||
next = it.hasNext; | ||
it.next(); | ||
done(); | ||
async.eachSeries(accountArr, function (addressHex, done) { | ||
var address = Buffer.from(addressHex, 'hex'); | ||
_this2._lookupAccount(address, function (err, account) { | ||
if (err) return done(err); | ||
_this2._update(address, account, false, false); | ||
done(); | ||
}); | ||
}, cb); | ||
} | ||
}, cb); | ||
}; | ||
Cache.prototype.checkpoint = function () { | ||
this._checkpoints.push(this._cache); | ||
}; | ||
/** | ||
* Flushes cache by updating accounts that have been modified | ||
* and removing accounts that have been deleted. | ||
* @param {function} cb - Callback | ||
*/ | ||
Cache.prototype.revert = function () { | ||
this._cache = this._checkpoints.pop(this._cache); | ||
}; | ||
}, { | ||
key: 'flush', | ||
value: function flush(cb) { | ||
var _this3 = this; | ||
Cache.prototype.commit = function () { | ||
this._checkpoints.pop(); | ||
}; | ||
var it = this._cache.begin; | ||
var next = true; | ||
async.whilst(function () { | ||
return next; | ||
}, function (done) { | ||
if (it.value && it.value.modified) { | ||
it.value.modified = false; | ||
it.value.val = it.value.val.serialize(); | ||
_this3._trie.put(Buffer.from(it.key, 'hex'), it.value.val, function () { | ||
next = it.hasNext; | ||
it.next(); | ||
done(); | ||
}); | ||
} else if (it.value && it.value.deleted) { | ||
it.value.modified = false; | ||
it.value.deleted = false; | ||
it.value.val = new Account().serialize(); | ||
_this3._trie.del(Buffer.from(it.key, 'hex'), function () { | ||
next = it.hasNext; | ||
it.next(); | ||
done(); | ||
}); | ||
} else { | ||
next = it.hasNext; | ||
it.next(); | ||
async.nextTick(done); | ||
} | ||
}, cb); | ||
} | ||
Cache.prototype.clear = function () { | ||
this._cache = Tree(); | ||
}; | ||
/** | ||
* Marks current state of cache as checkpoint, which can | ||
* later on be reverted or commited. | ||
*/ | ||
Cache.prototype.del = function (key) { | ||
this._update(key, new Account(), false, true); | ||
}; | ||
}, { | ||
key: 'checkpoint', | ||
value: function checkpoint() { | ||
this._checkpoints.push(this._cache); | ||
} | ||
Cache.prototype._update = function (key, val, modified, deleted) { | ||
key = key.toString('hex'); | ||
var it = this._cache.find(key); | ||
if (it.node) { | ||
this._cache = it.update({ | ||
val: val, | ||
modified: modified, | ||
deleted: deleted | ||
}); | ||
} else { | ||
this._cache = this._cache.insert(key, { | ||
val: val, | ||
modified: modified, | ||
deleted: deleted | ||
}); | ||
} | ||
}; | ||
/** | ||
* Revert changes to cache last checkpoint (no effect on trie). | ||
*/ | ||
}, { | ||
key: 'revert', | ||
value: function revert() { | ||
this._cache = this._checkpoints.pop(); | ||
} | ||
/** | ||
* Commits to current state of cache (no effect on trie). | ||
*/ | ||
}, { | ||
key: 'commit', | ||
value: function commit() { | ||
this._checkpoints.pop(); | ||
} | ||
/** | ||
* Clears cache. | ||
*/ | ||
}, { | ||
key: 'clear', | ||
value: function clear() { | ||
this._cache = Tree(); | ||
} | ||
/** | ||
* Marks address as deleted in cache. | ||
* @params {Buffer} key - Address | ||
*/ | ||
}, { | ||
key: 'del', | ||
value: function del(key) { | ||
this._update(key, new Account(), false, true); | ||
} | ||
}, { | ||
key: '_update', | ||
value: function _update(key, val, modified, deleted) { | ||
key = key.toString('hex'); | ||
var it = this._cache.find(key); | ||
if (it.node) { | ||
this._cache = it.update({ | ||
val: val, | ||
modified: modified, | ||
deleted: deleted | ||
}); | ||
} else { | ||
this._cache = this._cache.insert(key, { | ||
val: val, | ||
modified: modified, | ||
deleted: deleted | ||
}); | ||
} | ||
} | ||
}]); | ||
return Cache; | ||
}(); |
@@ -37,3 +37,3 @@ 'use strict'; | ||
vm.stateManager._lookupStorageTrie = createAccountStorageTrie; | ||
vm.stateManager.cache._lookupAccount = loadAccount; | ||
vm.stateManager._cache._lookupAccount = loadAccount; | ||
vm.stateManager.getContractCode = codeStore.get.bind(codeStore); | ||
@@ -40,0 +40,0 @@ vm.stateManager.setContractCode = codeStore.set.bind(codeStore); |
@@ -7,3 +7,3 @@ 'use strict'; | ||
var StateManager = require('./stateManager.js'); | ||
var Common = require('ethereumjs-common'); | ||
var Common = require('ethereumjs-common').default; | ||
var Account = require('ethereumjs-account'); | ||
@@ -41,3 +41,3 @@ var AsyncEventEmitter = require('async-eventemitter'); | ||
* @param {String|Number} opts.chain the chain the VM operates on [default: 'mainnet'] | ||
* @param {String} opts.hardfork hardfork rules to be used [default: 'byzantium', supported: 'byzantium', 'constantinople' (will throw on unsupported)] | ||
* @param {String} opts.hardfork hardfork rules to be used [default: 'byzantium', supported: 'byzantium', 'constantinople', 'petersburg' (will throw on unsupported)] | ||
* @param {Boolean} opts.activatePrecompiles create entries in the state tree for the precompiled contracts | ||
@@ -54,3 +54,3 @@ * @param {Boolean} opts.allowUnlimitedContractSize allows unlimited contract sizes while debugging. By setting this to `true`, the check for contract size limit of 24KB (see [EIP-170](https://git.io/vxZkK)) is bypassed. (default: `false`; ONLY set to `true` during debugging) | ||
var hardfork = opts.hardfork ? opts.hardfork : 'byzantium'; | ||
var supportedHardforks = ['byzantium', 'constantinople']; | ||
var supportedHardforks = ['byzantium', 'constantinople', 'petersburg']; | ||
this._common = new Common(chain, hardfork, supportedHardforks); | ||
@@ -57,0 +57,0 @@ |
@@ -6,3 +6,3 @@ 'use strict'; | ||
var ethUtil = require('ethereumjs-util'); | ||
var Bloom = require('./bloom.js'); | ||
var Bloom = require('./bloom'); | ||
var rlp = ethUtil.rlp; | ||
@@ -9,0 +9,0 @@ var Trie = require('merkle-patricia-tree'); |
@@ -20,4 +20,4 @@ 'use strict'; | ||
var Block = require('ethereumjs-block'); | ||
var lookupOpInfo = require('./opcodes.js'); | ||
var opFns = require('./opFns.js'); | ||
var lookupOpInfo = require('./vm/opcodes.js'); | ||
var opFns = require('./vm/opFns.js'); | ||
var exceptions = require('./exceptions.js'); | ||
@@ -24,0 +24,0 @@ var StorageReader = require('./storageReader'); |
@@ -7,3 +7,3 @@ 'use strict'; | ||
var BN = utils.BN; | ||
var Bloom = require('./bloom.js'); | ||
var Bloom = require('./bloom'); | ||
var Block = require('ethereumjs-block'); | ||
@@ -10,0 +10,0 @@ var Account = require('ethereumjs-account'); |
@@ -7,4 +7,7 @@ 'use strict'; | ||
var Trie = require('merkle-patricia-tree/secure.js'); | ||
var Common = require('ethereumjs-common'); | ||
var genesisStates = require('ethereumjs-common/genesisStates'); | ||
var Common = require('ethereumjs-common').default; | ||
var _require = require('ethereumjs-common/dist/genesisStates'), | ||
genesisStateByName = _require.genesisStateByName; | ||
var async = require('async'); | ||
@@ -410,2 +413,7 @@ var Account = require('ethereumjs-account'); | ||
} | ||
if (stateRoot === self._trie.EMPTY_TRIE_ROOT) { | ||
self._trie.root = stateRoot; | ||
self._cache.clear(); | ||
return cb(); | ||
} | ||
self._trie.checkRoot(stateRoot, function (err, hasRoot) { | ||
@@ -416,2 +424,3 @@ if (err || !hasRoot) { | ||
self._trie.root = stateRoot; | ||
self._cache.clear(); | ||
cb(); | ||
@@ -493,3 +502,3 @@ } | ||
if (!genesis && !err) { | ||
self.generateGenesis(genesisStates[self._common.chainName()], cb); | ||
self.generateGenesis(genesisStateByName(self._common.chainName()), cb); | ||
} else { | ||
@@ -496,0 +505,0 @@ cb(err); |
{ | ||
"name": "ethereumjs-vm", | ||
"version": "2.5.1", | ||
"version": "2.6.0", | ||
"description": "An Ethereum VM implementation", | ||
@@ -16,4 +16,5 @@ "main": "dist/index.js", | ||
"testStateConstantinople": "npm run build:dist && node ./tests/tester -s --fork='Constantinople' --dist", | ||
"testStatePetersburg": "npm run build:dist && node ./tests/tester -s --fork='Petersburg' --dist", | ||
"testBuildIntegrity": "npm run build:dist && node ./tests/tester -s --dist --test='stackOverflow'", | ||
"testBlockchain": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --dist --excludeDir='GeneralStateTests'", | ||
"testBlockchain": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --fork='Constantinople' --dist --excludeDir='GeneralStateTests'", | ||
"testBlockchainGeneralStateTests": "npm run build:dist && node --stack-size=1500 ./tests/tester -b --dist --dir='GeneralStateTests'", | ||
@@ -40,4 +41,4 @@ "testAPI": "tape ./tests/api/*.js", | ||
"ethereumjs-account": "^2.0.3", | ||
"ethereumjs-block": "~2.1.0", | ||
"ethereumjs-common": "^0.6.0", | ||
"ethereumjs-block": "~2.2.0", | ||
"ethereumjs-common": "^1.1.0", | ||
"ethereumjs-util": "^6.0.0", | ||
@@ -55,4 +56,4 @@ "fake-merkle-patricia-tree": "^1.0.1", | ||
"documentation": "^8.1.2", | ||
"ethereumjs-blockchain": "^3.3.3", | ||
"ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.2.5", | ||
"ethereumjs-blockchain": "^3.4.0", | ||
"ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.2.7", | ||
"ethereumjs-tx": "1.3.7", | ||
@@ -59,0 +60,0 @@ "level": "^4.0.0", |
@@ -16,4 +16,13 @@ # SYNOPSIS | ||
Starting with the ``v2.5.0`` release we now support both ``Byzantium`` and ``Constantinople`` fork rules - with ``Byzantium`` currently being the default (this will change in the future). See [release notes](https://github.com/ethereumjs/ethereumjs-vm/releases/tag/v2.5.0) for further details and have a look at the [API docs](./docs/index.md) on instructions how to instantiate the VM with the respective fork rules. | ||
The VM (`v2.6.x` release series) currently supports the following hardforks | ||
(default: `Byzantium`): | ||
- `Byzantium` | ||
- `Constantinople` | ||
- `Petersburg` | ||
Parallel HF support was introduced in the `v2.5.0` release, if you want | ||
some background have a look at the respective | ||
[release notes](https://github.com/ethereumjs/ethereumjs-vm/releases/tag/v2.5.0). | ||
If you are still looking for a [Spurious Dragon](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-607.md) compatible version of this library install the latest of the ``2.2.x`` series (see [Changelog](./CHANGELOG.md)). | ||
@@ -20,0 +29,0 @@ |
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
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
226850
33
5186
106
+ Addedethereumjs-block@2.2.2(transitive)
+ Addedethereumjs-common@1.5.2(transitive)
+ Addedethereumjs-tx@2.1.2(transitive)
- Removedethereum-common@0.0.18(transitive)
- Removedethereumjs-block@2.1.0(transitive)
- Removedethereumjs-common@0.6.1(transitive)
- Removedethereumjs-tx@1.3.7(transitive)
Updatedethereumjs-block@~2.2.0
Updatedethereumjs-common@^1.1.0