From 2fd4be918dd6be82c140250bb5b2479e201813b4 Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 2 Oct 2024 16:36:31 +0100 Subject: [PATCH] fix: use tree calculator in world state synchronizer (#8902) references to temp stores inside `verifyMessagesHashToInHash` were left uncleared & cause memory growth --- yarn-project/kv-store/src/lmdb/store.ts | 18 ++++++++++--- .../server_world_state_synchronizer.ts | 25 +++++++++++-------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/yarn-project/kv-store/src/lmdb/store.ts b/yarn-project/kv-store/src/lmdb/store.ts index d789778c7e0..1c5e53f71ff 100644 --- a/yarn-project/kv-store/src/lmdb/store.ts +++ b/yarn-project/kv-store/src/lmdb/store.ts @@ -144,23 +144,35 @@ export class AztecLmdbStore implements AztecKVStore { } /** - * Clears all entries in the store + * Clears all entries in the store & sub DBs. */ async clear() { + await this.#data.clearAsync(); + await this.#multiMapData.clearAsync(); await this.#rootDb.clearAsync(); } + /** + * Drops the database & sub DBs. + */ + async drop() { + await this.#data.drop(); + await this.#multiMapData.drop(); + await this.#rootDb.drop(); + } + /** * Close the database. Note, once this is closed we can no longer interact with the DB. - * Closing the root DB also closes child DBs. */ async close() { + await this.#data.close(); + await this.#multiMapData.close(); await this.#rootDb.close(); } /** Deletes this store and removes the database files from disk */ async delete() { - await this.#rootDb.drop(); + await this.drop(); await this.close(); if (this.path) { await rm(this.path, { recursive: true, force: true }); diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts index 9cd2d861104..cb4804eb082 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts @@ -10,15 +10,15 @@ import { type WorldStateSynchronizer, } from '@aztec/circuit-types'; import { type L2BlockHandledStats } from '@aztec/circuit-types/stats'; +import { MerkleTreeCalculator } from '@aztec/circuits.js'; import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants'; -import { Fr } from '@aztec/foundation/fields'; +import { type Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { promiseWithResolvers } from '@aztec/foundation/promise'; import { SerialQueue } from '@aztec/foundation/queue'; import { elapsed } from '@aztec/foundation/timer'; import { type AztecKVStore, type AztecSingleton } from '@aztec/kv-store'; -import { openTmpStore } from '@aztec/kv-store/utils'; -import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc } from '@aztec/merkle-tree'; import { MerkleTreeAdminOperationsFacade, @@ -272,7 +272,7 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { // Note that we cannot optimize this check by checking the root of the subtree after inserting the messages // to the real L1_TO_L2_MESSAGE_TREE (like we do in merkleTreeDb.handleL2BlockAndMessages(...)) because that // tree uses pedersen and we don't have access to the converted root. - await this.#verifyMessagesHashToInHash(l1ToL2Messages, l2Block.header.contentCommitment.inHash); + this.#verifyMessagesHashToInHash(l1ToL2Messages, l2Block.header.contentCommitment.inHash); // If the above check succeeds, we can proceed to handle the block. const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages); @@ -302,14 +302,19 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { * @param inHash - The inHash of the block. * @throws If the L1 to L2 messages do not hash to the block inHash. */ - async #verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Buffer) { - const store = openTmpStore(true); - const tree = new StandardTree(store, new SHA256Trunc(), 'temp_in_hash_check', L1_TO_L2_MSG_SUBTREE_HEIGHT, 0n, Fr); - await tree.appendLeaves(l1ToL2Messages); + #verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Buffer) { + const treeCalculator = new MerkleTreeCalculator( + L1_TO_L2_MSG_SUBTREE_HEIGHT, + Buffer.alloc(32), + new SHA256Trunc().hash, + ); - if (!tree.getRoot(true).equals(inHash)) { + const root = treeCalculator.computeTreeRoot(l1ToL2Messages.map(msg => msg.toBuffer())); + this.log.info(`root: ${root.toString('hex')}`); + this.log.info(`inHash: ${inHash.toString('hex')}`); + + if (!root.equals(inHash)) { throw new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash'); } - await store.delete(); } }