Skip to content

Commit

Permalink
Remove vm accesses to stateManager trie and cache
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdean-digicatapult committed Nov 5, 2018
1 parent 41e3f63 commit 80c1c34
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 104 deletions.
73 changes: 34 additions & 39 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
- [Parameters][6]
- [runBlock~callback][7]
- [Parameters][8]
- [vm.runTx][9]
- [runTx~callback][9]
- [Parameters][10]
- [runTx~callback][11]
- [vm.runTx][11]
- [Parameters][12]
- [vm.runCode][13]
- [Parameters][14]
- [runCode~callback][15]
- [Parameters][16]
- [Event: beforeBlock][17]
- [Properties][18]
- [Event: beforeTx][19]
- [Event: afterBlock][19]
- [Properties][20]
- [Event: afterBlock][21]
- [Event: beforeTx][21]
- [Properties][22]
- [Event: afterTx][23]
- [Properties][24]
Expand Down Expand Up @@ -80,19 +80,6 @@ Type: [Function][30]
- `results.receipts` **[Array][39]** the receipts from the transactions in the block
- `results.results` **[Array][39]**

## vm.runTx

Process a transaction. Run the vm. Transfers eth. Checks balances.

### Parameters

- `opts`
- `opts.tx` **Transaction** a [`Transaction`][40] to run
- `opts.skipNonce` **[Boolean][34]** skips the nonce check
- `opts.skipBalance` **[Boolean][34]** skips the balance check
- `opts.block` **Block** the block to which the `tx` belongs, if no block is given a default one is created
- `cb` **[runTx~callback][41]** the callback

## runTx~callback

Callback for `runTx` method
Expand All @@ -106,7 +93,20 @@ Type: [Function][30]
- `results.amountSpent` **BN** the amount of ether used by this transaction as a `bignum`
- `results.gasUsed` **BN** the amount of gas as a `bignum` used by the transaction
- `results.gasRefund` **BN** the amount of gas as a `bignum` that was refunded during the transaction (i.e. `gasUsed = totalGasConsumed - gasRefund`)
- `vm` **[VM][42]** contains the results from running the code, if any, as described in `vm.runCode(params, cb)`
- `vm` **[VM][40]** contains the results from running the code, if any, as described in `vm.runCode(params, cb)`

## vm.runTx

Process a transaction. Run the vm. Transfers eth. Checks balances.

### Parameters

- `opts`
- `opts.tx` **Transaction** a [`Transaction`][41] to run
- `opts.skipNonce` **[Boolean][34]** skips the nonce check
- `opts.skipBalance` **[Boolean][34]** skips the balance check
- `opts.block` **Block** the block to which the `tx` belongs, if no block is given a default one is created
- `cb` **[runTx~callback][42]** the callback

## vm.runCode

Expand Down Expand Up @@ -155,25 +155,25 @@ Type: [Object][31]

- `block` **Block** emits the block that is about to be processed

## Event: beforeTx
## Event: afterBlock

The `beforeTx` event
The `afterBlock` event

Type: [Object][31]

### Properties

- `tx` **Transaction** emits the Transaction that is about to be processed
- `result` **[Object][31]** emits the results of processing a block

## Event: afterBlock
## Event: beforeTx

The `afterBlock` event
The `beforeTx` event

Type: [Object][31]

### Properties

- `result` **[Object][31]** emits the results of processing a block
- `tx` **Transaction** emits the Transaction that is about to be processed

## Event: afterTx

Expand Down Expand Up @@ -208,12 +208,11 @@ Type: [Object][31]
- `opcode` **[String][32]** the next opcode to be ran
- `gasLeft` **BN** amount of gasLeft
- `stack` **[Array][39]** an `Array` of `Buffers` containing the stack
- `storageTrie` **Trie** the storage [trie][46] for the account
- `account` **Account** the [`Account`][47] which owns the code running
- `account` **Account** the [`Account`][46] which owns the code running
- `address` **[Buffer][44]** the address of the `account`
- `depth` **[Number][33]** the current number of calls deep the contract is
- `memory` **[Buffer][44]** the memory of the VM as a `buffer`
- `cache` **FunctionalRedBlackTree** the account cache. Contains all the accounts loaded from the trie. It is an instance of [functional red black tree][48]
- `storageManager` **StateManager** a state manager instance (EXPERIMENTAL - unstable API)

