1
1
import { AztecAddress , BlockHeader , Fr , PublicKey } from '@aztec/circuits.js' ;
2
2
import { computeGlobalsHash } from '@aztec/circuits.js/abis' ;
3
+ import { SerialQueue } from '@aztec/foundation/fifo' ;
3
4
import { DebugLogger , createDebugLogger } from '@aztec/foundation/log' ;
4
5
import { InterruptibleSleep } from '@aztec/foundation/sleep' ;
5
6
import { AztecNode , INITIAL_L2_BLOCK_NUM , KeyStore , L2BlockContext , L2BlockL2Logs , LogType } from '@aztec/types' ;
@@ -24,7 +25,7 @@ export class Synchronizer {
24
25
private log : DebugLogger ;
25
26
private noteProcessorsToCatchUp : NoteProcessor [ ] = [ ] ;
26
27
27
- constructor ( private node : AztecNode , private db : PxeDatabase , logSuffix = '' ) {
28
+ constructor ( private node : AztecNode , private db : PxeDatabase , private jobQueue : SerialQueue , logSuffix = '' ) {
28
29
this . log = createDebugLogger ( logSuffix ? `aztec:pxe_synchronizer_${ logSuffix } ` : 'aztec:pxe_synchronizer' ) ;
29
30
}
30
31
@@ -36,23 +37,35 @@ export class Synchronizer {
36
37
* @param limit - The maximum number of encrypted, unencrypted logs and blocks to fetch in each iteration.
37
38
* @param retryInterval - The time interval (in ms) to wait before retrying if no data is available.
38
39
*/
39
- public async start ( limit = 1 , retryInterval = 1000 ) {
40
+ public start ( limit = 1 , retryInterval = 1000 ) {
40
41
if ( this . running ) {
41
42
return ;
42
43
}
43
44
this . running = true ;
44
45
45
- await this . initialSync ( ) ;
46
+ this . jobQueue
47
+ . put ( ( ) => this . initialSync ( ) )
48
+ . catch ( err => {
49
+ this . log . error ( `Error in synchronizer initial sync` , err ) ;
50
+ this . running = false ;
51
+ throw err ;
52
+ } ) ;
46
53
47
54
const run = async ( ) => {
48
55
while ( this . running ) {
49
- if ( this . noteProcessorsToCatchUp . length > 0 ) {
50
- // There is a note processor that needs to catch up. We hijack the main loop to catch up the note processor.
51
- await this . workNoteProcessorCatchUp ( limit , retryInterval ) ;
52
- } else {
53
- // No note processor needs to catch up. We continue with the normal flow.
54
- await this . work ( limit , retryInterval ) ;
55
- }
56
+ await this . jobQueue . put ( async ( ) => {
57
+ let moreWork = true ;
58
+ while ( moreWork && this . running ) {
59
+ if ( this . noteProcessorsToCatchUp . length > 0 ) {
60
+ // There is a note processor that needs to catch up. We hijack the main loop to catch up the note processor.
61
+ moreWork = await this . workNoteProcessorCatchUp ( limit ) ;
62
+ } else {
63
+ // No note processor needs to catch up. We continue with the normal flow.
64
+ moreWork = await this . work ( limit ) ;
65
+ }
66
+ }
67
+ } ) ;
68
+ await this . interruptibleSleep . sleep ( retryInterval ) ;
56
69
}
57
70
} ;
58
71
@@ -70,26 +83,29 @@ export class Synchronizer {
70
83
await this . db . setBlockData ( latestBlockNumber , latestBlockHeader ) ;
71
84
}
72
85
73
- protected async work ( limit = 1 , retryInterval = 1000 ) : Promise < void > {
86
+ /**
87
+ * Fetches encrypted logs and blocks from the Aztec node and processes them for all note processors.
88
+ *
89
+ * @param limit - The maximum number of encrypted, unencrypted logs and blocks to fetch in each iteration.
90
+ * @returns true if there could be more work, false if we're caught up or there was an error.
91
+ */
92
+ protected async work ( limit = 1 ) : Promise < boolean > {
74
93
const from = this . getSynchedBlockNumber ( ) + 1 ;
75
94
try {
76
95
let encryptedLogs = await this . node . getLogs ( from , limit , LogType . ENCRYPTED ) ;
77
96
if ( ! encryptedLogs . length ) {
78
- await this . interruptibleSleep . sleep ( retryInterval ) ;
79
- return ;
97
+ return false ;
80
98
}
81
99
82
100
let unencryptedLogs = await this . node . getLogs ( from , limit , LogType . UNENCRYPTED ) ;
83
101
if ( ! unencryptedLogs . length ) {
84
- await this . interruptibleSleep . sleep ( retryInterval ) ;
85
- return ;
102
+ return false ;
86
103
}
87
104
88
105
// Note: If less than `limit` encrypted logs is returned, then we fetch only that number of blocks.
89
106
const blocks = await this . node . getBlocks ( from , encryptedLogs . length ) ;
90
107
if ( ! blocks . length ) {
91
- await this . interruptibleSleep . sleep ( retryInterval ) ;
92
- return ;
108
+ return false ;
93
109
}
94
110
95
111
if ( blocks . length !== encryptedLogs . length ) {
@@ -120,21 +136,30 @@ export class Synchronizer {
120
136
for ( const noteProcessor of this . noteProcessors ) {
121
137
await noteProcessor . process ( blockContexts , encryptedLogs ) ;
122
138
}
139
+ return true ;
123
140
} catch ( err ) {
124
141
this . log . error ( `Error in synchronizer work` , err ) ;
125
- await this . interruptibleSleep . sleep ( retryInterval ) ;
142
+ return false ;
126
143
}
127
144
}
128
145
129
- protected async workNoteProcessorCatchUp ( limit = 1 , retryInterval = 1000 ) : Promise < void > {
146
+ /**
147
+ * Catch up a note processor that is lagging behind the main sync,
148
+ * e.g. because we just added a new account.
149
+ *
150
+ * @param limit - the maximum number of encrypted, unencrypted logs and blocks to fetch in each iteration.
151
+ * @returns true if there could be more work, false if we're caught up or there was an error.
152
+ */
153
+ protected async workNoteProcessorCatchUp ( limit = 1 ) : Promise < boolean > {
130
154
const noteProcessor = this . noteProcessorsToCatchUp [ 0 ] ;
131
155
const toBlockNumber = this . getSynchedBlockNumber ( ) ;
132
156
133
157
if ( noteProcessor . status . syncedToBlock >= toBlockNumber ) {
134
158
// Note processor already synched, nothing to do
135
159
this . noteProcessorsToCatchUp . shift ( ) ;
136
160
this . noteProcessors . push ( noteProcessor ) ;
137
- return ;
161
+ // could be more work if there are more note processors to catch up
162
+ return true ;
138
163
}
139
164
140
165
const from = noteProcessor . status . syncedToBlock + 1 ;
@@ -184,9 +209,10 @@ export class Synchronizer {
184
209
this . noteProcessorsToCatchUp . shift ( ) ;
185
210
this . noteProcessors . push ( noteProcessor ) ;
186
211
}
212
+ return true ;
187
213
} catch ( err ) {
188
214
this . log . error ( `Error in synchronizer workNoteProcessorCatchUp` , err ) ;
189
- await this . interruptibleSleep . sleep ( retryInterval ) ;
215
+ return false ;
190
216
}
191
217
}
192
218
0 commit comments