diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index dd29b991f0cf..6049767b8fee 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -845,6 +845,8 @@ export class AztecNodeService implements AztecNode, Traceable { } } + // TODO(md): change this to run in parrel the same as in the p2p client - maybe not required + // as everything is sub ms apart from the double spend validator public async isValidTx(tx: Tx, isSimulation: boolean = false): Promise { const blockNumber = (await this.blockSource.getBlockNumber()) + 1; const db = this.worldStateSynchronizer.getCommitted(); @@ -855,9 +857,8 @@ export class AztecNodeService implements AztecNode, Traceable { new DataTxValidator(), new MetadataTxValidator(new Fr(this.l1ChainId), new Fr(blockNumber)), new DoubleSpendTxValidator({ - getNullifierIndex(nullifier) { - return db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]).then(x => x[0]); - }, + getNullifierIndices: nullifiers => + db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers).then(x => x.filter(index => index !== undefined) as bigint[]), }), ]; diff --git a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts index 378cfd7f78c7..f7f196135bd9 100644 --- a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts +++ b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts @@ -603,10 +603,10 @@ export class LibP2PService extends WithTracer implement }, doubleSpendValidator: { validator: new DoubleSpendTxValidator({ - getNullifierIndex: async (nullifier: Fr) => { + getNullifierIndices: async (nullifiers: Buffer[]) => { const merkleTree = this.worldStateSynchronizer.getCommitted(); - const index = (await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0]; - return index; + const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers); + return indices.filter(index => index !== undefined) as bigint[]; }, }), severity: PeerErrorSeverity.HighToleranceError, @@ -669,12 +669,12 @@ export class LibP2PService extends WithTracer implement } const snapshotValidator = new DoubleSpendTxValidator({ - getNullifierIndex: async (nullifier: Fr) => { + getNullifierIndices: async (nullifiers: Buffer[]) => { const merkleTree = this.worldStateSynchronizer.getSnapshot( blockNumber - this.config.severePeerPenaltyBlockLength, ); - const index = (await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0]; - return index; + const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers); + return indices.filter(index => index !== undefined) as bigint[]; }, }); diff --git a/yarn-project/p2p/src/tx_validator/double_spend_validator.test.ts b/yarn-project/p2p/src/tx_validator/double_spend_validator.test.ts index 1c123319f33e..e90d4b242f14 100644 --- a/yarn-project/p2p/src/tx_validator/double_spend_validator.test.ts +++ b/yarn-project/p2p/src/tx_validator/double_spend_validator.test.ts @@ -10,7 +10,7 @@ describe('DoubleSpendTxValidator', () => { beforeEach(() => { nullifierSource = mock({ - getNullifierIndex: mockFn().mockImplementation(() => { + getNullifierIndices: mockFn().mockImplementation(() => { return Promise.resolve(undefined); }), }); @@ -48,7 +48,7 @@ describe('DoubleSpendTxValidator', () => { it('rejects duplicates against history', async () => { const badTx = mockTx(); - nullifierSource.getNullifierIndex.mockReturnValueOnce(Promise.resolve(1n)); + nullifierSource.getNullifierIndices.mockReturnValueOnce(Promise.resolve([1n])); await expect(txValidator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); }); }); diff --git a/yarn-project/p2p/src/tx_validator/double_spend_validator.ts b/yarn-project/p2p/src/tx_validator/double_spend_validator.ts index 5bb06bf1fa9d..81538eaea342 100644 --- a/yarn-project/p2p/src/tx_validator/double_spend_validator.ts +++ b/yarn-project/p2p/src/tx_validator/double_spend_validator.ts @@ -3,7 +3,7 @@ import { Fr } from '@aztec/circuits.js'; import { createLogger } from '@aztec/foundation/log'; export interface NullifierSource { - getNullifierIndex: (nullifier: Fr) => Promise; + getNullifierIndices: (nullifiers: Buffer[]) => Promise; } export class DoubleSpendTxValidator implements TxValidator { @@ -36,9 +36,7 @@ export class DoubleSpendTxValidator implements TxValidator { } async #uniqueNullifiers(tx: AnyTx, thisBlockNullifiers: Set): Promise { - const nullifiers = (tx instanceof Tx ? tx.data.getNonEmptyNullifiers() : tx.txEffect.nullifiers).map(x => - x.toBigInt(), - ); + const nullifiers = (tx instanceof Tx ? tx.data.getNonEmptyNullifiers() : tx.txEffect.nullifiers); // Ditch this tx if it has repeated nullifiers const uniqueNullifiers = new Set(nullifiers); @@ -48,7 +46,8 @@ export class DoubleSpendTxValidator implements TxValidator { } if (this.isValidatingBlock) { - for (const nullifier of nullifiers) { + // TODO: remove all this type casting + for (const nullifier of nullifiers.map(n => n.toBigInt())) { if (thisBlockNullifiers.has(nullifier)) { this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier in the same block`); return false; @@ -58,7 +57,7 @@ export class DoubleSpendTxValidator implements TxValidator { } } - const nullifierIndexes = await Promise.all(nullifiers.map(n => this.#nullifierSource.getNullifierIndex(new Fr(n)))); + const nullifierIndexes = await this.#nullifierSource.getNullifierIndices(nullifiers.map(n => n.toBuffer())); const hasDuplicates = nullifierIndexes.some(index => index !== undefined); if (hasDuplicates) { diff --git a/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts b/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts index dd36e4ebc3d9..13d02329ff17 100644 --- a/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts +++ b/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts @@ -29,8 +29,8 @@ export class TxValidatorFactory { private enforceFees: boolean, ) { this.nullifierSource = { - getNullifierIndex: nullifier => - this.committedDb.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]).then(x => x[0]), + getNullifierIndices: nullifiers => + this.committedDb.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers).then(x => x.filter(index => index !== undefined) as bigint[]), }; this.publicStateSource = { @@ -52,8 +52,8 @@ export class TxValidatorFactory { validatorForProcessedTxs(fork: MerkleTreeReadOperations): TxValidator { return new DoubleSpendTxValidator({ - getNullifierIndex: nullifier => - fork.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]).then(x => x[0]), + getNullifierIndices: nullifiers => + fork.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers).then(x => x.filter(index => index !== undefined) as bigint[]), }); } }