@@ -32,6 +32,7 @@ import {
32
32
import { padArrayEnd } from '@aztec/foundation/collection' ;
33
33
import { type DebugLogger , createDebugLogger } from '@aztec/foundation/log' ;
34
34
import { SerialQueue } from '@aztec/foundation/queue' ;
35
+ import { Timer , elapsed } from '@aztec/foundation/timer' ;
35
36
import { type IndexedTreeLeafPreimage } from '@aztec/foundation/trees' ;
36
37
import { type AztecKVStore , type AztecSingleton } from '@aztec/kv-store' ;
37
38
import {
@@ -45,6 +46,7 @@ import {
45
46
loadTree ,
46
47
newTree ,
47
48
} from '@aztec/merkle-tree' ;
49
+ import { type TelemetryClient } from '@aztec/telemetry-client' ;
48
50
import { type Hasher } from '@aztec/types/interfaces' ;
49
51
50
52
import {
@@ -55,6 +57,7 @@ import {
55
57
} from './merkle_tree_db.js' ;
56
58
import { type MerkleTreeMap } from './merkle_tree_map.js' ;
57
59
import { MerkleTreeOperationsFacade } from './merkle_tree_operations_facade.js' ;
60
+ import { WorldStateMetrics } from './metrics.js' ;
58
61
59
62
/**
60
63
* The nullifier tree is an indexed tree.
@@ -98,18 +101,20 @@ export class MerkleTrees implements MerkleTreeDb {
98
101
private trees : MerkleTreeMap = null as any ;
99
102
private jobQueue = new SerialQueue ( ) ;
100
103
private initialStateReference : AztecSingleton < Buffer > ;
104
+ private metrics : WorldStateMetrics ;
101
105
102
- private constructor ( private store : AztecKVStore , private log : DebugLogger ) {
106
+ private constructor ( private store : AztecKVStore , private telemetryClient : TelemetryClient , private log : DebugLogger ) {
103
107
this . initialStateReference = store . openSingleton ( 'merkle_trees_initial_state_reference' ) ;
108
+ this . metrics = new WorldStateMetrics ( telemetryClient ) ;
104
109
}
105
110
106
111
/**
107
112
* Method to asynchronously create and initialize a MerkleTrees instance.
108
113
* @param store - The db instance to use for data persistance.
109
114
* @returns - A fully initialized MerkleTrees instance.
110
115
*/
111
- public static async new ( store : AztecKVStore , log = createDebugLogger ( 'aztec:merkle_trees' ) ) {
112
- const merkleTrees = new MerkleTrees ( store , log ) ;
116
+ public static async new ( store : AztecKVStore , client : TelemetryClient , log = createDebugLogger ( 'aztec:merkle_trees' ) ) {
117
+ const merkleTrees = new MerkleTrees ( store , client , log ) ;
113
118
await merkleTrees . #init( ) ;
114
119
return merkleTrees ;
115
120
}
@@ -181,12 +186,17 @@ export class MerkleTrees implements MerkleTreeDb {
181
186
}
182
187
183
188
public async fork ( ) : Promise < MerkleTrees > {
184
- // TODO(palla/prover-node): If the underlying store is being shared with other components, we're unnecessarily
185
- // copying a lot of data unrelated to merkle trees. This may be fine for now, and we may be able to ditch backup-based
186
- // forking in favor of a more elegant proposal. But if we see this operation starts taking a lot of time, we may want
187
- // to open separate stores for merkle trees and other components.
188
- const forked = await this . store . fork ( ) ;
189
- return MerkleTrees . new ( forked , this . log ) ;
189
+ const [ ms , db ] = await elapsed ( async ( ) => {
190
+ // TODO(palla/prover-node): If the underlying store is being shared with other components, we're unnecessarily
191
+ // copying a lot of data unrelated to merkle trees. This may be fine for now, and we may be able to ditch backup-based
192
+ // forking in favor of a more elegant proposal. But if we see this operation starts taking a lot of time, we may want
193
+ // to open separate stores for merkle trees and other components.
194
+ const forked = await this . store . fork ( ) ;
195
+ return MerkleTrees . new ( forked , this . telemetryClient , this . log ) ;
196
+ } ) ;
197
+
198
+ this . metrics . recordForkDuration ( ms ) ;
199
+ return db ;
190
200
}
191
201
192
202
public async delete ( ) {
@@ -581,6 +591,8 @@ export class MerkleTrees implements MerkleTreeDb {
581
591
* @param l1ToL2Messages - The L1 to L2 messages for the block.
582
592
*/
583
593
async #handleL2BlockAndMessages( l2Block : L2Block , l1ToL2Messages : Fr [ ] ) : Promise < HandleL2BlockAndMessagesResult > {
594
+ const timer = new Timer ( ) ;
595
+
584
596
const treeRootWithIdPairs = [
585
597
[ l2Block . header . state . partial . nullifierTree . root , MerkleTreeId . NULLIFIER_TREE ] ,
586
598
[ l2Block . header . state . partial . noteHashTree . root , MerkleTreeId . NOTE_HASH_TREE ] ,
@@ -664,10 +676,13 @@ export class MerkleTrees implements MerkleTreeDb {
664
676
) ;
665
677
} else {
666
678
this . log . debug ( `Tree ${ treeName } synched with size ${ info . size } root ${ rootStr } ` ) ;
679
+ this . metrics . recordTreeSize ( treeName , info . size ) ;
667
680
}
668
681
}
669
682
await this . #snapshot( l2Block . number ) ;
670
683
684
+ this . metrics . recordDbSize ( this . store . estimateSize ( ) . bytes ) ;
685
+ this . metrics . recordSyncDuration ( ourBlock ? 'commit' : 'rollback_and_update' , timer ) ;
671
686
return { isBlockOurs : ourBlock } ;
672
687
}
673
688
0 commit comments