[1]: #vmrunblockchain

Expand All @@ -231,11 +230,11 @@ Type: [Object][31]

[8]: #parameters-3

[9]: #vmruntx
[9]: #runtxcallback

[10]: #parameters-4

[11]: #runtxcallback
[11]: #vmruntx

[12]: #parameters-5

Expand All @@ -251,11 +250,11 @@ Type: [Object][31]

[18]: #properties

[19]: #event-beforetx
[19]: #event-afterblock

[20]: #properties-1

[21]: #event-afterblock
[21]: #event-beforetx

[22]: #properties-2

Expand Down Expand Up @@ -293,20 +292,16 @@ Type: [Object][31]

[39]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array

[40]: https://github.com/ethereum/ethereumjs-tx
[40]: #vm

[41]: #runtxcallback
[41]: https://github.com/ethereum/ethereumjs-tx

[42]: #vm
[42]: #runtxcallback

[43]: https://github.com/ethereumjs/ethereumjs-account

[44]: https://nodejs.org/api/buffer.html

[45]: #runcodecallback

[46]: https://github.com/wanderer/merkle-patricia-tree

[47]: https://github.com/ethereum/ethereumjs-account

[48]: https://www.npmjs.com/package/functional-red-black-tree
[46]: https://github.com/ethereum/ethereumjs-account
28 changes: 9 additions & 19 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const StateManager = require('./stateManager.js')
const Common = require('ethereumjs-common')
const Account = require('ethereumjs-account')
const AsyncEventEmitter = require('async-eventemitter')
const Trie = require('merkle-patricia-tree/secure.js')
const fakeBlockchain = require('./fakeBlockChain.js')
const BN = ethUtil.BN

Expand Down Expand Up @@ -54,11 +55,14 @@ function VM (opts = {}) {
if (opts.stateManager) {
this.stateManager = opts.stateManager
} else {
this.stateManager = new StateManager({
trie: opts.state,
blockchain: opts.blockchain,
common: this._common
})
var trie = opts.state || new Trie()
if (opts.activatePrecompiles) {
trie = new Trie()
for (var i = 1; i <= 8; i++) {
trie.put(new BN(i).toArrayLike(Buffer, 'be', 20), new Account().serialize())
}
}
this.stateManager = new StateManager({ trie, common: this._common })
}

this.blockchain = opts.blockchain || fakeBlockchain
Expand All @@ -77,12 +81,6 @@ function VM (opts = {}) {
this._precompiled['0000000000000000000000000000000000000007'] = num07
this._precompiled['0000000000000000000000000000000000000008'] = num08

if (this.opts.activatePrecompiles) {
for (var i = 1; i <= 7; i++) {
this.stateManager.trie.put(new BN(i).toArrayLike(Buffer, 'be', 20), new Account().serialize())
}
}

AsyncEventEmitter.call(this)
}

Expand All @@ -98,11 +96,3 @@ VM.prototype.runBlockchain = require('./runBlockchain.js')
VM.prototype.copy = function () {
return new VM({ stateManager: this.stateManager.copy(), blockchain: this.blockchain })
}

/**
* Loads precompiled contracts into the state
* @private
*/
VM.prototype.loadCompiled = function (address, src, cb) {
this.stateManager.trie.db.put(address, src, cb)
}
6 changes: 4 additions & 2 deletions lib/opFns.js
Original file line number Diff line number Diff line change
Expand Up @@ -956,8 +956,10 @@ function makeCall (runState, callOptions, localOpts, cb) {
runState.contract.nonce = new BN(runState.contract.nonce).addn(1)
}

runState.stateManager.cache.put(runState.address, runState.contract)
runState._vm.runCall(callOptions, parseCallResults)
runState.stateManager.putAccount(runState.address, runState.contract, function (err) {
if (err) return cb(err)
runState._vm.runCall(callOptions, parseCallResults)
})
}

