From 0b632d88f7e0c481bdc778a931d45e6685e02185 Mon Sep 17 00:00:00 2001 From: spypsy Date: Tue, 1 Oct 2024 09:41:29 +0000 Subject: [PATCH 1/2] fix: reuse tree store in world state synchronizer --- yarn-project/kv-store/src/lmdb/store.ts | 18 +++++++++-- .../server_world_state_synchronizer.ts | 31 +++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/yarn-project/kv-store/src/lmdb/store.ts b/yarn-project/kv-store/src/lmdb/store.ts index d789778c7e08..1c5e53f71ffa 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 9cd2d8611048..41662a50d2c3 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 @@ -17,7 +17,7 @@ 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 { AztecLmdbStore } from '@aztec/kv-store/lmdb'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { @@ -48,6 +48,7 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { private pausedResolve?: () => void = undefined; private currentState: WorldStateRunningState = WorldStateRunningState.IDLE; private blockNumber: AztecSingleton; + private treeMemStore: AztecLmdbStore | null = null; constructor( store: AztecKVStore, @@ -64,6 +65,13 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { }); } + private getTreeMemStore(): AztecLmdbStore { + if (!this.treeMemStore) { + this.treeMemStore = AztecLmdbStore.open(undefined, true); + } + return this.treeMemStore; + } + public getLatest(): MerkleTreeAdminOperations { return new MerkleTreeAdminOperationsFacade(this.merkleTreeDb, true); } @@ -303,13 +311,24 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { * @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 store = this.getTreeMemStore(); const tree = new StandardTree(store, new SHA256Trunc(), 'temp_in_hash_check', L1_TO_L2_MSG_SUBTREE_HEIGHT, 0n, Fr); - await tree.appendLeaves(l1ToL2Messages); - if (!tree.getRoot(true).equals(inHash)) { - throw new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash'); + let error: Error | null = null; + try { + await tree.appendLeaves(l1ToL2Messages); + + if (!tree.getRoot(true).equals(inHash)) { + error = new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash'); + } + } catch (e) { + error = e as Error; + } finally { + await store.clear(); + } + + if (error instanceof Error) { + throw error; } - await store.delete(); } } From 9e3c07031407ae09abb25f276a5451977ddc357d Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 2 Oct 2024 08:21:22 +0000 Subject: [PATCH 2/2] use tree calculator --- .../server_world_state_synchronizer.ts | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) 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 41662a50d2c3..cb4804eb0826 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 { AztecLmdbStore } from '@aztec/kv-store/lmdb'; -import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc } from '@aztec/merkle-tree'; import { MerkleTreeAdminOperationsFacade, @@ -48,7 +48,6 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { private pausedResolve?: () => void = undefined; private currentState: WorldStateRunningState = WorldStateRunningState.IDLE; private blockNumber: AztecSingleton; - private treeMemStore: AztecLmdbStore | null = null; constructor( store: AztecKVStore, @@ -65,13 +64,6 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { }); } - private getTreeMemStore(): AztecLmdbStore { - if (!this.treeMemStore) { - this.treeMemStore = AztecLmdbStore.open(undefined, true); - } - return this.treeMemStore; - } - public getLatest(): MerkleTreeAdminOperations { return new MerkleTreeAdminOperationsFacade(this.merkleTreeDb, true); } @@ -280,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); @@ -310,25 +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 = this.getTreeMemStore(); - const tree = new StandardTree(store, new SHA256Trunc(), 'temp_in_hash_check', L1_TO_L2_MSG_SUBTREE_HEIGHT, 0n, Fr); - - let error: Error | null = null; - try { - await tree.appendLeaves(l1ToL2Messages); - - if (!tree.getRoot(true).equals(inHash)) { - error = new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash'); - } - } catch (e) { - error = e as Error; - } finally { - await store.clear(); - } - - if (error instanceof Error) { - throw error; + #verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Buffer) { + const treeCalculator = new MerkleTreeCalculator( + L1_TO_L2_MSG_SUBTREE_HEIGHT, + Buffer.alloc(32), + new SHA256Trunc().hash, + ); + + 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'); } } }