@aztec/p2p 0.86.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  2. package/dest/client/factory.d.ts +4 -1
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +16 -14
  5. package/dest/client/index.d.ts +1 -0
  6. package/dest/client/index.d.ts.map +1 -1
  7. package/dest/client/index.js +1 -0
  8. package/dest/client/interface.d.ts +155 -0
  9. package/dest/client/interface.d.ts.map +1 -0
  10. package/dest/client/interface.js +9 -0
  11. package/dest/client/p2p_client.d.ts +26 -164
  12. package/dest/client/p2p_client.d.ts.map +1 -1
  13. package/dest/client/p2p_client.js +185 -114
  14. package/dest/config.d.ts +5 -6
  15. package/dest/config.d.ts.map +1 -1
  16. package/dest/config.js +6 -11
  17. package/dest/enr/generate-enr.d.ts +9 -1
  18. package/dest/enr/generate-enr.d.ts.map +1 -1
  19. package/dest/enr/generate-enr.js +24 -2
  20. package/dest/index.d.ts +1 -0
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +1 -0
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +2 -0
  24. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +4 -4
  26. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -0
  27. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  28. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +8 -2
  29. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -0
  30. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  31. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +5 -2
  32. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  33. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  34. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +4 -0
  35. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  36. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +50 -14
  37. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +3 -0
  38. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  39. package/dest/mem_pools/tx_pool/memory_tx_pool.js +9 -0
  40. package/dest/mem_pools/tx_pool/tx_pool.d.ts +9 -0
  41. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  42. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +13 -5
  44. package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
  45. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +1 -1
  46. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  47. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  48. package/dest/msg_validators/tx_validator/data_validator.js +15 -14
  49. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +0 -2
  50. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  51. package/dest/msg_validators/tx_validator/double_spend_validator.js +2 -2
  52. package/dest/msg_validators/tx_validator/factory.d.ts +14 -0
  53. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
  54. package/dest/msg_validators/tx_validator/factory.js +62 -0
  55. package/dest/msg_validators/tx_validator/gas_validator.js +3 -3
  56. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +8 -4
  57. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  58. package/dest/msg_validators/tx_validator/metadata_validator.js +35 -17
  59. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  60. package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
  61. package/dest/msg_validators/tx_validator/tx_proof_validator.js +1 -1
  62. package/dest/services/discv5/discV5_service.d.ts +2 -2
  63. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  64. package/dest/services/discv5/discV5_service.js +9 -13
  65. package/dest/services/dummy_service.d.ts +3 -3
  66. package/dest/services/dummy_service.d.ts.map +1 -1
  67. package/dest/services/dummy_service.js +6 -1
  68. package/dest/services/encoding.d.ts +1 -3
  69. package/dest/services/encoding.d.ts.map +1 -1
  70. package/dest/services/libp2p/libp2p_service.d.ts +4 -2
  71. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  72. package/dest/services/libp2p/libp2p_service.js +94 -88
  73. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  74. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  75. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  76. package/dest/services/peer-manager/peer_manager.js +11 -2
  77. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  78. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -2
  79. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  80. package/dest/services/reqresp/connection-sampler/connection_sampler.js +41 -21
  81. package/dest/services/reqresp/interface.d.ts +1 -3
  82. package/dest/services/reqresp/interface.d.ts.map +1 -1
  83. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  84. package/dest/services/reqresp/protocols/goodbye.d.ts +0 -2
  85. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  86. package/dest/services/reqresp/protocols/goodbye.js +1 -1
  87. package/dest/services/reqresp/protocols/ping.d.ts +0 -2
  88. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
  89. package/dest/services/reqresp/protocols/status.d.ts +0 -2
  90. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  91. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  92. package/dest/services/reqresp/reqresp.d.ts +1 -3
  93. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  94. package/dest/services/reqresp/reqresp.js +13 -10
  95. package/dest/services/service.d.ts +4 -3
  96. package/dest/services/service.d.ts.map +1 -1
  97. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  98. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  99. package/dest/test-helpers/make-test-p2p-clients.js +2 -2
  100. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  101. package/dest/test-helpers/reqresp-nodes.js +1 -1
  102. package/dest/testbench/p2p_client_testbench_worker.js +11 -6
  103. package/dest/testbench/testbench.js +1 -1
  104. package/dest/testbench/worker_client_manager.d.ts +0 -1
  105. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  106. package/dest/testbench/worker_client_manager.js +2 -2
  107. package/dest/types/index.d.ts +1 -0
  108. package/dest/types/index.d.ts.map +1 -1
  109. package/dest/types/index.js +1 -0
  110. package/dest/versioning.d.ts +2 -2
  111. package/dest/versioning.d.ts.map +1 -1
  112. package/dest/versioning.js +6 -1
  113. package/package.json +15 -15
  114. package/src/bootstrap/bootstrap.ts +1 -1
  115. package/src/client/factory.ts +38 -33
  116. package/src/client/index.ts +1 -0
  117. package/src/client/interface.ts +186 -0
  118. package/src/client/p2p_client.ts +226 -287
  119. package/src/config.ts +11 -18
  120. package/src/enr/generate-enr.ts +35 -3
  121. package/src/index.ts +1 -0
  122. package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -0
  123. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +4 -4
  124. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +11 -4
  125. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +10 -3
  126. package/src/mem_pools/attestation_pool/mocks.ts +2 -2
  127. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +79 -34
  128. package/src/mem_pools/tx_pool/memory_tx_pool.ts +16 -1
  129. package/src/mem_pools/tx_pool/tx_pool.ts +12 -0
  130. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +9 -3
  131. package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
  132. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
  133. package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
  134. package/src/msg_validators/tx_validator/data_validator.ts +24 -18
  135. package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
  136. package/src/msg_validators/tx_validator/factory.ts +94 -0
  137. package/src/msg_validators/tx_validator/gas_validator.ts +3 -3
  138. package/src/msg_validators/tx_validator/metadata_validator.ts +50 -14
  139. package/src/msg_validators/tx_validator/phases_validator.ts +6 -2
  140. package/src/msg_validators/tx_validator/tx_proof_validator.ts +1 -1
  141. package/src/services/discv5/discV5_service.ts +14 -12
  142. package/src/services/dummy_service.ts +8 -2
  143. package/src/services/libp2p/libp2p_service.ts +102 -111
  144. package/src/services/peer-manager/metrics.ts +4 -1
  145. package/src/services/peer-manager/peer_manager.ts +18 -1
  146. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +5 -1
  147. package/src/services/reqresp/connection-sampler/connection_sampler.ts +42 -19
  148. package/src/services/reqresp/metrics.ts +4 -1
  149. package/src/services/reqresp/protocols/goodbye.ts +1 -1
  150. package/src/services/reqresp/rate-limiter/rate_limiter.ts +4 -1
  151. package/src/services/reqresp/reqresp.ts +12 -12
  152. package/src/services/service.ts +7 -1
  153. package/src/test-helpers/make-test-p2p-clients.ts +2 -1
  154. package/src/test-helpers/reqresp-nodes.ts +1 -1
  155. package/src/testbench/p2p_client_testbench_worker.ts +10 -4
  156. package/src/testbench/testbench.ts +1 -1
  157. package/src/testbench/worker_client_manager.ts +2 -2
  158. package/src/types/index.ts +1 -0
  159. package/src/versioning.ts +8 -1
