@aztec/p2p 0.66.0 → 0.67.1-devnet

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 (163) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +4 -1
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +21 -9
  4. package/dest/client/index.d.ts +5 -4
  5. package/dest/client/index.d.ts.map +1 -1
  6. package/dest/client/index.js +18 -12
  7. package/dest/client/p2p_client.d.ts +13 -20
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +32 -15
  10. package/dest/config.d.ts +1 -1
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +2 -2
  13. package/dest/errors/reqresp.error.d.ts +12 -1
  14. package/dest/errors/reqresp.error.d.ts.map +1 -1
  15. package/dest/errors/reqresp.error.js +15 -2
  16. package/dest/index.d.ts +1 -1
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +2 -2
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +9 -0
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +3 -0
  22. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -0
  23. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +171 -0
  24. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +29 -0
  25. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -0
  26. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +114 -0
  27. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  28. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +3 -3
  29. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  30. package/dest/mem_pools/instrumentation.js +2 -20
  31. package/dest/mem_pools/interface.d.ts +4 -3
  32. package/dest/mem_pools/interface.d.ts.map +1 -1
  33. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +4 -4
  35. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  36. package/dest/mem_pools/tx_pool/memory_tx_pool.js +4 -4
  37. package/dest/mocks/index.d.ts +6 -6
  38. package/dest/mocks/index.d.ts.map +1 -1
  39. package/dest/mocks/index.js +9 -9
  40. package/dest/services/data_store.d.ts.map +1 -0
  41. package/dest/services/data_store.js +188 -0
  42. package/dest/{service → services/discv5}/discV5_service.d.ts +4 -2
  43. package/dest/services/discv5/discV5_service.d.ts.map +1 -0
  44. package/dest/services/discv5/discV5_service.js +144 -0
  45. package/dest/{service → services}/dummy_service.d.ts +3 -1
  46. package/dest/services/dummy_service.d.ts.map +1 -0
  47. package/dest/{service → services}/dummy_service.js +5 -1
  48. package/dest/{service → services}/encoding.d.ts +5 -0
  49. package/dest/services/encoding.d.ts.map +1 -0
  50. package/dest/services/encoding.js +65 -0
  51. package/dest/services/index.d.ts +3 -0
  52. package/dest/services/index.d.ts.map +1 -0
  53. package/dest/services/index.js +3 -0
  54. package/dest/{service → services/libp2p}/libp2p_service.d.ts +50 -11
  55. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -0
  56. package/dest/services/libp2p/libp2p_service.js +573 -0
  57. package/dest/{service → services/peer-scoring}/peer_scoring.d.ts +5 -2
  58. package/dest/services/peer-scoring/peer_scoring.d.ts.map +1 -0
  59. package/dest/services/peer-scoring/peer_scoring.js +72 -0
  60. package/dest/{service → services}/peer_manager.d.ts +8 -3
  61. package/dest/services/peer_manager.d.ts.map +1 -0
  62. package/dest/services/peer_manager.js +230 -0
  63. package/dest/services/reqresp/config.d.ts.map +1 -0
  64. package/dest/{service → services}/reqresp/config.js +1 -1
  65. package/dest/services/reqresp/handlers.d.ts.map +1 -0
  66. package/dest/{service → services}/reqresp/handlers.js +1 -1
  67. package/dest/services/reqresp/index.d.ts.map +1 -0
  68. package/dest/{service → services}/reqresp/index.js +1 -1
  69. package/dest/services/reqresp/interface.d.ts.map +1 -0
  70. package/dest/{service → services}/reqresp/interface.js +1 -1
  71. package/dest/services/reqresp/rate_limiter/index.d.ts.map +1 -0
  72. package/dest/{service → services}/reqresp/rate_limiter/index.js +1 -1
  73. package/dest/services/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -0
  74. package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.js +2 -2
  75. package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +1 -0
  76. package/dest/{service → services}/reqresp/rate_limiter/rate_limits.js +1 -1
  77. package/dest/{service → services}/reqresp/reqresp.d.ts +16 -0
  78. package/dest/services/reqresp/reqresp.d.ts.map +1 -0
  79. package/dest/{service → services}/reqresp/reqresp.js +69 -20
  80. package/dest/{service → services}/service.d.ts +2 -1
  81. package/dest/services/service.d.ts.map +1 -0
  82. package/dest/{service → services}/service.js +1 -1
  83. package/dest/tx_validator/aggregate_tx_validator.d.ts +1 -1
  84. package/dest/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  85. package/dest/tx_validator/aggregate_tx_validator.js +5 -3
  86. package/dest/tx_validator/data_validator.js +3 -3
  87. package/dest/tx_validator/double_spend_validator.d.ts +3 -2
  88. package/dest/tx_validator/double_spend_validator.d.ts.map +1 -1
  89. package/dest/tx_validator/double_spend_validator.js +8 -8
  90. package/dest/tx_validator/metadata_validator.js +3 -3
  91. package/dest/tx_validator/tx_proof_validator.js +3 -3
  92. package/package.json +12 -8
  93. package/src/bootstrap/bootstrap.ts +24 -10
  94. package/src/client/index.ts +44 -19
  95. package/src/client/p2p_client.ts +58 -36
  96. package/src/config.ts +1 -1
  97. package/src/errors/reqresp.error.ts +15 -1
  98. package/src/index.ts +1 -1
  99. package/src/mem_pools/attestation_pool/attestation_pool.ts +10 -0
  100. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +237 -0
  101. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +153 -0
  102. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +2 -2
  103. package/src/mem_pools/instrumentation.ts +1 -21
  104. package/src/mem_pools/interface.ts +5 -3
  105. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +3 -3
  106. package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
  107. package/src/mocks/index.ts +14 -11
  108. package/src/{service → services/discv5}/discV5_service.ts +20 -15
  109. package/src/{service → services}/dummy_service.ts +6 -1
  110. package/src/{service → services}/encoding.ts +21 -3
  111. package/src/services/index.ts +2 -0
  112. package/src/{service → services/libp2p}/libp2p_service.ts +208 -96
  113. package/src/{service → services/peer-scoring}/peer_scoring.ts +9 -2
  114. package/src/{service → services}/peer_manager.ts +73 -24
  115. package/src/{service → services}/reqresp/rate_limiter/rate_limiter.ts +1 -1
  116. package/src/{service → services}/reqresp/reqresp.ts +87 -21
  117. package/src/{service → services}/service.ts +3 -1
  118. package/src/tx_validator/aggregate_tx_validator.ts +5 -3
  119. package/src/tx_validator/data_validator.ts +2 -2
  120. package/src/tx_validator/double_spend_validator.ts +8 -10
  121. package/src/tx_validator/metadata_validator.ts +2 -2
  122. package/src/tx_validator/tx_proof_validator.ts +2 -2
  123. package/dest/service/data_store.d.ts.map +0 -1
  124. package/dest/service/data_store.js +0 -188
  125. package/dest/service/discV5_service.d.ts.map +0 -1
  126. package/dest/service/discV5_service.js +0 -141
  127. package/dest/service/dummy_service.d.ts.map +0 -1
  128. package/dest/service/encoding.d.ts.map +0 -1
  129. package/dest/service/encoding.js +0 -49
  130. package/dest/service/index.d.ts +0 -3
  131. package/dest/service/index.d.ts.map +0 -1
  132. package/dest/service/index.js +0 -3
  133. package/dest/service/libp2p_service.d.ts.map +0 -1
  134. package/dest/service/libp2p_service.js +0 -496
  135. package/dest/service/peer_manager.d.ts.map +0 -1
  136. package/dest/service/peer_manager.js +0 -176
  137. package/dest/service/peer_scoring.d.ts.map +0 -1
  138. package/dest/service/peer_scoring.js +0 -67
  139. package/dest/service/reqresp/config.d.ts.map +0 -1
  140. package/dest/service/reqresp/handlers.d.ts.map +0 -1
  141. package/dest/service/reqresp/index.d.ts.map +0 -1
  142. package/dest/service/reqresp/interface.d.ts.map +0 -1
  143. package/dest/service/reqresp/rate_limiter/index.d.ts.map +0 -1
  144. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +0 -1
  145. package/dest/service/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
  146. package/dest/service/reqresp/reqresp.d.ts.map +0 -1
  147. package/dest/service/service.d.ts.map +0 -1
  148. package/src/service/index.ts +0 -2
  149. /package/dest/{service → services}/data_store.d.ts +0 -0
  150. /package/dest/{service → services}/reqresp/config.d.ts +0 -0
  151. /package/dest/{service → services}/reqresp/handlers.d.ts +0 -0
  152. /package/dest/{service → services}/reqresp/index.d.ts +0 -0
  153. /package/dest/{service → services}/reqresp/interface.d.ts +0 -0
  154. /package/dest/{service → services}/reqresp/rate_limiter/index.d.ts +0 -0
  155. /package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.d.ts +0 -0
  156. /package/dest/{service → services}/reqresp/rate_limiter/rate_limits.d.ts +0 -0
  157. /package/src/{service → services}/data_store.ts +0 -0
  158. /package/src/{service → services}/reqresp/config.ts +0 -0
  159. /package/src/{service → services}/reqresp/handlers.ts +0 -0
  160. /package/src/{service → services}/reqresp/index.ts +0 -0
  161. /package/src/{service → services}/reqresp/interface.ts +0 -0
  162. /package/src/{service → services}/reqresp/rate_limiter/index.ts +0 -0
  163. /package/src/{service → services}/reqresp/rate_limiter/rate_limits.ts +0 -0
