Skip to content

Commit

Permalink
Make stateManager cache and trie private
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdean-digicatapult committed Nov 7, 2018
1 parent 84db45e commit 688d28d
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 42 deletions.
56 changes: 26 additions & 30 deletions lib/stateManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ module.exports = StateManager
function StateManager (opts = {}) {
var self = this

self.trie = opts.trie || new Trie()

var common = opts.common
if (!common) {
common = new Common('mainnet', 'byzantium')
}
self._common = common

self._trie = opts.trie || new Trie()
self._storageTries = {} // the storage trie cache
self.cache = new Cache(self.trie)
self._cache = new Cache(self._trie)
self._touched = new Set()
self._touchedStack = []
self._checkpointCount = 0
Expand All @@ -32,13 +31,13 @@ function StateManager (opts = {}) {
var proto = StateManager.prototype

proto.copy = function () {
return new StateManager({ trie: this.trie.copy() })
return new StateManager({ trie: this._trie.copy() })
}

// gets the account from the cache, or triggers a lookup and stores
// the result in the cache
proto.getAccount = function (address, cb) {
this.cache.getOrLoad(address, cb)
this._cache.getOrLoad(address, cb)
}

// saves the account
Expand All @@ -47,9 +46,9 @@ proto.putAccount = function (address, account, cb) {
// TODO: dont save newly created accounts that have no balance
// if (toAccount.balance.toString('hex') === '00') {
// if they have money or a non-zero nonce or code, then write to tree
self.cache.put(address, account)
self._cache.put(address, account)
self._touched.add(address.toString('hex'))
// self.trie.put(addressHex, account.serialize(), cb)
// self._trie.put(addressHex, account.serialize(), cb)
cb()
}

Expand Down Expand Up @@ -84,7 +83,7 @@ proto.putContractCode = function (address, value, cb) {
return cb(err)
}
// TODO: setCode use trie.setRaw which creates a storage leak
account.setCode(self.trie, value, function (err) {
account.setCode(self._trie, value, function (err) {
if (err) {
return cb(err)
}
Expand All @@ -100,7 +99,7 @@ proto.getContractCode = function (address, cb) {
if (err) {
return cb(err)
}
account.getCode(self.trie, cb)
account.getCode(self._trie, cb)
})
}

Expand All @@ -112,7 +111,7 @@ proto._lookupStorageTrie = function (address, cb) {
if (err) {
return cb(err)
}
var storageTrie = self.trie.copy()
var storageTrie = self._trie.copy()
storageTrie.root = account.stateRoot
storageTrie._checkpoints = []
cb(null, storageTrie)
Expand Down Expand Up @@ -161,7 +160,7 @@ proto._modifyContractStorage = function (address, modifyTrie, cb) {
// update storage cache
self._storageTries[address.toString('hex')] = storageTrie
// update contract stateRoot
var contract = self.cache.get(address)
var contract = self._cache.get(address)
contract.stateRoot = storageTrie.root
self.putAccount(address, contract, cb)
self._touched.add(address.toString('hex'))
Expand Down Expand Up @@ -196,63 +195,60 @@ proto.clearContractStorage = function (address, cb) {
//
proto.checkpoint = function () {
var self = this
self.trie.checkpoint()
self.cache.checkpoint()
self._trie.checkpoint()
self._cache.checkpoint()
self._touchedStack.push(new Set([...self._touched]))
self._checkpointCount++
}

proto.commit = function (cb) {
var self = this
// setup trie checkpointing
self.trie.commit(function () {
self._trie.commit(function () {
// setup cache checkpointing
self.cache.commit()
self._cache.commit()
self._touchedStack.pop()
self._checkpointCount--

if (self._checkpointCount === 0) self.cache.flush(cb)
if (self._checkpointCount === 0) self._cache.flush(cb)
else cb()
})
}

proto.revert = function (cb) {
var self = this
// setup trie checkpointing
self.trie.revert()
self._trie.revert()
// setup cache checkpointing
self.cache.revert()
self._cache.revert()
self._storageTries = {}
self._touched = self._touchedStack.pop()
self._checkpointCount--

if (self._checkpointCount === 0) self.cache.flush(cb)
if (self._checkpointCount === 0) self._cache.flush(cb)
else cb()
}

//
// cache stuff
//
proto.getStateRoot = function (cb) {
var self = this
self.cache.flush(function (err) {
self._cache.flush(function (err) {
if (err) {
return cb(err)
}
var stateRoot = self.trie.root
var stateRoot = self._trie.root
cb(null, stateRoot)
})
}

proto.setStateRoot = function (stateRoot, cb) {
var self = this
self.cache.flush(function (err) {
self._cache.flush(function (err) {
if (err) { return cb(err) }
self.trie.checkRoot(stateRoot, function (err, hasRoot) {
self._trie.checkRoot(stateRoot, function (err, hasRoot) {
if (err || !hasRoot) {
cb(err || new Error('State trie does not contain state root'))
} else {
self.trie.root = stateRoot
self._trie.root = stateRoot
cb()
}
})
Expand All @@ -278,7 +274,7 @@ proto.dumpStorage = function (address, cb) {

proto.hasGenesisState = function (cb) {
const root = this._common.genesis().stateRoot
this.trie.checkRoot(root, cb)
this._trie.checkRoot(root, cb)
}

proto.generateCanonicalGenesis = function (cb) {
Expand All @@ -300,7 +296,7 @@ proto.generateGenesis = function (initState, cb) {
var account = new Account()
account.balance = new BN(initState[address]).toArrayLike(Buffer)
address = Buffer.from(address, 'hex')
self.trie.put(address, account.serialize(), done)
self._trie.put(address, account.serialize(), done)
}, cb)
}

Expand All @@ -327,7 +323,7 @@ proto.cleanupTouchedAccounts = function (cb) {
}

if (empty) {
self.cache.del(address)
self._cache.del(address)
}
next(null)
})
Expand Down
10 changes: 5 additions & 5 deletions tests/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ tape('VM with fake blockchain', (t) => {
t.test('should insantiate without params', (st) => {
const vm = new VM()
st.ok(vm.stateManager)
st.deepEqual(vm.stateManager.trie.root, util.KECCAK256_RLP, 'it has default trie')
st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
st.ok(vm.blockchain.fake, 'it has fake blockchain by default')
st.end()
})

t.test('should be able to activate precompiles', (st) => {
let vm = new VM({ activatePrecompiles: true })
st.notEqual(vm.stateManager.trie.root, util.KECCAK256_RLP, 'it has different root')
st.notEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has different root')
st.end()
})

Expand Down Expand Up @@ -47,7 +47,7 @@ tape('VM with fake blockchain', (t) => {
tape('VM with blockchain', (t) => {
t.test('should instantiate', (st) => {
const vm = setupVM()
st.deepEqual(vm.stateManager.trie.root, util.KECCAK256_RLP, 'it has default trie')
st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
st.notOk(vm.stateManager.fake, 'it doesn\'t have fake blockchain')
st.end()
})
Expand All @@ -74,7 +74,7 @@ tape('VM with blockchain', (t) => {
)

const setupPreP = promisify(setupPreConditions)
await setupPreP(vm.stateManager.trie, testData)
await setupPreP(vm.stateManager._trie, testData)

vm.runBlock = (block, cb) => cb(new Error('test'))
runBlockchainP(vm)
Expand All @@ -101,7 +101,7 @@ tape('VM with blockchain', (t) => {
)

const setupPreP = promisify(setupPreConditions)
await setupPreP(vm.stateManager.trie, testData)
await setupPreP(vm.stateManager._trie, testData)

await runBlockchainP(vm)

Expand Down
8 changes: 4 additions & 4 deletions tests/api/runBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ tape('should fail when runCall fails', async (t) => {
// which always returns an error.
// runTx is a full implementation that works.
suite.vm.runTx = runTx
await suite.p.runBlock({ block, root: suite.vm.stateManager.trie.root })
await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root })
.then(() => t.fail('should have returned error'))
.catch((e) => t.equal(e.message, 'test'))

Expand All @@ -137,15 +137,15 @@ tape('should run valid block', async (t) => {
const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))

const setupPreP = promisify(setupPreConditions)
await setupPreP(suite.vm.stateManager.trie, suite.data)
await setupPreP(suite.vm.stateManager._trie, suite.data)

t.equal(
suite.vm.stateManager.trie.root.toString('hex'),
suite.vm.stateManager._trie.root.toString('hex'),
genesis.header.stateRoot.toString('hex'),
'genesis state root should match calculated state root'
)

let res = await suite.p.runBlock({ block, root: suite.vm.stateManager.trie.root })
let res = await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root })
t.error(res.error, 'runBlock shouldn\'t have returned error')
t.equal(res.results[0].gasUsed.toString('hex'), '5208', 'actual gas used should equal blockHeader gasUsed')

Expand Down
6 changes: 3 additions & 3 deletions tests/api/stateManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ tape('StateManager', (t) => {
t.test('should instantiate', (st) => {
const stateManager = new StateManager()

st.deepEqual(stateManager.trie.root, util.KECCAK256_RLP, 'it has default root')
st.deepEqual(stateManager._trie.root, util.KECCAK256_RLP, 'it has default root')
stateManager.getStateRoot((err, res) => {
st.error(err, 'getStateRoot returns no error')
st.deepEqual(res, util.KECCAK256_RLP, 'it has default root')
Expand All @@ -33,13 +33,13 @@ tape('StateManager', (t) => {

st.equal(res.balance.toString('hex'), 'fff384')

stateManager.cache.clear()
stateManager._cache.clear()

res = await promisify(stateManager.getAccount.bind(stateManager))(
'a94f5374fce5edbc8e2a8697c15331677e6ebf0b'
)

st.equal(stateManager.cache._cache.keys[0], 'a94f5374fce5edbc8e2a8697c15331677e6ebf0b')
st.equal(stateManager._cache._cache.keys[0], 'a94f5374fce5edbc8e2a8697c15331677e6ebf0b')

st.end()
})
Expand Down

0 comments on commit 688d28d

Please sign in to comment.