diff --git a/ironfish/src/consensus/verifier.ts b/ironfish/src/consensus/verifier.ts index da349865d3..9baa765e42 100644 --- a/ironfish/src/consensus/verifier.ts +++ b/ironfish/src/consensus/verifier.ts @@ -167,10 +167,8 @@ export class Verifier { tx?: IDatabaseTransaction, ): Promise { return this.chain.db.withTransaction(tx, async (tx) => { - const noteSize = await this.chain.notes.size(tx) - for (const spend of transaction.spends()) { - const reason = await this.verifySpend(spend, noteSize, tx) + const reason = await this.verifySpend(spend, tx) if (reason) { return { valid: false, reason } } @@ -296,16 +294,15 @@ export class Verifier { async hasValidSpends(block: Block, tx?: IDatabaseTransaction): Promise { return this.chain.db.withTransaction(tx, async (tx) => { const spendsInThisBlock = Array.from(block.spends()) - const previousSpendCount = - block.header.nullifierCommitment.size - spendsInThisBlock.length + const processedSpends = new BufferSet() - for (const [index, spend] of spendsInThisBlock.entries()) { + for (const [_, spend] of spendsInThisBlock.entries()) { if (processedSpends.has(spend.nullifier)) { return { valid: false, reason: VerificationResultReason.DOUBLE_SPEND } } - const verificationError = await this.verifySpend(spend, previousSpendCount + index, tx) + const verificationError = await this.verifySpend(spend, tx) if (verificationError) { return { valid: false, reason: verificationError } } @@ -329,10 +326,9 @@ export class Verifier { */ async verifySpend( spend: Spend, - size: number, tx?: IDatabaseTransaction, ): Promise { - if (await this.chain.nullifiers.contained(spend.nullifier, size, tx)) { + if (await this.chain.nullifiers.contains(spend.nullifier, tx)) { return VerificationResultReason.DOUBLE_SPEND } diff --git a/ironfish/src/merkletree/merkletree.test.ts b/ironfish/src/merkletree/merkletree.test.ts index d59aabd998..5e12589893 100644 --- a/ironfish/src/merkletree/merkletree.test.ts +++ b/ironfish/src/merkletree/merkletree.test.ts @@ -317,20 +317,36 @@ describe('Merkle tree', function () { it('finds contained values', async () => { const tree = await makeTree() - expect(await tree.contained('1', 0)).toBe(false) - expect(await tree.contained('1', 1)).toBe(false) for (let i = 1; i < 32; i++) { await tree.add(String(i)) + expect(await tree.contains(String(i))).toBe(true) + expect(await tree.contains(String(i + 1))).toBe(false) + } + }) - for (let j = 1; j < i; j++) { - expect(await tree.contained(String(i), j)).toBe(false) - expect(await tree.contained(String(j), i)).toBe(true) - } + it('does not find value after truncating tree', async () => { + const tree = await makeTree() + const elementSize = 32 - expect(await tree.contained(String(i), i)).toBe(true) - expect(await tree.contained(String(i), i + 1)).toBe(true) - expect(await tree.contains(String(i))).toBe(true) + for (let i = 0; i < elementSize; i++) { + const element = String(i) + await tree.add(element) + + expect(await tree.contains(element)).toBe(true) + } + + for (let i = elementSize - 1; i > 0; i--) { + // truncate the tree by 1 and check that the last value isn't there + const element = String(i) + await tree.truncate(i) + + expect(await tree.contains(element)).toBe(false) + + // check that the rest of the elements are still there + for (let j = 0; j < i; j++) { + expect(await tree.contains(String(j))).toBe(true) + } } }) diff --git a/ironfish/src/merkletree/merkletree.ts b/ironfish/src/merkletree/merkletree.ts index c569b33f98..8196bd9e01 100644 --- a/ironfish/src/merkletree/merkletree.ts +++ b/ironfish/src/merkletree/merkletree.ts @@ -513,9 +513,12 @@ export class MerkleTree< /** * Check if the tree contained the given element when it was the given size. - * TODO — pastSize is unecessary here now */ - async contained(value: E, pastSize: number, tx?: IDatabaseTransaction): Promise { + private async contained( + value: E, + pastSize: number, + tx?: IDatabaseTransaction, + ): Promise { return this.db.withTransaction(tx, async (tx) => { const elementIndex = await this.leavesIndex.get(this.hasher.merkleHash(value), tx)