@@ -124,10 +124,12 @@ export class NoteStore {
124124 * specified block number. It restores any notes that were nullified after the given block
125125 * and deletes any active notes created after that block.
126126 *
127+ * IMPORTANT: This method must be called within a transaction to ensure atomicity.
128+ *
127129 * @param blockNumber - The new chain tip after a reorg
128130 * @param synchedBlockNumber - The block number up to which PXE managed to sync before the reorg happened.
129131 */
130- public async rollbackNotesAndNullifiers ( blockNumber : number , synchedBlockNumber : number ) : Promise < void > {
132+ public async rollback ( blockNumber : number , synchedBlockNumber : number ) : Promise < void > {
131133 await this . #rewindNullifiersAfterBlock( blockNumber , synchedBlockNumber ) ;
132134 await this . #deleteActiveNotesAfterBlock( blockNumber ) ;
133135 }
@@ -140,24 +142,22 @@ export class NoteStore {
140142 *
141143 * @param blockNumber - Notes created after this block number will be deleted
142144 */
143- #deleteActiveNotesAfterBlock( blockNumber : number ) : Promise < void > {
144- return this . #store. transactionAsync ( async ( ) => {
145- const notes = await toArray ( this . #notes. valuesAsync ( ) ) ;
146- for ( const note of notes ) {
147- const noteDao = NoteDao . fromBuffer ( note ) ;
148- if ( noteDao . l2BlockNumber > blockNumber ) {
149- const noteIndex = toBufferBE ( noteDao . index , 32 ) . toString ( 'hex' ) ;
150- await this . #notes. delete ( noteIndex ) ;
151- await this . #notesToScope. delete ( noteIndex ) ;
152- await this . #nullifierToNoteId. delete ( noteDao . siloedNullifier . toString ( ) ) ;
153- const scopes = await toArray ( this . #scopes. keysAsync ( ) ) ;
154- for ( const scope of scopes ) {
155- await this . #notesByContractAndScope. get ( scope ) ! . deleteValue ( noteDao . contractAddress . toString ( ) , noteIndex ) ;
156- await this . #notesByStorageSlotAndScope. get ( scope ) ! . deleteValue ( noteDao . storageSlot . toString ( ) , noteIndex ) ;
157- }
145+ async #deleteActiveNotesAfterBlock( blockNumber : number ) : Promise < void > {
146+ const notes = await toArray ( this . #notes. valuesAsync ( ) ) ;
147+ for ( const note of notes ) {
148+ const noteDao = NoteDao . fromBuffer ( note ) ;
149+ if ( noteDao . l2BlockNumber > blockNumber ) {
150+ const noteIndex = toBufferBE ( noteDao . index , 32 ) . toString ( 'hex' ) ;
151+ await this . #notes. delete ( noteIndex ) ;
152+ await this . #notesToScope. delete ( noteIndex ) ;
153+ await this . #nullifierToNoteId. delete ( noteDao . siloedNullifier . toString ( ) ) ;
154+ const scopes = await toArray ( this . #scopes. keysAsync ( ) ) ;
155+ for ( const scope of scopes ) {
156+ await this . #notesByContractAndScope. get ( scope ) ! . deleteValue ( noteDao . contractAddress . toString ( ) , noteIndex ) ;
157+ await this . #notesByStorageSlotAndScope. get ( scope ) ! . deleteValue ( noteDao . storageSlot . toString ( ) , noteIndex ) ;
158158 }
159159 }
160- } ) ;
160+ }
161161 }
162162
163163 /**
@@ -171,50 +171,52 @@ export class NoteStore {
171171 * @param synchedBlockNumber - Upper bound for the block range to process
172172 */
173173 async #rewindNullifiersAfterBlock( blockNumber : number , synchedBlockNumber : number ) : Promise < void > {
174- await this . #store. transactionAsync ( async ( ) => {
175- const nullifiersToUndo : string [ ] = [ ] ;
176- const currentBlockNumber = blockNumber + 1 ;
177- for ( let i = currentBlockNumber ; i <= synchedBlockNumber ; i ++ ) {
178- nullifiersToUndo . push ( ...( await toArray ( this . #nullifiersByBlockNumber. getValuesAsync ( i ) ) ) ) ;
179- }
180- const notesIndexesToReinsert = await Promise . all (
181- nullifiersToUndo . map ( nullifier => this . #nullifiedNotesByNullifier. getAsync ( nullifier ) ) ,
182- ) ;
183- const notNullNoteIndexes = notesIndexesToReinsert . filter ( noteIndex => noteIndex != undefined ) ;
184- const nullifiedNoteBuffers = await Promise . all (
185- notNullNoteIndexes . map ( noteIndex => this . #nullifiedNotes. getAsync ( noteIndex ! ) ) ,
186- ) ;
187- const noteDaos = nullifiedNoteBuffers
188- . filter ( buffer => buffer != undefined )
189- . map ( buffer => NoteDao . fromBuffer ( buffer ! ) ) ;
190-
191- for ( const dao of noteDaos ) {
192- const noteIndex = toBufferBE ( dao . index , 32 ) . toString ( 'hex' ) ;
193- await this . #notes. set ( noteIndex , dao . toBuffer ( ) ) ;
194- await this . #nullifierToNoteId. set ( dao . siloedNullifier . toString ( ) , noteIndex ) ;
174+ const nullifiersToUndo : string [ ] = [ ] ;
175+ const currentBlockNumber = blockNumber + 1 ;
176+ for ( let i = currentBlockNumber ; i <= synchedBlockNumber ; i ++ ) {
177+ nullifiersToUndo . push ( ...( await toArray ( this . #nullifiersByBlockNumber. getValuesAsync ( i ) ) ) ) ;
178+ }
179+ const notesIndexesToReinsert = await Promise . all (
180+ nullifiersToUndo . map ( nullifier => this . #nullifiedNotesByNullifier. getAsync ( nullifier ) ) ,
181+ ) ;
182+ const notNullNoteIndexes = notesIndexesToReinsert . filter ( noteIndex => noteIndex != undefined ) ;
183+ const nullifiedNoteBuffers = await Promise . all (
184+ notNullNoteIndexes . map ( noteIndex => this . #nullifiedNotes. getAsync ( noteIndex ! ) ) ,
185+ ) ;
186+ const noteDaos = nullifiedNoteBuffers
187+ . filter ( buffer => buffer != undefined )
188+ . map ( buffer => NoteDao . fromBuffer ( buffer ! ) ) ;
195189
196- const scopes = await toArray ( this . #nullifiedNotesToScope. getValuesAsync ( noteIndex ) ) ;
190+ for ( const dao of noteDaos ) {
191+ const noteIndex = toBufferBE ( dao . index , 32 ) . toString ( 'hex' ) ;
197192
198- if ( scopes . length === 0 ) {
199- // We should never run into this error because notes always have a scope assigned to them - either on initial
200- // insertion via `addNotes` or when removing their nullifiers.
201- throw new Error ( `No scopes found for nullified note with index ${ noteIndex } ` ) ;
202- }
193+ const scopes = await toArray ( this . #nullifiedNotesToScope. getValuesAsync ( noteIndex ) ) ;
203194
204- for ( const scope of scopes ) {
205- await this . #notesByContractAndScope . get ( scope . toString ( ) ) ! . set ( dao . contractAddress . toString ( ) , noteIndex ) ;
206- await this . #notesByStorageSlotAndScope . get ( scope . toString ( ) ) ! . set ( dao . storageSlot . toString ( ) , noteIndex ) ;
207- await this . #notesToScope . set ( noteIndex , scope ) ;
208- }
195+ if ( scopes . length === 0 ) {
196+ // We should never run into this error because notes always have a scope assigned to them - either on initial
197+ // insertion via `addNotes` or when removing their nullifiers.
198+ throw new Error ( `No scopes found for nullified note with index ${ noteIndex } ` ) ;
199+ }
209200
210- await this . #nullifiedNotes . delete ( noteIndex ) ;
211- await this . #nullifiedNotesToScope . delete ( noteIndex ) ;
212- await this . #nullifiersByBlockNumber . deleteValue ( dao . l2BlockNumber , dao . siloedNullifier . toString ( ) ) ;
213- await this . #nullifiedNotesByContract . deleteValue ( dao . contractAddress . toString ( ) , noteIndex ) ;
214- await this . #nullifiedNotesByStorageSlot . deleteValue ( dao . storageSlot . toString ( ) , noteIndex ) ;
215- await this . #nullifiedNotesByNullifier . delete ( dao . siloedNullifier . toString ( ) ) ;
201+ for ( const scope of scopes ) {
202+ await Promise . all ( [
203+ this . #notesByContractAndScope . get ( scope . toString ( ) ) ! . set ( dao . contractAddress . toString ( ) , noteIndex ) ,
204+ this . #notesByStorageSlotAndScope . get ( scope . toString ( ) ) ! . set ( dao . storageSlot . toString ( ) , noteIndex ) ,
205+ this . #notesToScope . set ( noteIndex , scope ) ,
206+ ] ) ;
216207 }
217- } ) ;
208+
209+ await Promise . all ( [
210+ this . #notes. set ( noteIndex , dao . toBuffer ( ) ) ,
211+ this . #nullifierToNoteId. set ( dao . siloedNullifier . toString ( ) , noteIndex ) ,
212+ this . #nullifiedNotes. delete ( noteIndex ) ,
213+ this . #nullifiedNotesToScope. delete ( noteIndex ) ,
214+ this . #nullifiersByBlockNumber. deleteValue ( dao . l2BlockNumber , dao . siloedNullifier . toString ( ) ) ,
215+ this . #nullifiedNotesByContract. deleteValue ( dao . contractAddress . toString ( ) , noteIndex ) ,
216+ this . #nullifiedNotesByStorageSlot. deleteValue ( dao . storageSlot . toString ( ) , noteIndex ) ,
217+ this . #nullifiedNotesByNullifier. delete ( dao . siloedNullifier . toString ( ) ) ,
218+ ] ) ;
219+ }
218220 }
219221
220222 /**
0 commit comments