diff --git a/lib/index.js b/lib/index.js index 91f0b75..6d6e22e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -83,23 +83,39 @@ class DBTangle extends MsgV3.Tangle { } /** + * Given a set of msgs (`msgIDs`) in this tangle, find all "deletable" and + * "erasable" msgs that precede that set. + * + * *Deletables* are msgs that precede `msgsIDs` but are not important in any + * validation path toward the root, and thus can be deleted. + * + * *Erasables* are msgs that precede `msgsIDs` and can be erased without + * losing a validation path toward the root. * @param {Array} msgIDs + * @returns {{ deletables: Set, erasables: Set }} */ getDeletablesAndErasables(...msgIDs) { - const erasableSet = new Set() + // Determine erasables + const erasables = new Set() const minimum = this.getMinimumAmong(msgIDs) for (const msgID of minimum) { const trail = this.shortestPathToRoot(msgID) for (const id of trail) { - erasableSet.add(id) + erasables.add(id) } } + + // Determine deletables + const deletables = new Set() const sorted = this.topoSort() - const deletables = sorted.filter( - (id) => - !erasableSet.has(id) && minimum.some((min) => this.precedes(id, min)) - ) - return { deletables, erasables: [...erasableSet] } + for (const msgID of sorted) { + if (erasables.has(msgID)) continue + if (minimum.some((min) => this.precedes(msgID, min))) { + deletables.add(msgID) + } + } + + return { deletables, erasables } } } @@ -929,7 +945,7 @@ function initDB(peer, config) { /** * @param {string} tangleID - * @returns {Tangle} + * @returns {DBTangle} */ function getTangle(tangleID) { return new DBTangle(tangleID, records()) diff --git a/test/getTangle.test.js b/test/getTangle.test.js index 50201c7..786b976 100644 --- a/test/getTangle.test.js +++ b/test/getTangle.test.js @@ -204,8 +204,8 @@ test('Tangle.getLipmaaSet', (t) => { test('Tangle.getDeletablesAndErasables basic', (t) => { const { deletables, erasables } = tangle.getDeletablesAndErasables(reply2) - assert.deepEqual(deletables, [reply1Hi], 'deletables') - assert.deepEqual(erasables, [reply1Lo, rootPost], 'erasables') + assert.deepEqual([...deletables], [reply1Hi], 'deletables') + assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables') }) test('Tangle.getDeletablesAndErasables with many inputs', (t) => { @@ -214,8 +214,8 @@ test('Tangle.getDeletablesAndErasables with many inputs', (t) => { reply2 ) - assert.deepEqual(deletables, [reply1Hi], 'deletables') - assert.deepEqual(erasables, [reply1Lo, rootPost], 'erasables') + assert.deepEqual([...deletables], [reply1Hi], 'deletables') + assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables') }) test('Tangle.getDeletablesAndErasables with many inputs again', (t) => { @@ -224,15 +224,15 @@ test('Tangle.getDeletablesAndErasables with many inputs again', (t) => { reply3Hi ) - assert.deepEqual(deletables, [reply1Lo, reply1Hi, reply2], 'deletables') - assert.deepEqual(erasables, [rootPost], 'erasables') + assert.deepEqual([...deletables], [reply1Lo, reply1Hi, reply2], 'deletables') + assert.deepEqual([...erasables], [rootPost], 'erasables') }) test('Tangle.getDeletablesAndErasables with lipmaa', (t) => { const { deletables, erasables } = tangle.getDeletablesAndErasables(reply3Lo) - assert.deepEqual(deletables, [reply1Lo, reply1Hi, reply2], 'deletables') - assert.deepEqual(erasables, [rootPost], 'erasables') + assert.deepEqual([...deletables], [reply1Lo, reply1Hi, reply2], 'deletables') + assert.deepEqual([...erasables], [rootPost], 'erasables') }) test('Tangle.getMinimumAmong', (t) => {