Skip to content

Commit

Permalink
Merge pull request #420 from ethereumjs/state-manager-clear-cache-aft…
Browse files Browse the repository at this point in the history
…er-set-state-root

Clear stateManager cache after setStateRoot
  • Loading branch information
holgerd77 committed Jan 16, 2019
2 parents fcf6eb7 + 784cfeb commit 09b8bfb
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
6 changes: 6 additions & 0 deletions lib/stateManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,11 +396,17 @@ proto.setStateRoot = function (stateRoot, cb) {

self._cache.flush(function (err) {
if (err) { return cb(err) }
if (stateRoot === self._trie.EMPTY_TRIE_ROOT) {
self._trie.root = stateRoot
self._cache.clear()
return cb()
}
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._cache.clear()
cb()
}
})
Expand Down
8 changes: 3 additions & 5 deletions tests/api/runBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@ tape('runBlock', async (t) => {
})

t.test('should fail when runTx fails', async (st) => {
const genesis = createGenesis()
const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))

await suite.p.generateCanonicalGenesis()

// The mocked VM uses a mocked runTx
// which always returns an error.
await suite.p.runBlock({ block, root: genesis.header.stateRoot, skipBlockValidation: true })
await suite.p.runBlock({ block, skipBlockValidation: true })
.then(() => t.fail('should have returned error'))
.catch((e) => t.equal(e.message, 'test'))

Expand Down Expand Up @@ -106,13 +105,12 @@ tape('should fail when block validation fails', async (t) => {
tape('should fail when tx gas limit higher than block gas limit', async (t) => {
const suite = setup()

const genesis = createGenesis()
const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))
block.transactions[0].gasLimit = Buffer.from('3fefba', 'hex')

await suite.p.generateCanonicalGenesis()

await suite.p.runBlock({ block, root: genesis.header.stateRoot, skipBlockValidation: true })
await suite.p.runBlock({ block, skipBlockValidation: true })
.then(() => t.fail('should have returned error'))
.catch((e) => t.ok(e.message.includes('higher gas limit')))

Expand All @@ -137,7 +135,7 @@ tape('should fail when runCall fails', async (t) => {
// runTx is a full implementation that works.
suite.vm.runTx = runTx

await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root, skipBlockValidation: true })
await suite.p.runBlock({ block, skipBlockValidation: true })

.then(() => t.fail('should have returned error'))
.catch((e) => t.equal(e.message, 'test'))
Expand Down
30 changes: 30 additions & 0 deletions tests/api/stateManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,36 @@ tape('StateManager', (t) => {
st.end()
})

t.test('should clear the cache when the state root is set', async (st) => {
const stateManager = new StateManager()
const addressBuffer = Buffer.from('a94f5374fce5edbc8e2a8697c15331677e6ebf0b', 'hex')
const account = createAccount()

const getStateRoot = promisify((...args) => stateManager.getStateRoot(...args))
const checkpoint = promisify((...args) => stateManager.checkpoint(...args))
const putAccount = promisify((...args) => stateManager.putAccount(...args))
const getAccount = promisify((...args) => stateManager.getAccount(...args))
const commit = promisify((...args) => stateManager.commit(...args))
const setStateRoot = promisify((...args) => stateManager.setStateRoot(...args))

const initialStateRoot = await getStateRoot()
await checkpoint()
await putAccount(addressBuffer, account)

const account0 = await getAccount(addressBuffer)
st.equal(account0.balance.toString('hex'), account.balance.toString('hex'), 'account value is set in the cache')

await commit()
const account1 = await getAccount(addressBuffer)
st.equal(account1.balance.toString('hex'), account.balance.toString('hex'), 'account value is set in the state trie')

await setStateRoot(initialStateRoot)
const account2 = await getAccount(addressBuffer)
st.equal(account2.balance.toString('hex'), '', 'account value is set to 0 in original state root')

st.end()
})

t.test('should put and get account, and add to the underlying cache if the account is not found', async (st) => {
const stateManager = new StateManager()
const account = createAccount()
Expand Down

0 comments on commit 09b8bfb

Please sign in to comment.