1
1
import { createDebugLogger } from '@aztec/foundation/log' ;
2
- import { L2Block , L2BlockContext , L2BlockDownloader , L2BlockSource , Tx , TxHash } from '@aztec/types' ;
2
+ import { AztecKVStore , AztecSingleton } from '@aztec/kv-store' ;
3
+ import {
4
+ INITIAL_L2_BLOCK_NUM ,
5
+ L2Block ,
6
+ L2BlockContext ,
7
+ L2BlockDownloader ,
8
+ L2BlockSource ,
9
+ Tx ,
10
+ TxHash ,
11
+ } from '@aztec/types' ;
3
12
4
13
import { getP2PConfigEnvVars } from '../config.js' ;
5
14
import { P2PService } from '../service/service.js' ;
@@ -102,31 +111,30 @@ export class P2PClient implements P2P {
102
111
*/
103
112
private runningPromise ! : Promise < void > ;
104
113
105
- /**
106
- * Store the ID of the latest block the client has synced to.
107
- */
108
- private currentL2BlockNum = 0 ;
109
-
110
114
private currentState = P2PClientState . IDLE ;
111
115
private syncPromise = Promise . resolve ( ) ;
112
116
private latestBlockNumberAtStart = - 1 ;
113
117
private syncResolve ?: ( ) => void = undefined ;
118
+ private synchedBlockNumber : AztecSingleton < number > ;
114
119
115
120
/**
116
121
* In-memory P2P client constructor.
122
+ * @param store - The client's instance of the KV store.
117
123
* @param l2BlockSource - P2P client's source for fetching existing blocks.
118
124
* @param txPool - The client's instance of a transaction pool. Defaults to in-memory implementation.
119
125
* @param p2pService - The concrete instance of p2p networking to use.
120
126
* @param log - A logger.
121
127
*/
122
128
constructor (
129
+ store : AztecKVStore ,
123
130
private l2BlockSource : L2BlockSource ,
124
131
private txPool : TxPool ,
125
132
private p2pService : P2PService ,
126
133
private log = createDebugLogger ( 'aztec:p2p' ) ,
127
134
) {
128
135
const { p2pBlockCheckIntervalMS : checkInterval , l2QueueSize } = getP2PConfigEnvVars ( ) ;
129
136
this . blockDownloader = new L2BlockDownloader ( l2BlockSource , l2QueueSize , checkInterval ) ;
137
+ this . synchedBlockNumber = store . createSingleton ( 'p2p_pool_last_l2_block' ) ;
130
138
}
131
139
132
140
/**
@@ -144,7 +152,7 @@ export class P2PClient implements P2P {
144
152
// get the current latest block number
145
153
this . latestBlockNumberAtStart = await this . l2BlockSource . getBlockNumber ( ) ;
146
154
147
- const blockToDownloadFrom = this . currentL2BlockNum + 1 ;
155
+ const blockToDownloadFrom = this . getSyncedBlockNum ( ) + 1 ;
148
156
149
157
// if there are blocks to be retrieved, go to a synching state
150
158
if ( blockToDownloadFrom <= this . latestBlockNumberAtStart ) {
@@ -161,6 +169,9 @@ export class P2PClient implements P2P {
161
169
this . log ( `Next block ${ blockToDownloadFrom } already beyond latest block at ${ this . latestBlockNumberAtStart } ` ) ;
162
170
}
163
171
172
+ // publish any txs in TxPool after its doing initial sync
173
+ this . syncPromise = this . syncPromise . then ( ( ) => this . publishStoredTxs ( ) ) ;
174
+
164
175
// start looking for further blocks
165
176
const blockProcess = async ( ) => {
166
177
while ( ! this . stopping ) {
@@ -171,6 +182,7 @@ export class P2PClient implements P2P {
171
182
this . runningPromise = blockProcess ( ) ;
172
183
this . blockDownloader . start ( blockToDownloadFrom ) ;
173
184
this . log ( `Started block downloader from block ${ blockToDownloadFrom } ` ) ;
185
+
174
186
return this . syncPromise ;
175
187
}
176
188
@@ -229,7 +241,7 @@ export class P2PClient implements P2P {
229
241
if ( ! ready ) {
230
242
throw new Error ( 'P2P client not ready' ) ;
231
243
}
232
- this . txPool . deleteTxs ( txHashes ) ;
244
+ await this . txPool . deleteTxs ( txHashes ) ;
233
245
}
234
246
235
247
/**
@@ -245,7 +257,7 @@ export class P2PClient implements P2P {
245
257
* @returns Block number of latest L2 Block we've synced with.
246
258
*/
247
259
public getSyncedBlockNum ( ) {
248
- return this . currentL2BlockNum ;
260
+ return this . synchedBlockNumber . get ( ) ?? INITIAL_L2_BLOCK_NUM - 1 ;
249
261
}
250
262
251
263
/**
@@ -255,7 +267,7 @@ export class P2PClient implements P2P {
255
267
public getStatus ( ) : Promise < P2PSyncState > {
256
268
return Promise . resolve ( {
257
269
state : this . currentState ,
258
- syncedToL2Block : this . currentL2BlockNum ,
270
+ syncedToL2Block : this . getSyncedBlockNum ( ) ,
259
271
} as P2PSyncState ) ;
260
272
}
261
273
@@ -264,14 +276,13 @@ export class P2PClient implements P2P {
264
276
* @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with.
265
277
* @returns Empty promise.
266
278
*/
267
- private reconcileTxPool ( blocks : L2Block [ ] ) : Promise < void > {
279
+ private async reconcileTxPool ( blocks : L2Block [ ] ) : Promise < void > {
268
280
for ( let i = 0 ; i < blocks . length ; i ++ ) {
269
281
const blockContext = new L2BlockContext ( blocks [ i ] ) ;
270
282
const txHashes = blockContext . getTxHashes ( ) ;
271
- this . txPool . deleteTxs ( txHashes ) ;
283
+ await this . txPool . deleteTxs ( txHashes ) ;
272
284
this . p2pService . settledTxs ( txHashes ) ;
273
285
}
274
- return Promise . resolve ( ) ;
275
286
}
276
287
277
288
/**
@@ -284,9 +295,11 @@ export class P2PClient implements P2P {
284
295
return Promise . resolve ( ) ;
285
296
}
286
297
await this . reconcileTxPool ( blocks ) ;
287
- this . currentL2BlockNum = blocks [ blocks . length - 1 ] . number ;
288
- this . log ( `Synched to block ${ this . currentL2BlockNum } ` ) ;
289
- if ( this . currentState === P2PClientState . SYNCHING && this . currentL2BlockNum >= this . latestBlockNumberAtStart ) {
298
+ const lastBlockNum = blocks [ blocks . length - 1 ] . number ;
299
+ await this . synchedBlockNumber . set ( lastBlockNum ) ;
300
+ this . log ( `Synched to block ${ lastBlockNum } ` ) ;
301
+
302
+ if ( this . currentState === P2PClientState . SYNCHING && lastBlockNum >= this . latestBlockNumberAtStart ) {
290
303
this . setCurrentState ( P2PClientState . RUNNING ) ;
291
304
if ( this . syncResolve !== undefined ) {
292
305
this . syncResolve ( ) ;
@@ -303,4 +316,16 @@ export class P2PClient implements P2P {
303
316
this . currentState = newState ;
304
317
this . log ( `Moved to state ${ P2PClientState [ this . currentState ] } ` ) ;
305
318
}
319
+
320
+ private async publishStoredTxs ( ) {
321
+ if ( ! this . isReady ( ) ) {
322
+ return ;
323
+ }
324
+
325
+ const txs = this . txPool . getAllTxs ( ) ;
326
+ if ( txs . length > 0 ) {
327
+ this . log ( `Publishing ${ txs . length } previously stored txs` ) ;
328
+ await Promise . all ( txs . map ( tx => this . p2pService . propagateTx ( tx ) ) ) ;
329
+ }
330
+ }
306
331
}
0 commit comments