@@ -5,13 +5,14 @@ import type {
5
5
  L2Block,
6
6
  L2BlockId,
7
7
  L2BlockSource,
8
+ L2BlockStream,
8
9
  L2BlockStreamEvent,
9
10
  L2Tips,
10
11
  PublishedL2Block,
11
12
  } from '@aztec/stdlib/block';
12
13
  import type { ContractDataSource } from '@aztec/stdlib/contract';
13
- import type { P2PApi, PeerInfo } from '@aztec/stdlib/interfaces/server';
14
- import { BlockAttestation, type BlockProposal, ConsensusPayload, type P2PClientType } from '@aztec/stdlib/p2p';
14
+ import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
15
+ import { BlockAttestation, type BlockProposal, type P2PClientType } from '@aztec/stdlib/p2p';
15
16
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
16
17
  import {
17
18
  Attributes,
@@ -30,172 +31,7 @@ import type { MemPools } from '../mem_pools/interface.js';
30
31
  import type { TxPool } from '../mem_pools/tx_pool/index.js';
31
32
  import { ReqRespSubProtocol } from '../services/reqresp/interface.js';
32
33
  import type { P2PService } from '../services/service.js';
33
-
34
- /**
35
- * Enum defining the possible states of the p2p client.
36
- */
37
- export enum P2PClientState {
38
- IDLE,
39
- SYNCHING,
40
- RUNNING,
41
- STOPPED,
42
- }
43
-
44
- /**
45
- * The synchronization status of the P2P client.
46
- */
47
- export interface P2PSyncState {
48
- /**
49
- * The current state of the p2p client.
50
- */
51
- state: P2PClientState;
52
- /**
53
- * The block number that the p2p client is synced to.
54
- */
55
- syncedToL2Block: L2BlockId;
56
- }
57
-
58
- /**
59
- * Interface of a P2P client.
60
- **/
61
- export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
62
- /**
63
- * Broadcasts a block proposal to other peers.
64
- *
65
- * @param proposal - the block proposal
66
- */
67
- broadcastProposal(proposal: BlockProposal): void;
68
-
69
- /**
70
- * Registers a callback from the validator client that determines how to behave when
71
- * foreign block proposals are received
72
- *
73
- * @param handler - A function taking a received block proposal and producing an attestation
74
- */
75
- // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
76
- // ^ This pattern is not my favorite (md)
77
- registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
78
-
79
- /**
80
- * Request a list of transactions from another peer by their tx hashes.
81
- * @param txHashes - Hashes of the txs to query.
82
- * @returns A list of transactions or undefined if the transactions are not found.
83
- */
84
- requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
85
-
86
- /**
87
- * Request a transaction from another peer by its tx hash.
88
- * @param txHash - Hash of the tx to query.
89
- */
90
- requestTxByHash(txHash: TxHash): Promise<Tx | undefined>;
91
-
92
- /**
93
- * Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers.
94
- * @param tx - The transaction.
95
- **/
96
- sendTx(tx: Tx): Promise<void>;
97
-
98
- /**
99
- * Adds transactions to the pool. Does not send to peers or validate the tx.
100
- * @param txs - The transactions.
101
- **/
102
- addTxs(txs: Tx[]): Promise<void>;
103
-
104
- /**
105
- * Deletes 'txs' from the pool, given hashes.
106
- * NOT used if we use sendTx as reconcileTxPool will handle this.
107
- * @param txHashes - Hashes to check.
108
- **/
109
- deleteTxs(txHashes: TxHash[]): Promise<void>;
110
-
111
- /**
112
- * Returns a transaction in the transaction pool by its hash.
113
- * @param txHash - Hash of tx to return.
114
- * @returns A single tx or undefined.
115
- */
116
- getTxByHashFromPool(txHash: TxHash): Promise<Tx | undefined>;
117
-
118
- /**
119
- * Returns transactions in the transaction pool by hash.
120
- * @param txHashes - Hashes of txs to return.
121
- * @returns An array of txs or undefined.
122
- */
123
- getTxsByHashFromPool(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
124
-
125
- /**
126
- * Checks if transactions exist in the pool
127
- * @param txHashes - The hashes of the transactions to check for
128
- * @returns True or False for each hash
129
- */
130
- hasTxsInPool(txHashes: TxHash[]): Promise<boolean[]>;
131
-
132
- /**
133
- * Returns a transaction in the transaction pool by its hash, requesting it from the network if it is not found.
134
- * @param txHash - Hash of tx to return.
135
- * @returns A single tx or undefined.
136
- */
137
- getTxByHash(txHash: TxHash): Promise<Tx | undefined>;
138
-
139
- /**
140
- * Returns transactions in the transaction pool by hash, requesting from the network if not found.
141
- * @param txHashes - Hashes of tx to return.
142
- * @returns An array of tx or undefined.
143
- */
144
- getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
145
-
146
- /**
147
- * Returns an archived transaction from the transaction pool by its hash.
148
- * @param txHash - Hash of tx to return.
149
- * @returns A single tx or undefined.
150
- */
151
- getArchivedTxByHash(txHash: TxHash): Promise<Tx | undefined>;
152
-
153
- /**
154
- * Returns whether the given tx hash is flagged as pending or mined.
155
- * @param txHash - Hash of the tx to query.
156
- * @returns Pending or mined depending on its status, or undefined if not found.
157
- */
158
- getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | undefined>;
159
-
160
- /** Returns an iterator over pending txs on the mempool. */
161
- iteratePendingTxs(): AsyncIterableIterator<Tx>;
162
-
163
- /** Returns the number of pending txs in the mempool. */
164
- getPendingTxCount(): Promise<number>;
165
-
166
- /**
167
- * Starts the p2p client.
168
- * @returns A promise signalling the completion of the block sync.
169
- */
170
- start(): Promise<void>;
171
-
172
- /**
173
- * Stops the p2p client.
174
- * @returns A promise signalling the completion of the stop process.
175
- */
176
- stop(): Promise<void>;
177
-
178
- /**
179
- * Indicates if the p2p client is ready for transaction submission.
180
- * @returns A boolean flag indicating readiness.
181
- */
182
- isReady(): boolean;
183
-
184
- /**
185
- * Returns the current status of the p2p client.
186
- */
187
- getStatus(): Promise<P2PSyncState>;
188
-
189
- /**
190
- * Returns the ENR of this node, if any.
191
- */
192
- getEnr(): ENR | undefined;
193
-
194
- /** Identifies a p2p client. */
195
- isP2PClient(): true;
196
-
197
- updateP2PConfig(config: Partial<P2PConfig>): Promise<void>;
198
- };
34
+ import { type P2P, P2PClientState, type P2PSyncState } from './interface.js';
199
35
 
200
36
  /**
201
37
  * The P2P client implementation.
@@ -212,69 +48,55 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
212
48
  private syncResolve?: () => void = undefined;
213
49
  private latestBlockNumberAtStart = -1;
214
50
  private provenBlockNumberAtStart = -1;
51
+ private finalizedBlockNumberAtStart = -1;
215
52
 
216
53
  private synchedBlockHashes: AztecAsyncMap<number, string>;
217
54
  private synchedLatestBlockNumber: AztecAsyncSingleton<number>;
218
55
  private synchedProvenBlockNumber: AztecAsyncSingleton<number>;
56
+ private synchedFinalizedBlockNumber: AztecAsyncSingleton<number>;
219
57
  private synchedLatestSlot: AztecAsyncSingleton<bigint>;
220
58
 
221
59
  private txPool: TxPool;
222
60
  private attestationPool: T extends P2PClientType.Full ? AttestationPool : undefined;
223
61
 
224
- /** How many slots to keep attestations for. */
225
- private keepAttestationsInPoolFor: number;
226
- /** How many slots to keep proven txs for. */
227
- private keepProvenTxsFor: number;
228
-
229
- private blockStream;
230
-
231
62
  private config: P2PConfig;
232
63
 
64
+ private blockStream: L2BlockStream | undefined;
65
+
233
66
  /**
234
67
  * In-memory P2P client constructor.
235
68
  * @param store - The client's instance of the KV store.
236
69
  * @param l2BlockSource - P2P client's source for fetching existing blocks.
237
70
  * @param txPool - The client's instance of a transaction pool. Defaults to in-memory implementation.
238
71
  * @param p2pService - The concrete instance of p2p networking to use.
239
- * @param keepProvenTxsFor - How many blocks have to pass after a block is proven before its txs are deleted (zero to delete immediately once proven).
240
72
  * @param log - A logger.
241
73
  */
242
74
  constructor(
243
75
  _clientType: T,
244
- store: AztecAsyncKVStore,
76
+ private store: AztecAsyncKVStore,
245
77
  private l2BlockSource: L2BlockSource & ContractDataSource,
246
78
  mempools: MemPools<T>,
247
79
  private p2pService: P2PService,
248
80
  config: Partial<P2PConfig> = {},
249
- telemetry: TelemetryClient = getTelemetryClient(),
81
+ private telemetry: TelemetryClient = getTelemetryClient(),
250
82
  private log = createLogger('p2p'),
251
83
  ) {
252
84
  super(telemetry, 'P2PClient');
253
85
 
254
- this.config = {
255
- ...getP2PDefaultConfig(),
256
- ...config,
257
- };
258
-
259
- const { keepProvenTxsInPoolFor, blockCheckIntervalMS, blockRequestBatchSize, keepAttestationsInPoolFor } =
260
- this.config;
261
- this.keepProvenTxsFor = keepProvenTxsInPoolFor;
262
- this.keepAttestationsInPoolFor = keepAttestationsInPoolFor;
263
-
264
- const tracer = telemetry.getTracer('P2PL2BlockStream');
265
- const logger = createLogger('p2p:l2-block-stream');
266
- this.blockStream = new TraceableL2BlockStream(l2BlockSource, this, this, tracer, 'P2PL2BlockStream', logger, {
267
- batchSize: blockRequestBatchSize,
268
- pollIntervalMS: blockCheckIntervalMS,
269
- });
86
+ this.config = { ...getP2PDefaultConfig(), ...config };
87
+ this.txPool = mempools.txPool;
88
+ this.attestationPool = mempools.attestationPool!;
270
89
 
90
+ // REFACTOR: Try replacing these with an L2TipsStore
271
91
  this.synchedBlockHashes = store.openMap('p2p_pool_block_hashes');
272
92
  this.synchedLatestBlockNumber = store.openSingleton('p2p_pool_last_l2_block');
273
93
  this.synchedProvenBlockNumber = store.openSingleton('p2p_pool_last_proven_l2_block');
94
+ this.synchedFinalizedBlockNumber = store.openSingleton('p2p_pool_last_finalized_l2_block');
274
95
  this.synchedLatestSlot = store.openSingleton('p2p_pool_last_l2_slot');
96
+ }
275
97
 
276
- this.txPool = mempools.txPool;
277
- this.attestationPool = mempools.attestationPool!;
98
+ public clear(): Promise<void> {
99
+ return this.store.clear();
278
100
  }
279
101
 
280
102
  public isP2PClient(): true {
@@ -299,30 +121,39 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
299
121
  public async getL2Tips(): Promise<L2Tips> {
300
122
  const latestBlockNumber = await this.getSyncedLatestBlockNum();
301
123
  let latestBlockHash: string | undefined;
124
+
302
125
  const provenBlockNumber = await this.getSyncedProvenBlockNum();
303
126
  let provenBlockHash: string | undefined;
304
127
 
128
+ const finalizedBlockNumber = await this.getSyncedFinalizedBlockNum();
129
+ let finalizedBlockHash: string | undefined;
130
+
305
131
  if (latestBlockNumber > 0) {
306
132
  latestBlockHash = await this.synchedBlockHashes.getAsync(latestBlockNumber);
307
133
  if (typeof latestBlockHash === 'undefined') {
308
- this.log.warn(`Block hash for latest block ${latestBlockNumber} not found`);
309
- throw new Error();
134
+ throw new Error(`Block hash for latest block ${latestBlockNumber} not found in p2p client`);
310
135
  }
311
136
  }
312
137
 
313
138
  if (provenBlockNumber > 0) {
314
139
  provenBlockHash = await this.synchedBlockHashes.getAsync(provenBlockNumber);
315
140
  if (typeof provenBlockHash === 'undefined') {
316
- this.log.warn(`Block hash for proven block ${provenBlockNumber} not found`);
317
- throw new Error();
141
+ throw new Error(`Block hash for proven block ${provenBlockNumber} not found in p2p client`);
142
+ }
143
+ }
144
+
145
+ if (finalizedBlockNumber > 0) {
146
+ finalizedBlockHash = await this.synchedBlockHashes.getAsync(finalizedBlockNumber);
147
+ if (typeof finalizedBlockHash === 'undefined') {
148
+ throw new Error(`Block hash for finalized block ${finalizedBlockNumber} not found in p2p client`);
318
149
  }
319
150
  }
320
151
 
321
- return Promise.resolve({
152
+ return {
322
153
  latest: { hash: latestBlockHash!, number: latestBlockNumber },
323
154
  proven: { hash: provenBlockHash!, number: provenBlockNumber },
324
- finalized: { hash: provenBlockHash!, number: provenBlockNumber },
325
- });
155
+ finalized: { hash: finalizedBlockHash!, number: finalizedBlockNumber },
156
+ };
326
157
  }
327
158
 
328
159
  public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
@@ -331,16 +162,23 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
331
162
  case 'blocks-added':
332
163
  await this.handleLatestL2Blocks(event.blocks);
333
164
  break;
334
- case 'chain-finalized':
165
+ case 'chain-finalized': {
335
166
  // TODO (alexg): I think we can prune the block hashes map here
167
+ await this.setBlockHash(event.block);
168
+ const from = (await this.getSyncedFinalizedBlockNum()) + 1;
169
+ const limit = event.block.number - from + 1;
170
+ if (limit > 0) {
171
+ await this.handleFinalizedL2Blocks(await this.l2BlockSource.getBlocks(from, limit));
172
+ }
336
173
  break;
174
+ }
337
175
  case 'chain-proven': {
338
- const from = (await this.getSyncedProvenBlockNum()) + 1;
339
- const limit = event.block.number - from + 1;
340
- await this.handleProvenL2Blocks(await this.l2BlockSource.getBlocks(from, limit));
176
+ await this.setBlockHash(event.block);
177
+ await this.synchedProvenBlockNumber.set(event.block.number);
341
178
  break;
342
179
  }
343
180
  case 'chain-pruned':
181
+ await this.setBlockHash(event.block);
344
182
  await this.handlePruneL2Blocks(event.block.number);
345
183
  break;
346
184
  default: {
@@ -350,6 +188,12 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
350
188
  }
351
189
  }
352
190
 
191
+ private async setBlockHash(block: L2BlockId): Promise<void> {
192
+ if (block.hash !== undefined) {
193
+ await this.synchedBlockHashes.set(block.number, block.hash.toString());
194
+ }
195
+ }
196
+
353
197
  #assertIsReady() {
354
198
  // this.log.info('Checking if p2p client is ready, current state: ', this.currentState);
355
199
  if (!this.isReady()) {
@@ -370,33 +214,74 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
370
214
  }
371
215
 
372
216
  // get the current latest block numbers
373
- this.latestBlockNumberAtStart = await this.l2BlockSource.getBlockNumber();
374
- this.provenBlockNumberAtStart = await this.l2BlockSource.getProvenBlockNumber();
217
+ const latestBlockNumbers = await this.l2BlockSource.getL2Tips();
218
+ this.latestBlockNumberAtStart = latestBlockNumbers.latest.number;
219
+ this.provenBlockNumberAtStart = latestBlockNumbers.proven.number;
220
+ this.finalizedBlockNumberAtStart = latestBlockNumbers.finalized.number;
375
221
 
376
222
  const syncedLatestBlock = (await this.getSyncedLatestBlockNum()) + 1;
377
223
  const syncedProvenBlock = (await this.getSyncedProvenBlockNum()) + 1;
224
+ const syncedFinalizedBlock = (await this.getSyncedFinalizedBlockNum()) + 1;
378
225
 
379
- // if there are blocks to be retrieved, go to a synching state
380
- if (syncedLatestBlock <= this.latestBlockNumberAtStart || syncedProvenBlock <= this.provenBlockNumberAtStart) {
226
+ if (
227
+ (await this.txPool.isEmpty()) &&
228
+ (this.attestationPool === undefined || (await this.attestationPool?.isEmpty()))
229
+ ) {
230
+ // if mempools are empty, we don't care about syncing prior blocks
231
+ this.initBlockStream(this.latestBlockNumberAtStart);
232
+ this.setCurrentState(P2PClientState.RUNNING);
233
+ this.syncPromise = Promise.resolve();
234
+ await this.p2pService.start();
235
+ this.log.info(`Starting p2p client from block ${this.latestBlockNumberAtStart} with empty mempools`);
236
+ } else if (
237
+ syncedLatestBlock <= this.latestBlockNumberAtStart ||
238
+ syncedProvenBlock <= this.provenBlockNumberAtStart ||
239
+ syncedFinalizedBlock <= this.finalizedBlockNumberAtStart
240
+ ) {
241
+ // if there are blocks to be retrieved, go to a synching state
242
+ // this gets resolved on `startServiceIfSynched`
243
+ this.initBlockStream();
381
244
  this.setCurrentState(P2PClientState.SYNCHING);
382
245
  this.syncPromise = new Promise(resolve => {
383
246
  this.syncResolve = resolve;
384
247
  });
385
- this.log.verbose(`Starting sync from ${syncedLatestBlock} (last proven ${syncedProvenBlock})`);
248
+ this.log.info(`Initiating p2p sync from ${syncedLatestBlock}`, {
249
+ syncedLatestBlock,
250
+ syncedProvenBlock,
251
+ syncedFinalizedBlock,
252
+ });
386
253
  } else {
387
254
  // if no blocks to be retrieved, go straight to running
255
+ this.initBlockStream();
388
256
  this.setCurrentState(P2PClientState.RUNNING);
389
257
  this.syncPromise = Promise.resolve();
390
258
  await this.p2pService.start();
391
- this.log.debug(`Block ${syncedLatestBlock} (proven ${syncedProvenBlock}) already beyond current block`);
259
+ this.log.info(`Starting P2P client synced to ${syncedLatestBlock}`, {
260
+ syncedLatestBlock,
261
+ syncedProvenBlock,
262
+ syncedFinalizedBlock,
263
+ });
392
264
  }
393
265
 
394
- this.blockStream.start();
395
- this.log.verbose(`Started block downloader from block ${syncedLatestBlock}`);
396
-
266
+ this.blockStream!.start();
397
267
  return this.syncPromise;
398
268
  }
399
269
 
270
+ private initBlockStream(startingBlock?: number) {
271
+ if (!this.blockStream) {
272
+ const { blockRequestBatchSize: batchSize, blockCheckIntervalMS: pollIntervalMS } = this.config;
273
+ this.blockStream = new TraceableL2BlockStream(
274
+ this.l2BlockSource,
275
+ this,
276
+ this,
277
+ this.telemetry.getTracer('P2PL2BlockStream'),
278
+ 'P2PL2BlockStream',
279
+ createLogger('p2p:l2-block-stream'),
280
+ { batchSize, pollIntervalMS, startingBlock },
281
+ );
282
+ }
283
+ }
284
+
400
285
  /**
401
286
  * Allows consumers to stop the instance of the P2P client.
402
287
  * 'ready' will now return 'false' and the running promise that keeps the client synced is interrupted.
@@ -405,7 +290,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
405
290
  this.log.debug('Stopping p2p client...');
406
291
  await this.p2pService.stop();
407
292
  this.log.debug('Stopped p2p service');
408
- await this.blockStream.stop();
293
+ await this.blockStream?.stop();
409
294
  this.log.debug('Stopped block downloader');
410
295
  await this.runningPromise;
411
296
  this.setCurrentState(P2PClientState.STOPPED);
@@ -414,7 +299,8 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
414
299
 
415
300
  /** Triggers a sync to the archiver. Used for testing. */
416
301
  public async sync() {
417
- await this.blockStream.sync();
302
+ this.initBlockStream();
303
+ await this.blockStream!.sync();
418
304
  }
419
305
 
420
306
  @trackSpan('p2pClient.broadcastProposal', async proposal => ({
@@ -423,7 +309,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
423
309
  [Attributes.BLOCK_ARCHIVE]: proposal.archive.toString(),
424
310
  [Attributes.P2P_ID]: (await proposal.p2pMessageIdentifier()).toString(),
425
311
  }))
426
- public broadcastProposal(proposal: BlockProposal): void {
312
+ public broadcastProposal(proposal: BlockProposal): Promise<void> {
427
313
  this.log.verbose(`Broadcasting proposal for slot ${proposal.slotNumber.toNumber()} to peers`);
428
314
  return this.p2pService.propagate(proposal);
429
315
  }
@@ -446,20 +332,6 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
446
332
  this.p2pService.registerBlockReceivedCallback(handler);
447
333
  }
448
334
 
449
- /**
450
- * Requests the transactions with the given hashes from the network.
451
- *
452
- * If a transaction can be retrieved, it will be returned, if not an undefined
453
- * will be returned. In place.
454
- *
455
- * @param txHashes - The hashes of the transactions to request.
456
- * @returns A promise that resolves to an array of transactions or undefined.
457
- */
458
- public async requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
459
- const res = await this.p2pService.sendBatchRequest(ReqRespSubProtocol.TX, txHashes);
460
- return Promise.resolve(res ?? []);
461
- }
462
-
463
335
  /**
464
336
  * Uses the Request Response protocol to request a transaction from the network.
465
337
  *
@@ -486,25 +358,36 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
486
358
  * Uses the batched Request Response protocol to request a set of transactions from the network.
487
359
  */
