Skip to content

Commit

Permalink
fix(trie): handle root key and value during pruned integrity verifica…
Browse files Browse the repository at this point in the history
…tion (#2296)

* fix(trie): handle root key and value during pruned integrity verification

* Update packages/trie/test/trie/prune.spec.ts

Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com>

* Update packages/trie/src/trie/trie.ts

Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com>

Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com>
  • Loading branch information
Brian Faust and jochem-brouwer committed Sep 20, 2022
1 parent 3d7472c commit 5ca079f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
4 changes: 2 additions & 2 deletions packages/trie/src/trie/trie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,9 +799,9 @@ export class Trie {
// (i.e. the Trie is not correctly pruned)
// If this method returns `true`, the Trie is correctly pruned and all keys are reachable
async verifyPrunedIntegrity(): Promise<boolean> {
const root = this.root().toString('hex')
const roots = [this.root().toString('hex'), this.appliedKey(ROOT_DB_KEY).toString('hex')]
for (const dbkey of (<any>this)._db.db._database.keys()) {
if (dbkey === root) {
if (roots.includes(dbkey)) {
// The root key can never be found from the trie, otherwise this would
// convert the tree from a directed acyclic graph to a directed cycling graph
continue
Expand Down
61 changes: 61 additions & 0 deletions packages/trie/test/trie/prune.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,65 @@ tape('Pruned trie tests', function (tester) {
await (<any>trie)._db.db.put(Buffer.from('aa', 'hex'))
st.ok(!(await trie.verifyPrunedIntegrity()), 'trie is not pruned')
})

it('should prune when keys are updated or deleted (with `useRootPersistence` enabled)', async (st) => {
for (let testID = 0; testID < 1; testID++) {
const trie = await Trie.create({ useNodePruning: true, useRootPersistence: true })
const keys: string[] = []
for (let i = 0; i < 100; i++) {
keys.push(crypto.randomBytes(32))
}
const values: string[] = []
for (let i = 0; i < 1000; i++) {
let val = Math.floor(Math.random() * 16384)
while (values.includes(val.toString(16))) {
val = Math.floor(Math.random() * 16384)
}
values.push(val.toString(16))
}
// Fill trie with items
for (let i = 0; i < keys.length; i++) {
const idx = Math.floor(Math.random() * keys.length)
const key = keys[idx]
await trie.put(Buffer.from(key), Buffer.from(values[i]))
}

st.ok(await trie.verifyPrunedIntegrity(), 'trie is correctly pruned')

// Randomly delete keys
for (let i = 0; i < 20; i++) {
const idx = Math.floor(Math.random() * keys.length)
await trie.del(Buffer.from(keys[idx]))
}

st.ok(await trie.verifyPrunedIntegrity(), 'trie is correctly pruned')

// Fill trie with items or randomly delete them
for (let i = 0; i < keys.length; i++) {
const idx = Math.floor(Math.random() * keys.length)
const key = keys[idx]
if (Math.random() < 0.5) {
await trie.put(Buffer.from(key), Buffer.from(values[i]))
} else {
await trie.del(Buffer.from(key))
}
}

st.ok(await trie.verifyPrunedIntegrity(), 'trie is correctly pruned')

// Delete all keys
for (let idx = 0; idx < 100; idx++) {
await trie.del(Buffer.from(keys[idx]))
}

st.ok(await trie.verifyPrunedIntegrity(), 'trie is correctly pruned')
st.ok(trie.root().equals(KECCAK256_RLP), 'trie is empty')

let dbKeys = 0
for (const _dbkey of (<any>trie)._db.db._database.keys()) {
dbKeys++
}
st.ok(dbKeys === 1, 'db is empty')
}
})
})

0 comments on commit 5ca079f

Please sign in to comment.