@@ -1,51 +1,66 @@
1
- import type { ClientProtocolCircuitVerifier, L2BlockSource, WorldStateSynchronizer } from '@aztec/circuit-types';
2
- import { createDebugLogger } from '@aztec/foundation/log';
1
+ import {
2
+ type ClientProtocolCircuitVerifier,
3
+ type L2BlockSource,
4
+ P2PClientType,
5
+ type WorldStateSynchronizer,
6
+ } from '@aztec/circuit-types';
7
+ import { createLogger } from '@aztec/foundation/log';
3
8
  import { type AztecKVStore } from '@aztec/kv-store';
4
9
  import { type DataStoreConfig } from '@aztec/kv-store/config';
5
- import { createStore } from '@aztec/kv-store/utils';
10
+ import { createStore } from '@aztec/kv-store/lmdb';
6
11
  import { type TelemetryClient } from '@aztec/telemetry-client';
7
12
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
8
13
 
9
14
  import { P2PClient } from '../client/p2p_client.js';
10
15
  import { type P2PConfig } from '../config.js';
11
16
  import { type AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
12
- import { InMemoryAttestationPool } from '../mem_pools/attestation_pool/memory_attestation_pool.js';
17
+ import { KvAttestationPool } from '../mem_pools/attestation_pool/kv_attestation_pool.js';
13
18
  import { type EpochProofQuotePool } from '../mem_pools/epoch_proof_quote_pool/epoch_proof_quote_pool.js';
14
19
  import { MemoryEpochProofQuotePool } from '../mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.js';
15
20
  import { type MemPools } from '../mem_pools/interface.js';
16
21
  import { AztecKVTxPool, type TxPool } from '../mem_pools/tx_pool/index.js';
17
- import { DiscV5Service } from '../service/discV5_service.js';
18
- import { DummyP2PService } from '../service/dummy_service.js';
19
- import { LibP2PService } from '../service/index.js';
22
+ import { DiscV5Service } from '../services/discv5/discV5_service.js';
23
+ import { DummyP2PService } from '../services/dummy_service.js';
24
+ import { LibP2PService } from '../services/index.js';
20
25
  import { configureP2PClientAddresses, createLibP2PPeerIdFromPrivateKey, getPeerIdPrivateKey } from '../util.js';
21
26
 
22
27
  export * from './p2p_client.js';
23
28
 
24
- export const createP2PClient = async (
29
+ type P2PClientDeps<T extends P2PClientType> = {
30
+ txPool?: TxPool;
31
+ store?: AztecKVStore;
32
+ attestationPool?: T extends P2PClientType.Full ? AttestationPool : undefined;
33
+ epochProofQuotePool?: EpochProofQuotePool;
34
+ };
35
+
36
+ export const createP2PClient = async <T extends P2PClientType>(
37
+ clientType: T,
25
38
  _config: P2PConfig & DataStoreConfig,
26
39
  l2BlockSource: L2BlockSource,
27
40
  proofVerifier: ClientProtocolCircuitVerifier,
28
41
  worldStateSynchronizer: WorldStateSynchronizer,
29
42
  telemetry: TelemetryClient = new NoopTelemetryClient(),
30
- deps: {
31
- txPool?: TxPool;
32
- store?: AztecKVStore;
33
- attestationPool?: AttestationPool;
34
- epochProofQuotePool?: EpochProofQuotePool;
35
- } = {},
43
+ deps: P2PClientDeps<T> = {},
36
44
  ) => {
37
45
  let config = { ..._config };
38
- const store = deps.store ?? (await createStore('p2p', config, createDebugLogger('aztec:p2p:lmdb')));
46
+ const logger = createLogger('p2p');
47
+ const store = deps.store ?? (await createStore('p2p', config, createLogger('p2p:lmdb')));
39
48
 
40
- const mempools: MemPools = {
49
+ const mempools: MemPools<T> = {
41
50
  txPool: deps.txPool ?? new AztecKVTxPool(store, telemetry),
42
- attestationPool: deps.attestationPool ?? new InMemoryAttestationPool(telemetry),
43
51
  epochProofQuotePool: deps.epochProofQuotePool ?? new MemoryEpochProofQuotePool(telemetry),
52
+ attestationPool:
53
+ clientType === P2PClientType.Full
54
+ ? ((deps.attestationPool ?? new KvAttestationPool(store, telemetry)) as T extends P2PClientType.Full
55
+ ? AttestationPool
56
+ : undefined)
57
+ : undefined,
44
58
  };
45
59
 
46
60
  let p2pService;
47
61
 
48
62
  if (_config.p2pEnabled) {
63
+ logger.verbose('P2P is enabled. Using LibP2P service.');
49
64
  config = await configureP2PClientAddresses(_config);
50
65
 
51
66
  // Create peer discovery service
@@ -53,7 +68,8 @@ export const createP2PClient = async (
53
68
  const peerId = await createLibP2PPeerIdFromPrivateKey(peerIdPrivateKey);
54
69
  const discoveryService = new DiscV5Service(peerId, config, telemetry);
55
70
 
56
- p2pService = await LibP2PService.new(
71
+ p2pService = await LibP2PService.new<T>(
72
+ clientType,
57
73
  config,
58
74
  discoveryService,
59
75
  peerId,
@@ -65,7 +81,16 @@ export const createP2PClient = async (
65
81
  telemetry,
66
82
  );
67
83
  } else {
84
+ logger.verbose('P2P is disabled. Using dummy P2P service');
68
85
  p2pService = new DummyP2PService();
69
86
  }
70
- return new P2PClient(store, l2BlockSource, mempools, p2pService, config.keepProvenTxsInPoolFor, telemetry);
87
+ return new P2PClient(
88
+ clientType,
89
+ store,
90
+ l2BlockSource,
91
+ mempools,
92
+ p2pService,
93
+ config.keepProvenTxsInPoolFor,
94
+ telemetry,
95
+ );
71
96
  };
@@ -5,16 +5,24 @@ import {
5
5
  type L2Block,
6
6
  type L2BlockId,
7
7
  type L2BlockSource,
8
- L2BlockStream,
9
8
  type L2BlockStreamEvent,
10
9
  type L2Tips,
10
+ type P2PApi,
11
+ type P2PClientType,
12
+ type PeerInfo,
11
13
  type Tx,
12
14
  type TxHash,
13
15
  } from '@aztec/circuit-types';
14
16
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants';
15
- import { createDebugLogger } from '@aztec/foundation/log';
17
+ import { createLogger } from '@aztec/foundation/log';
16
18
  import { type AztecKVStore, type AztecMap, type AztecSingleton } from '@aztec/kv-store';
17
- import { Attributes, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
19
+ import {
20
+ Attributes,
21
+ type TelemetryClient,
22
+ TraceableL2BlockStream,
23
+ WithTracer,
24
+ trackSpan,
25
+ } from '@aztec/telemetry-client';
18
26
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
19
27
 
20
28
  import { type ENR } from '@chainsafe/enr';
@@ -24,8 +32,8 @@ import { type AttestationPool } from '../mem_pools/attestation_pool/attestation_
24
32
  import { type EpochProofQuotePool } from '../mem_pools/epoch_proof_quote_pool/epoch_proof_quote_pool.js';
25
33
  import { type MemPools } from '../mem_pools/interface.js';
26
34
  import { type TxPool } from '../mem_pools/tx_pool/index.js';
27
- import { TX_REQ_PROTOCOL } from '../service/reqresp/interface.js';
28
- import type { P2PService } from '../service/service.js';
35
+ import { TX_REQ_PROTOCOL } from '../services/reqresp/interface.js';
36
+ import type { P2PService } from '../services/service.js';
29
37
 
30
38
  /**
31
39
  * Enum defining the possible states of the p2p client.
@@ -54,7 +62,7 @@ export interface P2PSyncState {
54
62
  /**
55
63
  * Interface of a P2P client.
56
64
  **/
57
- export interface P2P {
65
+ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
58
66
  /**
59
67
  * Broadcasts a block proposal to other peers.
60
68
  *
@@ -62,15 +70,6 @@ export interface P2P {
62
70
  */
63
71
  broadcastProposal(proposal: BlockProposal): void;
64
72
 
65
- /**
66
- * Queries the Attestation pool for attestations for the given slot
67
- *
68
- * @param slot - the slot to query
69
- * @param proposalId - the proposal id to query
70
- * @returns BlockAttestations
71
- */
72
- getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]>;
73
-
74
73
  /**
75
74
  * Queries the EpochProofQuote pool for quotes for the given epoch
76
75
  *
@@ -122,12 +121,6 @@ export interface P2P {
122
121
  **/
123
122
  deleteTxs(txHashes: TxHash[]): Promise<void>;
124
123
 
125
- /**
126
- * Returns all transactions in the transaction pool.
127
- * @returns An array of Txs.
128
- */
129
- getTxs(filter: 'all' | 'pending' | 'mined'): Tx[];
130
-
131
124
  /**
132
125
  * Returns a transaction in the transaction pool by its hash.
133
126
  * @param txHash - Hash of tx to return.
@@ -173,15 +166,21 @@ export interface P2P {
173
166
  getStatus(): Promise<P2PSyncState>;
174
167
 
175
168
  /**
176
- * Returns the ENR for this node, if any.
169
+ * Returns the ENR of this node, if any.
177
170
  */
178
171
  getEnr(): ENR | undefined;
179
- }
172
+
173
+ /** Identifies a p2p client. */
174
+ isP2PClient(): true;
175
+ };
180
176
 
181
177
  /**
182
178
  * The P2P client implementation.
183
179
  */
184
- export class P2PClient extends WithTracer implements P2P {
180
+ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
181
+ extends WithTracer
182
+ implements P2P, P2P<P2PClientType.Prover>
183
+ {
185
184
  /** Property that indicates whether the client is running. */
186
185
  private stopping = false;
187
186
 
@@ -199,7 +198,7 @@ export class P2PClient extends WithTracer implements P2P {
199
198
  private synchedProvenBlockNumber: AztecSingleton<number>;
200
199
 
201
200
  private txPool: TxPool;
202
- private attestationPool: AttestationPool;
201
+ private attestationPool: T extends P2PClientType.Full ? AttestationPool : undefined;
203
202
  private epochProofQuotePool: EpochProofQuotePool;
204
203
 
205
204
  /** How many slots to keep attestations for. */
@@ -217,13 +216,14 @@ export class P2PClient extends WithTracer implements P2P {
217
216
  * @param log - A logger.
218
217
  */
219
218
  constructor(
219
+ clientType: T,
220
220
  store: AztecKVStore,
221
221
  private l2BlockSource: L2BlockSource,
222
- mempools: MemPools,
222
+ mempools: MemPools<T>,
223
223
  private p2pService: P2PService,
224
224
  private keepProvenTxsFor: number,
225
225
  telemetry: TelemetryClient = new NoopTelemetryClient(),
226
- private log = createDebugLogger('aztec:p2p'),
226
+ private log = createLogger('p2p'),
227
227
  ) {
228
228
  super(telemetry, 'P2PClient');
229
229
 
@@ -231,7 +231,9 @@ export class P2PClient extends WithTracer implements P2P {
231
231
 
232
232
  this.keepAttestationsInPoolFor = keepAttestationsInPoolFor;
233
233
 
234
- this.blockStream = new L2BlockStream(l2BlockSource, this, this, {
234
+ const tracer = telemetry.getTracer('P2PL2BlockStream');
235
+ const logger = createLogger('p2p:l2-block-stream');
236
+ this.blockStream = new TraceableL2BlockStream(l2BlockSource, this, this, tracer, 'P2PL2BlockStream', logger, {
235
237
  batchSize: blockRequestBatchSize,
236
238
  pollIntervalMS: blockCheckIntervalMS,
237
239
  });
@@ -241,8 +243,16 @@ export class P2PClient extends WithTracer implements P2P {
241
243
  this.synchedProvenBlockNumber = store.openSingleton('p2p_pool_last_proven_l2_block');
242
244
 
243
245
  this.txPool = mempools.txPool;
244
- this.attestationPool = mempools.attestationPool;
245
246
  this.epochProofQuotePool = mempools.epochProofQuotePool;
247
+ this.attestationPool = mempools.attestationPool!;
248
+ }
249
+
250
+ public isP2PClient(): true {
251
+ return true;
252
+ }
253
+
254
+ public getPeers(includePending?: boolean): Promise<PeerInfo[]> {
255
+ return Promise.resolve(this.p2pService.getPeers(includePending));
246
256
  }
247
257
 
248
258
  public getL2BlockHash(number: number): Promise<string | undefined> {
@@ -361,7 +371,7 @@ export class P2PClient extends WithTracer implements P2P {
361
371
  this.setCurrentState(P2PClientState.RUNNING);
362
372
  this.syncPromise = Promise.resolve();
363
373
  await this.p2pService.start();
364
- this.log.verbose(`Block ${syncedLatestBlock} (proven ${syncedProvenBlock}) already beyond current block`);
374
+ this.log.debug(`Block ${syncedLatestBlock} (proven ${syncedProvenBlock}) already beyond current block`);
365
375
  }
366
376
 
367
377
  // publish any txs in TxPool after its doing initial sync
@@ -401,7 +411,7 @@ export class P2PClient extends WithTracer implements P2P {
401
411
  }
402
412
 
403
413
  public getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
404
- return Promise.resolve(this.attestationPool.getAttestationsForSlot(slot, proposalId));
414
+ return Promise.resolve(this.attestationPool?.getAttestationsForSlot(slot, proposalId) ?? []);
405
415
  }
406
416
 
407
417
  // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
@@ -436,14 +446,20 @@ export class P2PClient extends WithTracer implements P2P {
436
446
  public async requestTxByHash(txHash: TxHash): Promise<Tx | undefined> {
437
447
  const tx = await this.p2pService.sendRequest(TX_REQ_PROTOCOL, txHash);
438
448
 
439
- this.log.debug(`Requested ${txHash.toString()} from peer | success = ${!!tx}`);
440
449
  if (tx) {
450
+ this.log.debug(`Received tx ${txHash.toString()} from peer`);
441
451
  await this.txPool.addTxs([tx]);
452
+ } else {
453
+ this.log.debug(`Failed to receive tx ${txHash.toString()} from peer`);
442
454
  }
443
455
 
444
456
  return tx;
445
457
  }
446
458
 
459
+ public getPendingTxs(): Promise<Tx[]> {
460
+ return Promise.resolve(this.getTxs('pending'));
461
+ }
462
+
447
463
  /**
448
464
  * Returns all transactions in the transaction pool.
449
465
  * @returns An array of Txs.
@@ -514,6 +530,10 @@ export class P2PClient extends WithTracer implements P2P {
514
530
  return this.p2pService.getEnr();
515
531
  }
516
532
 
533
+ public getEncodedEnr(): Promise<string | undefined> {
534
+ return Promise.resolve(this.p2pService.getEnr()?.encodeTxt());
535
+ }
536
+
517
537
  /**
518
538
  * Deletes the 'txs' from the pool.
519
539
  * NOT used if we use sendTx as reconcileTxPool will handle this.
@@ -636,16 +656,17 @@ export class P2PClient extends WithTracer implements P2P {
636
656
  // We delete attestations older than the last block slot minus the number of slots we want to keep in the pool.
637
657
  const lastBlockSlotMinusKeepAttestationsInPoolFor = lastBlockSlot - BigInt(this.keepAttestationsInPoolFor);
638
658
  if (lastBlockSlotMinusKeepAttestationsInPoolFor >= BigInt(INITIAL_L2_BLOCK_NUM)) {
639
- await this.attestationPool.deleteAttestationsOlderThan(lastBlockSlotMinusKeepAttestationsInPoolFor);
659
+ await this.attestationPool?.deleteAttestationsOlderThan(lastBlockSlotMinusKeepAttestationsInPoolFor);
640
660
  }
641
661
 
642
- await this.synchedProvenBlockNumber.set(lastBlockNum);
643
- this.log.debug(`Synched to proven block ${lastBlockNum}`);
644
662
  const provenEpochNumber = await this.l2BlockSource.getProvenL2EpochNumber();
645
663
  if (provenEpochNumber !== undefined) {
646
664
  this.epochProofQuotePool.deleteQuotesToEpoch(BigInt(provenEpochNumber));
647
665
  }
648
666
 
667
+ await this.synchedProvenBlockNumber.set(lastBlockNum);
668
+ this.log.debug(`Synched to proven block ${lastBlockNum}`);
669
+
649
670
  await this.startServiceIfSynched();
650
671
  }
651
672
 
@@ -709,8 +730,9 @@ export class P2PClient extends WithTracer implements P2P {
709
730
  * @param newState - New state value.
710
731
  */
711
732
  private setCurrentState(newState: P2PClientState) {
733
+ const oldState = this.currentState;
712
734
  this.currentState = newState;
713
- this.log.debug(`Moved to state ${P2PClientState[this.currentState]}`);
735
+ this.log.debug(`Moved from state ${P2PClientState[oldState]} to ${P2PClientState[this.currentState]}`);
714
736
  }
715
737
 
716
738
  private async publishStoredTxs() {
package/src/config.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from '@aztec/foundation/config';
9
9
  import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
10
10
 
11
- import { type P2PReqRespConfig, p2pReqRespConfigMappings } from './service/reqresp/config.js';
11
+ import { type P2PReqRespConfig, p2pReqRespConfigMappings } from './services/reqresp/config.js';
12
12
 
13
13
  /**
14
14
  * P2P client configuration values.
@@ -3,7 +3,7 @@
3
3
  * This error will be thrown when a request to a specific peer times out.
4
4
  * @category Errors
5
5
  */
6
- export class IndiviualReqRespTimeoutError extends Error {
6
+ export class IndividualReqRespTimeoutError extends Error {
7
7
  constructor() {
8
8
  super(`Request to peer timed out`);
9
9
  }
@@ -19,3 +19,17 @@ export class CollectiveReqRespTimeoutError extends Error {
19
19
  super(`Request to all peers timed out`);
20
20
  }
21
21
  }
22
+
23
+ /** Invalid response error
24
+ *
25
+ * This error will be thrown when a response is received that is not valid.
26
+ *
27
+ * This error does not need to be punished as message validators will handle punishing invalid
28
+ * requests
29
+ * @category Errors
30
+ */
31
+ export class InvalidResponseError extends Error {
32
+ constructor() {
33
+ super(`Invalid response received`);
34
+ }
35
+ }
package/src/index.ts CHANGED
@@ -3,6 +3,6 @@ export * from './bootstrap/bootstrap.js';
3
3
  export * from './client/index.js';
4
4
  export * from './config.js';
5
5
  export * from './mem_pools/epoch_proof_quote_pool/index.js';
6
- export * from './service/index.js';
6
+ export * from './services/index.js';
7
7
  export * from './mem_pools/tx_pool/index.js';
8
8
  export * from './tx_validator/index.js';
@@ -39,6 +39,16 @@ export interface AttestationPool {
39
39
  */
40
40
  deleteAttestationsForSlot(slot: bigint): Promise<void>;
41
41
 
42
+ /**
43
+ * Delete Attestations for slot and proposal
44
+ *
45
+ * Removes all attestations associated with a slot and proposal
46
+ *
47
+ * @param slot - The slot to delete.
48
+ * @param proposalId - The proposal to delete.
49
+ */
50
+ deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void>;
51
+
42
52
  /**
43
53
  * Get Attestations for slot
44
54
  *
@@ -0,0 +1,237 @@
1
+ import { type BlockAttestation, TxHash } from '@aztec/circuit-types';
2
+ import { Secp256k1Signer } from '@aztec/foundation/crypto';
3
+ import { Fr } from '@aztec/foundation/fields';
4
+
5
+ import { jest } from '@jest/globals';
6
+ import { type MockProxy, mock } from 'jest-mock-extended';
7
+
8
+ import { type PoolInstrumentation } from '../instrumentation.js';
9
+ import { type AttestationPool } from './attestation_pool.js';
10
+ import { mockAttestation } from './mocks.js';
11
+
12
+ const NUMBER_OF_SIGNERS_PER_TEST = 4;
13
+
14
+ export function describeAttestationPool(getAttestationPool: () => AttestationPool) {
15
+ let ap: AttestationPool;
16
+ let signers: Secp256k1Signer[];
17
+
18
+ // Check that metrics are recorded correctly
19
+ let metricsMock: MockProxy<PoolInstrumentation<BlockAttestation>>;
20
+
21
+ beforeEach(() => {
22
+ ap = getAttestationPool();
23
+ signers = Array.from({ length: NUMBER_OF_SIGNERS_PER_TEST }, () => Secp256k1Signer.random());
24
+
25
+ metricsMock = mock<PoolInstrumentation<BlockAttestation>>();
26
+ // Can i overwrite this like this??
27
+ (ap as any).metrics = metricsMock;
28
+ });
29
+
30
+ const createAttestationsForSlot = (slotNumber: number) => {
31
+ const archive = Fr.random();
32
+ return signers.map(signer => mockAttestation(signer, slotNumber, archive));
33
+ };
34
+
35
+ // We compare buffers as the objects can have cached values attached to them which are not serialised
36
+ // using array containing as the kv store does not respect insertion order
37
+ const compareAttestations = (a1: BlockAttestation[], a2: BlockAttestation[]) => {
38
+ const a1Buffer = a1.map(attestation => attestation.toBuffer());
39
+ const a2Buffer = a2.map(attestation => attestation.toBuffer());
40
+ expect(a1Buffer.length).toBe(a2Buffer.length);
41
+ expect(a1Buffer).toEqual(expect.arrayContaining(a2Buffer));
42
+ };
43
+
44
+ it('should add attestations to pool', async () => {
45
+ const slotNumber = 420;
46
+ const archive = Fr.random();
47
+ const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
48
+
49
+ await ap.addAttestations(attestations);
50
+
51
+ // Check metrics have been updated.
52
+ expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
53
+
54
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), archive.toString());
55
+
56
+ expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
57
+
58
+ compareAttestations(retreivedAttestations, attestations);
59
+
60
+ // Delete by slot
61
+ await ap.deleteAttestationsForSlot(BigInt(slotNumber));
62
+
63
+ expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length);
64
+
65
+ const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), archive.toString());
66
+ expect(retreivedAttestationsAfterDelete.length).toBe(0);
67
+ });
68
+
69
+ it('Should handle duplicate proposals in a slot', async () => {
70
+ const slotNumber = 420;
71
+ const archive = Fr.random();
72
+ const txs = [0, 1, 2, 3, 4, 5].map(() => TxHash.random());
73
+
74
+ // Use the same signer for all attestations
75
+ const attestations: BlockAttestation[] = [];
76
+ const signer = signers[0];
77
+ for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
78
+ attestations.push(mockAttestation(signer, slotNumber, archive, txs));
79
+ }
80
+
81
+ await ap.addAttestations(attestations);
82
+
83
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), archive.toString());
84
+ expect(retreivedAttestations.length).toBe(1);
85
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
86
+ expect(retreivedAttestations[0].payload.txHashes).toEqual(txs);
87
+ expect(retreivedAttestations[0].getSender().toString()).toEqual(signer.address.toString());
88
+ });
89
+
90
+ it('Should store attestations by differing slot', async () => {
91
+ const slotNumbers = [1, 2, 3, 4];
92
+ const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i]));
93
+
94
+ await ap.addAttestations(attestations);
95
+
96
+ for (const attestation of attestations) {
97
+ const slot = attestation.payload.header.globalVariables.slotNumber;
98
+ const archive = attestation.archive.toString();
99
+
100
+ const retreivedAttestations = await ap.getAttestationsForSlot(slot.toBigInt(), archive);
101
+ expect(retreivedAttestations.length).toBe(1);
102
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
103
+ expect(retreivedAttestations[0].payload.header.globalVariables.slotNumber).toEqual(slot);
104
+ }
105
+ });
106
+
107
+ it('Should store attestations by differing slot and archive', async () => {
108
+ const slotNumbers = [1, 1, 2, 3];
109
+ const archives = [Fr.random(), Fr.random(), Fr.random(), Fr.random()];
110
+ const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i], archives[i]));
111
+
112
+ await ap.addAttestations(attestations);
113
+
114
+ for (const attestation of attestations) {
115
+ const slot = attestation.payload.header.globalVariables.slotNumber;
116
+ const proposalId = attestation.archive.toString();
117
+
118
+ const retreivedAttestations = await ap.getAttestationsForSlot(slot.toBigInt(), proposalId);
119
+ expect(retreivedAttestations.length).toBe(1);
120
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
121
+ expect(retreivedAttestations[0].payload.header.globalVariables.slotNumber).toEqual(slot);
122
+ }
123
+ });
124
+
125
+ it('Should delete attestations', async () => {
126
+ const slotNumber = 420;
127
+ const archive = Fr.random();
128
+ const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
129
+ const proposalId = attestations[0].archive.toString();
130
+
131
+ await ap.addAttestations(attestations);
132
+
133
+ expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
134
+
135
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
136
+ expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
137
+ compareAttestations(retreivedAttestations, attestations);
138
+
139
+ await ap.deleteAttestations(attestations);
140
+
141
+ expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length);
142
+
143
+ const gottenAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
144
+ expect(gottenAfterDelete.length).toBe(0);
145
+ });
146
+
147
+ it('Should blanket delete attestations per slot', async () => {
148
+ const slotNumber = 420;
149
+ const archive = Fr.random();
150
+ const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
151
+ const proposalId = attestations[0].archive.toString();
152
+
153
+ await ap.addAttestations(attestations);
154
+
155
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
156
+ expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
157
+ compareAttestations(retreivedAttestations, attestations);
158
+
159
+ await ap.deleteAttestationsForSlot(BigInt(slotNumber));
160
+
161
+ const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
162
+ expect(retreivedAttestationsAfterDelete.length).toBe(0);
163
+ });
164
+
165
+ it('Should blanket delete attestations per slot and proposal', async () => {
166
+ const slotNumber = 420;
167
+ const archive = Fr.random();
168
+ const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
169
+ const proposalId = attestations[0].archive.toString();
170
+
171
+ // Add another set of attestations with a different proposalId, yet the same slot
172
+ const archive2 = Fr.random();
173
+ const attestations2 = signers.map(signer => mockAttestation(signer, slotNumber, archive2));
174
+ const proposalId2 = attestations2[0].archive.toString();
175
+
176
+ await ap.addAttestations(attestations);
177
+ await ap.addAttestations(attestations2);
178
+
179
+ expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
180
+ expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations2.length);
181
+
182
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
183
+ expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
184
+ compareAttestations(retreivedAttestations, attestations);
185
+
186
+ await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
187
+
188
+ expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length);
189
+
190
+ const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
191
+ expect(retreivedAttestationsAfterDelete.length).toBe(0);
192
+
193
+ const retreivedAttestationsAfterDeleteForOtherProposal = await ap.getAttestationsForSlot(
194
+ BigInt(slotNumber),
195
+ proposalId2,
196
+ );
197
+ expect(retreivedAttestationsAfterDeleteForOtherProposal.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
198
+ compareAttestations(retreivedAttestationsAfterDeleteForOtherProposal, attestations2);
199
+ });
200
+
201
+ it('Should blanket delete attestations per slot and proposal (does not perform db ops if there are no attestations)', async () => {
202
+ const slotNumber = 420;
203
+ const proposalId = 'proposalId';
204
+
205
+ const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
206
+ expect(retreivedAttestations.length).toBe(0);
207
+
208
+ await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
209
+
210
+ expect(metricsMock.recordRemovedObjects).toHaveBeenCalledTimes(0);
211
+ });
212
+
213
+ it('Should delete attestations older than a given slot', async () => {
214
+ const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
215
+ const attestations = slotNumbers.map(slotNumber => createAttestationsForSlot(slotNumber)).flat();
216
+ const proposalId = attestations[0].archive.toString();
217
+
218
+ await ap.addAttestations(attestations);
219
+
220
+ const attestationsForSlot1 = await ap.getAttestationsForSlot(BigInt(1), proposalId);
221
+ expect(attestationsForSlot1.length).toBe(signers.length);
222
+
223
+ const deleteAttestationsSpy = jest.spyOn(ap, 'deleteAttestationsForSlot');
224
+
225
+ await ap.deleteAttestationsOlderThan(BigInt(73));
226
+
227
+ const attestationsForSlot1AfterDelete = await ap.getAttestationsForSlot(BigInt(1), proposalId);
228
+ expect(attestationsForSlot1AfterDelete.length).toBe(0);
229
+
230
+ expect(deleteAttestationsSpy).toHaveBeenCalledTimes(5);
231
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(1));
232
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(2));
233
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(3));
234
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(69));
235
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(72));
236
+ });
237
+ }