488
360
  public async requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
489
- const txs = await this.p2pService.sendBatchRequest(ReqRespSubProtocol.TX, txHashes);
361
+ const timeoutMs = 8000; // Longer timeout for now
362
+ const maxPeers = Math.min(Math.ceil(txHashes.length / 3), 10);
363
+ const maxRetryAttempts = 10; // Keep retrying within the timeout
364
+
365
+ const txs = await this.p2pService.sendBatchRequest(
366
+ ReqRespSubProtocol.TX,
367
+ txHashes,
368
+ timeoutMs,
369
+ maxPeers,
370
+ maxRetryAttempts,
371
+ );
490
372
 
491
373
  // Some transactions may return undefined, so we filter them out
492
374
  const filteredTxs = txs.filter((tx): tx is Tx => !!tx);
493
- await this.txPool.addTxs(filteredTxs);
375
+ if (filteredTxs.length > 0) {
376
+ await this.txPool.addTxs(filteredTxs);
377
+ }
494
378
  const txHashesStr = txHashes.map(tx => tx.toString()).join(', ');
495
- this.log.debug(`Received batched txs ${txHashesStr} (${txs.length} / ${txHashes.length}}) from peers`);
379
+ this.log.debug(`Requested txs ${txHashesStr} (${filteredTxs.length} / ${txHashes.length}}) from peers`);
496
380
 