function parseCallResults (err, results) {
Expand Down
50 changes: 29 additions & 21 deletions lib/runBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,12 @@ module.exports = function (opts, cb) {
var txResults = []
var result

if (opts.root) {
self.stateManager.trie.root = opts.root
}

self.stateManager.trie.checkpoint()
self.stateManager.checkpoint()

// run everything
async.series([
beforeBlock,
setStateRoot,
processTransactions,
payOmmersAndMiner
], parseBlockResults)
Expand All @@ -81,6 +78,14 @@ module.exports = function (opts, cb) {
self.emit('afterBlock', result, cb)
}

function setStateRoot (cb) {
if (opts.root) {
self.stateManager.setStateRoot(opts.root, cb)
} else {
cb(null)
}
}

/**
* Processes all of the transaction in the block
* @method processTransaction
Expand Down Expand Up @@ -148,19 +153,19 @@ module.exports = function (opts, cb) {
}
}

// credit all block rewards
// credit all block rewards
function payOmmersAndMiner (cb) {
var ommers = block.uncleHeaders

// pay each ommer
// pay each ommer
async.series([
rewardOmmers,
rewardMiner
], cb)

function rewardOmmers (done) {
async.each(block.uncleHeaders, function (ommer, next) {
// calculate reward
// calculate reward
var minerReward = new BN(self._common.param('pow', 'minerReward'))
var heightDiff = new BN(block.header.number).sub(new BN(ommer.number))
var reward = ((new BN(8)).sub(heightDiff)).mul(minerReward.divn(8))
Expand All @@ -174,7 +179,7 @@ module.exports = function (opts, cb) {
}

function rewardMiner (done) {
// calculate nibling reward
// calculate nibling reward
var minerReward = new BN(self._common.param('pow', 'minerReward'))
var niblingReward = minerReward.divn(32)
var totalNiblingReward = niblingReward.muln(ommers.length)
Expand All @@ -185,7 +190,7 @@ module.exports = function (opts, cb) {
function rewardAccount (address, reward, done) {
self.stateManager.getAccount(address, function (err, account) {
if (err) return done(err)
// give miner the block reward
// give miner the block reward
account.balance = new BN(account.balance).add(reward)
self.stateManager.putAccount(address, account, done)
})
Expand All @@ -195,18 +200,23 @@ module.exports = function (opts, cb) {
// handle results or error from block run
function parseBlockResults (err) {
if (err) {
self.stateManager.trie.revert()
cb(err)
self.stateManager.revert(true, function () {
cb(err)
})
return
}

// credit all block rewards
if (generateStateRoot) {
block.header.stateRoot = self.stateManager.trie.root
}
self.stateManager.commit(true, function (err) {
if (err) return cb(err)

self.stateManager.getStateRoot(function (err, stateRoot) {
if (err) return cb(err)

// credit all block rewards
if (generateStateRoot) {
block.header.stateRoot = stateRoot
}

self.stateManager.trie.commit(function (err) {
self.stateManager.cache.flush(function () {
if (validateStateRoot) {
if (receiptTrie.root && receiptTrie.root.toString('hex') !== block.header.receiptTrie.toString('hex')) {
err = new Error((err || '') + 'invalid receiptTrie ')
Expand All @@ -217,13 +227,11 @@ module.exports = function (opts, cb) {
if (ethUtil.bufferToInt(block.header.gasUsed) !== Number(gasUsed)) {
err = new Error((err || '') + 'invalid gasUsed ')
}
if (self.stateManager.trie.root.toString('hex') !== block.header.stateRoot.toString('hex')) {
if (stateRoot.toString('hex') !== block.header.stateRoot.toString('hex')) {
err = new Error((err || '') + 'invalid block stateRoot ')
}
}

self.stateManager.cache.clear()

result = {
receipts: receipts,
results: txResults,
Expand Down
6 changes: 3 additions & 3 deletions lib/runCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ module.exports = function (opts, cb) {
function runCode (cb) {
if (!code) {
vmResults.exception = 1
stateManager.commit(cb)
stateManager.commit(false, cb)
return
}

Expand Down Expand Up @@ -217,7 +217,7 @@ module.exports = function (opts, cb) {
gasUsed = results.gasUsed
if (err) {
results.logs = []
stateManager.revert(function (revertErr) {
stateManager.revert(false, function (revertErr) {
if (revertErr || !isCompiled) cb(revertErr)
else {
// Empty precompiled contracts need to be deleted even in case of OOG
Expand All @@ -235,7 +235,7 @@ module.exports = function (opts, cb) {
}
})
} else {
stateManager.commit(cb)
stateManager.commit(false, cb)
}
}
}
Expand Down
Loading

0 comments on commit 80c1c34

Please sign in to comment.