497
381
  // We return all transactions, even the not found ones to the caller, such they can handle missing items themselves.
498
382
  return txs;
499
383
  }
500
384
 
501
385
  public getPendingTxs(): Promise<Tx[]> {
502
- return Promise.resolve(this.getTxs('pending'));
386
+ return this.getTxs('pending');
503
387
  }
504
388
 
505
- public async getPendingTxCount(): Promise<number> {
506
- const pendingTxs = await this.txPool.getPendingTxHashes();
507
- return pendingTxs.length;
389
+ public getPendingTxCount(): Promise<number> {
390
+ return this.txPool.getPendingTxCount();
508
391
  }
509
392
 
510
393
  public async *iteratePendingTxs(): AsyncIterableIterator<Tx> {
@@ -577,9 +460,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
577
460
  * Returns transactions in the transaction pool by hash.
578
461
  * If a transaction is not in the pool, it will be requested from the network.
579
462
  * @param txHashes - Hashes of the transactions to look for.
580
- * @returns The txs found, not necessarily on the same order as the hashes.
463
+ * @returns The txs found, or undefined if not found in the order requested.
581
464
  */
582
- async getTxsByHash(txHashes: TxHash[]): Promise<Tx[]> {
465
+ async getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
583
466
  const txs = await Promise.all(txHashes.map(txHash => this.txPool.getTxByHash(txHash)));
584
467
  const missingTxHashes = txs
585
468
  .map((tx, index) => [tx, index] as const)
@@ -592,7 +475,29 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
592
475
 
593
476
  const missingTxs = await this.requestTxsByHash(missingTxHashes);
594
477
  const fetchedMissingTxs = missingTxs.filter((tx): tx is Tx => !!tx);
595
- return txs.filter((tx): tx is Tx => !!tx).concat(fetchedMissingTxs);
478
+
479
+ // TODO: optimize
480
+ // Merge the found txs in order
481
+ const mergingTxsPromises = txHashes.map(async txHash => {
482
+ // Is it in the txs list from the mempool?
483
+ for (const tx of txs) {
484
+ if (tx !== undefined && (await tx.getTxHash()).equals(txHash)) {
485
+ return tx;
486
+ }
487
+ }
488
+
489
+ // Is it in the fetched missing txs?
490
+ for (const tx of fetchedMissingTxs) {
491
+ if (tx !== undefined && (await tx.getTxHash()).equals(txHash)) {
492
+ return tx;
493
+ }
494
+ }
495
+
496
+ // Otherwise return undefined
497
+ return undefined;
498
+ });
499
+
500
+ return await Promise.all(mergingTxsPromises);
596
501
  }
597
502
 
598
503
  /**
@@ -611,7 +516,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
611
516
  **/
612
517
  public async sendTx(tx: Tx): Promise<void> {
613
518
  await this.addTxs([tx]);
614
- this.p2pService.propagate(tx);
519
+ await this.p2pService.propagate(tx);
615
520
  }
616
521
 
617
522
  /**
@@ -675,6 +580,10 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
675
580
  return (await this.synchedProvenBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
676
581
  }
677
582
 
583
+ public async getSyncedFinalizedBlockNum(): Promise<number> {
584
+ return (await this.synchedFinalizedBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
585
+ }
586
+
678
587
  /** Returns latest L2 slot for which we have seen an L2 block. */
679
588
  public async getSyncedLatestSlot(): Promise<bigint> {
680
589
  return (await this.synchedLatestSlot.getAsync()) ?? BigInt(0);
@@ -712,16 +621,6 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
712
621
  }
713
622
  }
714
623
 
715
- private async addAttestationsToPool(blocks: PublishedL2Block[]): Promise<void> {
716
- const attestations = blocks.flatMap(block => {
717
- const payload = ConsensusPayload.fromBlock(block.block);
718
- return block.signatures.filter(sig => !sig.isEmpty).map(signature => new BlockAttestation(payload, signature));
719
- });
720
- await this.attestationPool?.addAttestations(attestations);
721
- const slots = blocks.map(b => b.block.header.getSlot()).sort((a, b) => Number(a - b));
722
- this.log.debug(`Added ${attestations.length} attestations for slots ${slots[0]}-${slots.at(-1)} to the pool`);
723
- }
724
-
725
624
  /**
726
625
  * Deletes txs from these blocks.
727
626
  * @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with.
@@ -746,50 +645,67 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
746
645
  }
747
646
 
748
647
  await this.markTxsAsMinedFromBlocks(blocks.map(b => b.block));
749
- await this.addAttestationsToPool(blocks);
648
+ void this.requestMissingTxsFromUnprovenBlocks(blocks.map(b => b.block));
649
+
750
650
  const lastBlock = blocks.at(-1)!.block;
651
+
751
652
  await Promise.all(
752
- blocks.map(async block => this.synchedBlockHashes.set(block.block.number, (await block.block.hash()).toString())),
653
+ blocks.map(async block =>
654
+ this.setBlockHash({
655
+ number: block.block.number,
656
+ hash: await block.block.hash().then(h => h.toString()),
657
+ }),
658
+ ),
753
659
  );
660
+
754
661
  await this.synchedLatestBlockNumber.set(lastBlock.number);
755
662
  await this.synchedLatestSlot.set(lastBlock.header.getSlot());
756
663
  this.log.verbose(`Synched to latest block ${lastBlock.number}`);
757
664
  await this.startServiceIfSynched();
758
665
  }
759
666
 
667
+ /** Request txs for unproven blocks so the prover node has more chances to get them. */
668
+ private async requestMissingTxsFromUnprovenBlocks(blocks: L2Block[]): Promise<void> {
669
+ try {
670
+ const provenBlockNumber = Math.max(await this.getSyncedProvenBlockNum(), this.provenBlockNumberAtStart);
671
+ const unprovenBlocks = blocks.filter(block => block.number > provenBlockNumber);
672
+ const txHashes = unprovenBlocks.flatMap(block => block.body.txEffects.map(txEffect => txEffect.txHash));
673
+ const missingTxHashes = await this.txPool
674
+ .hasTxs(txHashes)
675
+ .then(availability => txHashes.filter((_, index) => !availability[index]));
676
+ if (missingTxHashes.length > 0) {
677
+ this.log.verbose(
678
+ `Requesting ${missingTxHashes.length} missing txs from peers for ${unprovenBlocks.length} unproven mined blocks`,
679
+ { missingTxHashes, unprovenBlockNumbers: unprovenBlocks.map(block => block.number) },
680
+ );
681
+ await this.requestTxsByHash(missingTxHashes);
682
+ }
683
+ } catch (err) {
684
+ this.log.error(`Error requesting missing txs from unproven blocks`, err, {
685
+ blocks: blocks.map(block => block.number),
686
+ });
687
+ }
688
+ }
689
+
760
690
  /**
761
- * Handles new proven blocks by deleting the txs in them, or by deleting the txs in blocks `keepProvenTxsFor` ago.
762
- * @param blocks - A list of proven L2 blocks.
691
+ * Handles new finalized blocks by deleting the txs and attestations in them.
692
+ * @param blocks - A list of finalized L2 blocks.
763
693
  * @returns Empty promise.
764
694
  */
765
- private async handleProvenL2Blocks(blocks: L2Block[]): Promise<void> {
695
+ private async handleFinalizedL2Blocks(blocks: L2Block[]): Promise<void> {
696
+ this.log.trace(`Handling finalized blocks ${blocks.length} up to ${blocks.at(-1)?.number}`);
766
697
  if (!blocks.length) {
767
698
  return Promise.resolve();
768
699
  }
769
700
 
770
- const firstBlockNum = blocks[0].number;
771
701
  const lastBlockNum = blocks[blocks.length - 1].number;
772
- const lastBlockSlot = blocks[blocks.length - 1].header.globalVariables.slotNumber.toBigInt();
773
-
774
- // If keepProvenTxsFor is 0, we delete all txs from all proven blocks.
775
- if (this.keepProvenTxsFor === 0) {
776
- await this.deleteTxsFromBlocks(blocks);
777
- } else if (lastBlockNum - this.keepProvenTxsFor >= INITIAL_L2_BLOCK_NUM) {
778
- const fromBlock = Math.max(INITIAL_L2_BLOCK_NUM, firstBlockNum - this.keepProvenTxsFor);
779
- const toBlock = lastBlockNum - this.keepProvenTxsFor;
780
- const limit = toBlock - fromBlock + 1;
781
- const blocksToDeleteTxsFrom = await this.l2BlockSource.getBlocks(fromBlock, limit, true);
782
- await this.deleteTxsFromBlocks(blocksToDeleteTxsFrom);
783
- }
702
+ const lastBlockSlot = blocks[blocks.length - 1].header.getSlot();
784
703
 
785
- // We delete attestations older than the last block slot minus the number of slots we want to keep in the pool.
786
- const lastBlockSlotMinusKeepAttestationsInPoolFor = lastBlockSlot - BigInt(this.keepAttestationsInPoolFor);
787
- if (lastBlockSlotMinusKeepAttestationsInPoolFor >= BigInt(INITIAL_L2_BLOCK_NUM)) {
788
- await this.attestationPool?.deleteAttestationsOlderThan(lastBlockSlotMinusKeepAttestationsInPoolFor);
789
- }
704
+ await this.deleteTxsFromBlocks(blocks);
705
+ await this.attestationPool?.deleteAttestationsOlderThan(lastBlockSlot);
790
706
 
791
- await this.synchedProvenBlockNumber.set(lastBlockNum);
792
- this.log.debug(`Synched to proven block ${lastBlockNum}`);
707
+ await this.synchedFinalizedBlockNumber.set(lastBlockNum);
708
+ this.log.debug(`Synched to finalized block ${lastBlockNum}`);
793
709
 
794
710
  await this.startServiceIfSynched();
795
711
  }
@@ -801,11 +717,11 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
801
717
  private async handlePruneL2Blocks(latestBlock: number): Promise<void> {
802
718
  // NOTE: temporary fix for alphanet, deleting ALL txs that were in the epoch from the pool #13723
803
719
  // TODO: undo once fixed: #13770
804
- const txsToDelete = new Set<TxHash>();
720
+ const txsToDelete = new Map<string, TxHash>();
805
721
  const minedTxs = await this.txPool.getMinedTxHashes();
806
722
  for (const [txHash, blockNumber] of minedTxs) {
807
723
  if (blockNumber > latestBlock) {
808
- txsToDelete.add(txHash);
724
+ txsToDelete.set(txHash.toString(), txHash);
809
725
  }
810
726
  }
811
727
 
@@ -814,7 +730,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
814
730
  // every tx that's been generated against a block that has now been pruned is no longer valid
815
731
  if (tx.data.constants.historicalHeader.globalVariables.blockNumber.toNumber() > latestBlock) {
816
732
  const txHash = await tx.getTxHash();
817
- txsToDelete.add(txHash);
733
+ txsToDelete.set(txHash.toString(), txHash);
818
734
  }
819
735
  }
820
736
 
@@ -825,7 +741,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
825
741
  );
826
742
 
827
743
  // delete invalid txs (both pending and mined)
828
- await this.txPool.deleteTxs(Array.from(txsToDelete));
744
+ await this.txPool.deleteTxs(Array.from(txsToDelete.values()));
829
745
 
830
746
  // everything left in the mined set was built against a block on the proven chain so its still valid
831
747
  // move back to pending the txs that were reorged out of the chain
@@ -849,12 +765,23 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
849
765
  }
850
766
 
851
767
  private async startServiceIfSynched() {
768
+ if (this.currentState !== P2PClientState.SYNCHING) {
769
+ return;
770
+ }
771
+ const syncedFinalizedBlock = await this.getSyncedFinalizedBlockNum();
772
+ const syncedProvenBlock = await this.getSyncedProvenBlockNum();
773
+ const syncedLatestBlock = await this.getSyncedLatestBlockNum();
774
+
852
775
  if (
853
- this.currentState === P2PClientState.SYNCHING &&
854
- (await this.getSyncedLatestBlockNum()) >= this.latestBlockNumberAtStart &&
855
- (await this.getSyncedProvenBlockNum()) >= this.provenBlockNumberAtStart
776
+ syncedLatestBlock >= this.latestBlockNumberAtStart &&
777
+ syncedProvenBlock >= this.provenBlockNumberAtStart &&
778
+ syncedFinalizedBlock >= this.finalizedBlockNumberAtStart
856
779
  ) {
857
- this.log.debug(`Synched to blocks at start`);
780
+ this.log.info(`Completed P2P client sync to block ${syncedLatestBlock}. Starting service.`, {
781
+ syncedLatestBlock,
782
+ syncedProvenBlock,
783
+ syncedFinalizedBlock,
784
+ });
858
785
  this.setCurrentState(P2PClientState.RUNNING);
859
786
  if (this.syncResolve !== undefined) {
860
787
  this.syncResolve();
@@ -872,4 +799,16 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
872
799
  this.currentState = newState;
873
800
  this.log.debug(`Moved from state ${P2PClientState[oldState]} to ${P2PClientState[this.currentState]}`);
874
801
  }
802
+
803
+ public validate(txs: Tx[]): Promise<void> {
804
+ return this.p2pService.validate(txs);
805
+ }
806
+
807
+ /**
808
+ * Marks transactions as non-evictable in the pool.
809
+ * @param txHashes - Hashes of the transactions to mark as non-evictable.
810
+ */
811
+ public markTxsAsNonEvictable(txHashes: TxHash[]): Promise<void> {
812
+ return this.txPool.markTxsAsNonEvictable(txHashes);
813
+ }
875
814
  }