@aztec/p2p 0.0.1-commit.7035c9bd6 → 0.0.1-commit.71324e566

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 (225) hide show
  1. package/dest/client/factory.d.ts +1 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +5 -4
  4. package/dest/client/interface.d.ts +9 -2
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +3 -2
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +30 -10
  9. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +16 -6
  10. package/dest/config.d.ts +103 -99
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +10 -5
  13. package/dest/errors/p2p-service.error.d.ts +9 -0
  14. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  15. package/dest/errors/p2p-service.error.js +10 -0
  16. package/dest/index.d.ts +1 -2
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +0 -1
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -2
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.js +8 -5
  22. package/dest/mem_pools/index.d.ts +1 -2
  23. package/dest/mem_pools/index.d.ts.map +1 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  25. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +1 -1
  26. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  27. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +6 -2
  28. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
  29. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  30. package/dest/msg_validators/attestation_validator/attestation_validator.js +17 -9
  31. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -2
  32. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  33. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
  34. package/dest/msg_validators/clock_tolerance.d.ts +12 -1
  35. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  36. package/dest/msg_validators/clock_tolerance.js +50 -0
  37. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
  38. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  39. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +2 -1
  40. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  41. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
  42. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  43. package/dest/msg_validators/proposal_validator/proposal_validator.js +16 -8
  44. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  45. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  46. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  47. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  48. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  49. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  50. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  51. package/dest/msg_validators/tx_validator/factory.d.ts +1 -1
  52. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  53. package/dest/msg_validators/tx_validator/factory.js +8 -2
  54. package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
  55. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  56. package/dest/msg_validators/tx_validator/gas_validator.js +11 -9
  57. package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
  58. package/dest/services/data_store.d.ts +1 -1
  59. package/dest/services/data_store.d.ts.map +1 -1
  60. package/dest/services/data_store.js +5 -5
  61. package/dest/services/dummy_service.d.ts +6 -3
  62. package/dest/services/dummy_service.d.ts.map +1 -1
  63. package/dest/services/dummy_service.js +6 -1
  64. package/dest/services/gossipsub/topic_score_params.d.ts +13 -2
  65. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  66. package/dest/services/gossipsub/topic_score_params.js +21 -4
  67. package/dest/services/libp2p/libp2p_service.d.ts +15 -18
  68. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  69. package/dest/services/libp2p/libp2p_service.js +117 -91
  70. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  71. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  72. package/dest/services/peer-manager/peer_manager.js +35 -8
  73. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  74. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  75. package/dest/services/peer-manager/peer_scoring.js +32 -10
  76. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -1
  77. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  78. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +3 -0
  79. package/dest/services/reqresp/config.d.ts +3 -3
  80. package/dest/services/reqresp/config.d.ts.map +1 -1
  81. package/dest/services/reqresp/interface.d.ts +14 -9
  82. package/dest/services/reqresp/interface.d.ts.map +1 -1
  83. package/dest/services/reqresp/interface.js +10 -11
  84. package/dest/services/reqresp/metrics.d.ts +1 -1
  85. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  86. package/dest/services/reqresp/metrics.js +0 -1
  87. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  88. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  89. package/dest/services/reqresp/protocols/index.js +0 -1
  90. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  91. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  92. package/dest/services/reqresp/protocols/tx.js +1 -3
  93. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  94. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  95. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  96. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  97. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  98. package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
  99. package/dest/services/reqresp/reqresp.d.ts +4 -2
  100. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  101. package/dest/services/reqresp/reqresp.js +11 -2
  102. package/dest/services/service.d.ts +5 -2
  103. package/dest/services/service.d.ts.map +1 -1
  104. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  105. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  106. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  107. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  108. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  109. package/dest/services/tx_collection/tx_source.js +9 -7
  110. package/dest/test-helpers/mock-pubsub.d.ts +11 -3
  111. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  112. package/dest/test-helpers/mock-pubsub.js +35 -10
  113. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  114. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  115. package/dest/test-helpers/reqresp-nodes.js +1 -2
  116. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  117. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  118. package/dest/test-helpers/testbench-utils.js +1 -0
  119. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  120. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  121. package/dest/testbench/p2p_client_testbench_worker.js +65 -15
  122. package/dest/testbench/worker_client_manager.d.ts +8 -1
  123. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  124. package/dest/testbench/worker_client_manager.js +49 -1
  125. package/package.json +14 -14
  126. package/src/client/factory.ts +7 -2
  127. package/src/client/interface.ts +9 -1
  128. package/src/client/p2p_client.ts +34 -11
  129. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +17 -6
  130. package/src/config.ts +18 -6
  131. package/src/errors/p2p-service.error.ts +11 -0
  132. package/src/index.ts +0 -1
  133. package/src/mem_pools/attestation_pool/attestation_pool.ts +9 -5
  134. package/src/mem_pools/index.ts +0 -3
  135. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
  136. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +8 -2
  137. package/src/msg_validators/attestation_validator/attestation_validator.ts +18 -7
  138. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
  139. package/src/msg_validators/clock_tolerance.ts +68 -0
  140. package/src/msg_validators/proposal_validator/README.md +1 -1
  141. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -1
  142. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +4 -1
  143. package/src/msg_validators/proposal_validator/proposal_validator.ts +13 -7
  144. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  145. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  146. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  147. package/src/msg_validators/tx_validator/factory.ts +7 -0
  148. package/src/msg_validators/tx_validator/gas_validator.ts +25 -9
  149. package/src/msg_validators/tx_validator/phases_validator.ts +1 -1
  150. package/src/services/data_store.ts +5 -13
  151. package/src/services/dummy_service.ts +8 -2
  152. package/src/services/gossipsub/topic_score_params.ts +36 -4
  153. package/src/services/libp2p/libp2p_service.ts +117 -102
  154. package/src/services/peer-manager/peer_manager.ts +40 -8
  155. package/src/services/peer-manager/peer_scoring.ts +27 -5
  156. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +3 -0
  157. package/src/services/reqresp/config.ts +2 -2
  158. package/src/services/reqresp/interface.ts +21 -11
  159. package/src/services/reqresp/metrics.ts +0 -1
  160. package/src/services/reqresp/protocols/index.ts +0 -1
  161. package/src/services/reqresp/protocols/tx.ts +1 -3
  162. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  163. package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
  164. package/src/services/reqresp/reqresp.ts +18 -1
  165. package/src/services/service.ts +6 -1
  166. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  167. package/src/services/tx_collection/tx_source.ts +8 -7
  168. package/src/test-helpers/mock-pubsub.ts +31 -5
  169. package/src/test-helpers/reqresp-nodes.ts +2 -2
  170. package/src/test-helpers/testbench-utils.ts +1 -0
  171. package/src/testbench/p2p_client_testbench_worker.ts +70 -12
  172. package/src/testbench/worker_client_manager.ts +55 -1
  173. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  174. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  175. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  176. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  177. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  178. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  179. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  180. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  181. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  182. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  183. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  184. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
  185. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  186. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  187. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  188. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  189. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  190. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  191. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  192. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  193. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  194. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  195. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  196. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  197. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  198. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  199. package/dest/mem_pools/tx_pool/index.js +0 -2
  200. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  201. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  202. package/dest/mem_pools/tx_pool/priority.js +0 -15
  203. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  204. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  205. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  206. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  207. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  208. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
  209. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  210. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  211. package/dest/services/reqresp/protocols/block.js +0 -32
  212. package/src/mem_pools/tx_pool/README.md +0 -270
  213. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  214. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  215. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  216. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
  217. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  218. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  219. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  220. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  221. package/src/mem_pools/tx_pool/index.ts +0 -2
  222. package/src/mem_pools/tx_pool/priority.ts +0 -20
  223. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  224. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
  225. package/src/services/reqresp/protocols/block.ts +0 -37
@@ -1,13 +1,12 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
3
  import { maxBy } from '@aztec/foundation/collection';
4
- import { Fr } from '@aztec/foundation/curves/bn254';
5
4
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
6
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
7
6
  import { Timer } from '@aztec/foundation/timer';
8
7
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
9
8
  import { protocolContractsHash } from '@aztec/protocol-contracts';
10
- import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
9
+ import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
11
10
  import type { ContractDataSource } from '@aztec/stdlib/contract';
12
11
  import { GasFees } from '@aztec/stdlib/gas';
13
12
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
@@ -58,6 +57,7 @@ import { ENR } from '@nethermindeth/enr';
58
57
  import { createLibp2p } from 'libp2p';
59
58
 
60
59
  import type { P2PConfig } from '../../config.js';
60
+ import { CheckpointProposalReceivedCallbackNotRegisteredError } from '../../errors/p2p-service.error.js';
61
61
  import type { MemPools } from '../../mem_pools/interface.js';
62
62
  import {
63
63
  BlockProposalValidator,
@@ -104,7 +104,6 @@ import {
104
104
  ValidationError,
105
105
  pingHandler,
106
106
  reqGoodbyeHandler,
107
- reqRespBlockHandler,
108
107
  reqRespBlockTxsHandler,
109
108
  reqRespStatusHandler,
110
109
  reqRespTxHandler,
@@ -130,7 +129,7 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
130
129
  // REFACTOR: Unify with the type above
131
130
  type ReceivedMessageValidationResult<T, M = undefined> =
132
131
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
133
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
132
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
134
133
 
135
134
  /**
136
135
  * Lib P2P implementation of the P2PService interface.
@@ -171,7 +170,13 @@ export class LibP2PService extends WithTracer implements P2PService {
171
170
  * @param checkpoint - The checkpoint proposal received from the peer.
172
171
  * @returns The attestations for the checkpoint, if any.
173
172
  */
174
- private checkpointReceivedCallback: P2PCheckpointReceivedCallback;
173
+ private allNodesCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
174
+ /**
175
+ * Callback for when a checkpoint proposal is received - specifically for validators - from a peer.
176
+ * @param checkpoint - The checkpoint proposal received from the peer.
177
+ * @returns The attestations for the checkpoint, if any.
178
+ */
179
+ private validatorCheckpointReceivedCallback: P2PCheckpointReceivedCallback;
175
180
 
176
181
  private gossipSubEventHandler: (e: CustomEvent<GossipsubMessage>) => void;
177
182
 
@@ -223,15 +228,19 @@ export class LibP2PService extends WithTracer implements P2PService {
223
228
  this.protocolVersion,
224
229
  );
225
230
 
231
+ const p2pPropagationTime = config.attestationPropagationTime;
226
232
  const proposalValidatorOpts = {
227
233
  txsPermitted: !config.disableTransactions,
228
234
  maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
235
+ p2pPropagationTime,
229
236
  };
230
237
  this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
231
238
  this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
232
239
  this.checkpointAttestationValidator = config.fishermanMode
233
- ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
234
- : new CheckpointAttestationValidator(epochCache);
240
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry, {
241
+ l1PublishingTime: config.l1PublishingTime,
242
+ })
243
+ : new CheckpointAttestationValidator(epochCache, { l1PublishingTime: config.l1PublishingTime });
235
244
 
236
245
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
237
246
 
@@ -243,12 +252,15 @@ export class LibP2PService extends WithTracer implements P2PService {
243
252
  return true;
244
253
  };
245
254
 
246
- this.checkpointReceivedCallback = (
247
- checkpoint: CheckpointProposalCore,
255
+ this.allNodesCheckpointReceivedCallback = (
256
+ _checkpoint: CheckpointProposalCore,
257
+ ): Promise<CheckpointAttestation[] | undefined> => {
258
+ throw new CheckpointProposalReceivedCallbackNotRegisteredError();
259
+ };
260
+
261
+ this.validatorCheckpointReceivedCallback = (
262
+ _checkpoint: CheckpointProposalCore,
248
263
  ): Promise<CheckpointAttestation[] | undefined> => {
249
- this.logger.debug(
250
- `Handler not yet registered: Checkpoint received callback not set. Received checkpoint for slot ${checkpoint.slotNumber} from peer.`,
251
- );
252
264
  return Promise.resolve(undefined);
253
265
  };
254
266
  }
@@ -338,9 +350,12 @@ export class LibP2PService extends WithTracer implements P2PService {
338
350
  const l1Constants = epochCache.getL1Constants();
339
351
  const topicScoreParams = createAllTopicScoreParams(protocolVersion, {
340
352
  slotDurationMs: l1Constants.slotDuration * 1000,
353
+ ethereumSlotDuration: l1Constants.ethereumSlotDuration,
341
354
  heartbeatIntervalMs: config.gossipsubInterval,
342
355
  targetCommitteeSize: l1Constants.targetCommitteeSize,
343
356
  blockDurationMs: config.blockDurationMs,
357
+ l1PublishingTime: config.l1PublishingTime,
358
+ p2pPropagationTime: config.attestationPropagationTime,
344
359
  expectedBlockProposalsPerSlot: config.expectedBlockProposalsPerSlot,
345
360
  });
346
361
 
@@ -465,6 +480,9 @@ export class LibP2PService extends WithTracer implements P2PService {
465
480
  epochCache,
466
481
  );
467
482
 
483
+ // Gate req/resp data protocols for unauthenticated peers when p2pAllowOnlyValidators is enabled
484
+ reqresp.setShouldRejectPeer(peerId => peerManager.shouldDisableP2PGossip(peerId));
485
+
468
486
  // Configure application-specific scoring for gossipsub.
469
487
  // The weight scales app score to align with gossipsub thresholds:
470
488
  // - Disconnect (-50) × 10 = -500 = gossipThreshold (stops receiving gossip)
@@ -510,14 +528,12 @@ export class LibP2PService extends WithTracer implements P2PService {
510
528
  // Create request response protocol handlers
511
529
  const txHandler = reqRespTxHandler(this.mempools);
512
530
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
513
- const blockHandler = reqRespBlockHandler(this.archiver);
514
531
  const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
515
532
 
516
533
  const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
517
534
  [ReqRespSubProtocol.PING]: pingHandler,
518
535
  [ReqRespSubProtocol.STATUS]: statusHandler.bind(this),
519
536
  [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
520
- [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
521
537
  };
522
538
 
523
539
  if (!this.config.disableTransactions) {
@@ -538,7 +554,6 @@ export class LibP2PService extends WithTracer implements P2PService {
538
554
  ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
539
555
  [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
540
556
  [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
541
- [ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
542
557
  };
543
558
 
544
559
  await this.peerManager.initializePeers();
@@ -666,8 +681,16 @@ export class LibP2PService extends WithTracer implements P2PService {
666
681
  this.blockReceivedCallback = callback;
667
682
  }
668
683
 
669
- public registerCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
670
- this.checkpointReceivedCallback = callback;
684
+ public registerValidatorCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
685
+ this.validatorCheckpointReceivedCallback = callback;
686
+ }
687
+
688
+ public registerAllNodesCheckpointReceivedCallback(callback: P2PCheckpointReceivedCallback) {
689
+ this.allNodesCheckpointReceivedCallback = callback;
690
+ }
691
+
692
+ public async notifyOwnCheckpointProposal(checkpoint: CheckpointProposalCore): Promise<void> {
693
+ await this.allNodesCheckpointReceivedCallback(checkpoint, this.node.peerId);
671
694
  }
672
695
 
673
696
  /**
@@ -882,30 +905,56 @@ export class LibP2PService extends WithTracer implements P2PService {
882
905
  source: PeerId,
883
906
  topicType: TopicType,
884
907
  ): Promise<ReceivedMessageValidationResult<T, M>> {
885
- let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
908
+ // Default to reject result with a penalty if validation function throws an error
909
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
910
+ result: TopicValidatorResult.Reject,
911
+ severity: PeerErrorSeverity.MidToleranceError,
912
+ };
886
913
  const timer = new Timer();
887
914
  try {
888
915
  resultAndObj = await validationFunc();
889
916
  } catch (err) {
890
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
891
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
892
- msgId,
893
- source: source.toString(),
894
- topicType,
895
- });
917
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
896
918
  }
897
919
 
898
920
  if (resultAndObj.result === TopicValidatorResult.Accept) {
921
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
899
922
  this.instrumentation.recordMessageValidation(topicType, timer);
923
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
924
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
925
+ msgId,
926
+ source: source.toString(),
927
+ topicType,
928
+ severity: resultAndObj.severity,
929
+ });
930
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
931
+ } else {
932
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
900
933
  }
901
934
 
902
935
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
903
936
  return resultAndObj;
904
937
  }
905
938
 
939
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
940
+ try {
941
+ return deserializeFunc();
942
+ } catch (err) {
943
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
944
+ err,
945
+ msgId,
946
+ source: source.toString(),
947
+ });
948
+ return undefined;
949
+ }
950
+ }
951
+
906
952
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
907
953
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
908
- const tx = Tx.fromBuffer(payloadData);
954
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
955
+ if (!tx) {
956
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
957
+ }
909
958
 
910
959
  const currentBlockNumber = await this.archiver.getBlockNumber();
911
960
  const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
@@ -930,8 +979,7 @@ export class LibP2PService extends WithTracer implements P2PService {
930
979
  severity,
931
980
  source: source.toString(),
932
981
  });
933
- this.peerManager.penalizePeer(source, severity);
934
- return { result: TopicValidatorResult.Reject };
982
+ return { result: TopicValidatorResult.Reject, severity };
935
983
  }
936
984
 
937
985
  // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
@@ -953,8 +1001,7 @@ export class LibP2PService extends WithTracer implements P2PService {
953
1001
  severity,
954
1002
  source: source.toString(),
955
1003
  });
956
- this.peerManager.penalizePeer(source, severity);
957
- return { result: TopicValidatorResult.Reject };
1004
+ return { result: TopicValidatorResult.Reject, severity };
958
1005
  }
959
1006
 
960
1007
  // Pool add: persist the tx
@@ -979,8 +1026,7 @@ export class LibP2PService extends WithTracer implements P2PService {
979
1026
  source: source.toString(),
980
1027
  txHash: txHash.toString(),
981
1028
  });
982
- this.peerManager.penalizePeer(source, PeerErrorSeverity.HighToleranceError);
983
- return { result: TopicValidatorResult.Reject };
1029
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
984
1030
  }
985
1031
  };
986
1032
 
@@ -1010,7 +1056,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1010
1056
  source: PeerId,
1011
1057
  ): Promise<void> {
1012
1058
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
1013
- () => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
1059
+ () => {
1060
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1061
+ if (!attestation) {
1062
+ return Promise.resolve({
1063
+ result: TopicValidatorResult.Reject,
1064
+ severity: PeerErrorSeverity.LowToleranceError,
1065
+ });
1066
+ }
1067
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1068
+ },
1014
1069
  msgId,
1015
1070
  source,
1016
1071
  TopicType.checkpoint_attestation,
@@ -1043,8 +1098,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1043
1098
 
1044
1099
  if (validationResult.result === 'reject') {
1045
1100
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1046
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1047
- return { result: TopicValidatorResult.Reject };
1101
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1048
1102
  }
1049
1103
 
1050
1104
  if (validationResult.result === 'ignore') {
@@ -1070,16 +1124,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1070
1124
  return { result: TopicValidatorResult.Ignore, obj: attestation };
1071
1125
  }
1072
1126
 
1073
- // Could not add (cap reached for signer), no need to re-broadcast
1127
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1074
1128
  if (!added) {
1075
- this.logger.warn(`Dropping checkpoint attestation due to cap`, {
1129
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1076
1130
  slot: slot.toString(),
1077
1131
  archive: attestation.archive.toString(),
1078
1132
  source: peerId.toString(),
1079
1133
  attester: attestation.getSender()?.toString(),
1080
1134
  count,
1081
1135
  });
1082
- return { result: TopicValidatorResult.Ignore, obj: attestation };
1136
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1083
1137
  }
1084
1138
 
1085
1139
  // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
@@ -1134,8 +1188,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1134
1188
 
1135
1189
  if (validationResult.result === 'reject') {
1136
1190
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1137
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1138
- return { result: TopicValidatorResult.Reject };
1191
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1139
1192
  }
1140
1193
 
1141
1194
  if (validationResult.result === 'ignore') {
@@ -1159,7 +1212,6 @@ export class LibP2PService extends WithTracer implements P2PService {
1159
1212
 
1160
1213
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1161
1214
  if (!added) {
1162
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1163
1215
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1164
1216
  ...block.toBlockInfo(),
1165
1217
  indexWithinCheckpoint: block.indexWithinCheckpoint,
@@ -1167,7 +1219,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1167
1219
  proposer: block.getSender()?.toString(),
1168
1220
  source: peerId.toString(),
1169
1221
  });
1170
- return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
1222
+ return {
1223
+ result: TopicValidatorResult.Reject,
1224
+ metadata: { isEquivocated },
1225
+ severity: PeerErrorSeverity.HighToleranceError,
1226
+ };
1171
1227
  }
1172
1228
 
1173
1229
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1260,8 +1316,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1260
1316
 
1261
1317
  if (validationResult.result === 'reject') {
1262
1318
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1263
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1264
- return { result: TopicValidatorResult.Reject };
1319
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1265
1320
  }
1266
1321
 
1267
1322
  if (validationResult.result === 'ignore') {
@@ -1276,20 +1331,21 @@ export class LibP2PService extends WithTracer implements P2PService {
1276
1331
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1277
1332
  [Attributes.P2P_ID]: peerId.toString(),
1278
1333
  });
1279
- const {
1280
- result,
1281
- obj,
1282
- metadata: { isEquivocated } = {},
1283
- } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1284
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1334
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1335
+ const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1336
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1285
1337
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1286
1338
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1287
1339
  [Attributes.P2P_ID]: peerId.toString(),
1288
1340
  isEquivocated,
1289
- result,
1341
+ result: blockProposalResult.result,
1290
1342
  });
1291
- return { result: TopicValidatorResult.Reject };
1292
- } else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1343
+ return {
1344
+ result: TopicValidatorResult.Reject,
1345
+ severity:
1346
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1347
+ };
1348
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1293
1349
  processBlock = true;
1294
1350
  }
1295
1351
  }
@@ -1316,13 +1372,17 @@ export class LibP2PService extends WithTracer implements P2PService {
1316
1372
  // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1317
1373
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1318
1374
  if (!added) {
1319
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1320
1375
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1321
1376
  ...checkpoint.toCheckpointInfo(),
1322
1377
  count,
1323
1378
  source: peerId.toString(),
1324
1379
  });
1325
- return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
1380
+ return {
1381
+ result: TopicValidatorResult.Reject,
1382
+ obj: checkpoint,
1383
+ metadata: { isEquivocated, processBlock },
1384
+ severity: PeerErrorSeverity.HighToleranceError,
1385
+ };
1326
1386
  }
1327
1387
 
1328
1388
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1367,9 +1427,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1367
1427
  source: sender.toString(),
1368
1428
  });
1369
1429
 
1430
+ await this.allNodesCheckpointReceivedCallback(checkpoint, sender);
1431
+
1370
1432
  // Call the checkpoint received callback with the core version (without lastBlock)
1371
1433
  // to validate and potentially generate attestations
1372
- const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
1434
+ const attestations = await this.validatorCheckpointReceivedCallback(checkpoint, sender);
1373
1435
  if (attestations && attestations.length > 0) {
1374
1436
  // If the callback returned attestations, add them to the pool and propagate them
1375
1437
  await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
@@ -1517,53 +1579,6 @@ export class LibP2PService extends WithTracer implements P2PService {
1517
1579
  }
1518
1580
  }
1519
1581
 
1520
- /**
1521
- * Validates a BLOCK response.
1522
- *
1523
- * If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
1524
- * Penalizes on block number mismatch or hash mismatch.
1525
- *
1526
- * @param requestedBlockNumber - The requested block number.
1527
- * @param responseBlock - The block returned by the peer.
1528
- * @param peerId - The peer that returned the block.
1529
- * @returns True if the response is valid, false otherwise.
1530
- */
1531
- @trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
1532
- [Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
1533
- }))
1534
- protected async validateRequestedBlock(
1535
- requestedBlockNumber: Fr,
1536
- responseBlock: L2Block,
1537
- peerId: PeerId,
1538
- ): Promise<boolean> {
1539
- try {
1540
- const reqNum = Number(requestedBlockNumber.toString());
1541
- if (responseBlock.number !== reqNum) {
1542
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
1543
- return false;
1544
- }
1545
-
1546
- const local = await this.archiver.getBlock(BlockNumber(reqNum));
1547
- if (!local) {
1548
- // We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
1549
- // TODO: Consider extending this validator to accept an expected hash or
1550
- // performing quorum-based checks when using P2P syncing prior to L1 sync.
1551
- this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
1552
- return false;
1553
- }
1554
- const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
1555
- if (!localHash.equals(respHash)) {
1556
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
1557
- return false;
1558
- }
1559
-
1560
- return true;
1561
- } catch (e) {
1562
- this.logger.warn(`Error validating requested block`, e);
1563
- return false;
1564
- }
1565
- }
1566
-
1567
1582
  protected async validateRequestedTx(
1568
1583
  tx: Tx,
1569
1584
  peerId: PeerId,
@@ -226,20 +226,30 @@ export class PeerManager implements PeerManagerInterface {
226
226
  }
227
227
 
228
228
  /**
229
- * Cleans up expired timeouts.
229
+ * Cleans up expired timeouts and stale failed-auth-handshake entries.
230
230
  *
231
231
  * When peers fail to dial after a number of retries, they are temporarily timed out.
232
232
  * This function removes any peers that have been in the timed out state for too long.
233
233
  * To give them a chance to reconnect.
234
+ *
235
+ * Also evicts entries from the failed-auth-handshake map whose expiry window has passed.
236
+ * Without this, peers that probe once and never reconnect would leave their entries in the
237
+ * map forever, causing an unbounded memory leak.
234
238
  */
235
239
  private cleanupExpiredTimeouts() {
236
- // Clean up expired timeouts
237
240
  const now = this.dateProvider.now();
241
+
238
242
  for (const [peerId, timedOutPeer] of this.timedOutPeers.entries()) {
239
243
  if (now >= timedOutPeer.timeoutUntilMs) {
240
244
  this.timedOutPeers.delete(peerId);
241
245
  }
242
246
  }
247
+
248
+ for (const [id, entry] of this.failedAuthHandshakes.entries()) {
249
+ if (now - entry.lastFailureTimestamp > FAILED_AUTH_HANDSHAKE_EXPIRY_MS) {
250
+ this.failedAuthHandshakes.delete(id);
251
+ }
252
+ }
243
253
  }
244
254
 
245
255
  /**
@@ -303,15 +313,20 @@ export class PeerManager implements PeerManagerInterface {
303
313
  */
304
314
  private handleDisconnectedPeerEvent(e: CustomEvent<PeerId>) {
305
315
  const peerId = e.detail;
316
+ const peerIdStr = peerId.toString();
306
317
  this.metrics.peerDisconnected(peerId);
307
- this.logger.verbose(`Disconnected from peer ${peerId.toString()}`);
308
- const validatorAddress = this.authenticatedPeerIdToValidatorAddress.get(peerId.toString());
318
+ this.logger.verbose(`Disconnected from peer ${peerIdStr}`);
319
+ const validatorAddress = this.authenticatedPeerIdToValidatorAddress.get(peerIdStr);
309
320
  if (validatorAddress !== undefined) {
310
321
  this.logger.info(
311
- `Removing authentication for validator ${validatorAddress} at peer id ${peerId.toString()} due to disconnection`,
322
+ `Removing authentication for validator ${validatorAddress} at peer id ${peerIdStr} due to disconnection`,
312
323
  );
313
324
  this.authenticatedValidatorAddressToPeerId.delete(validatorAddress.toString());
314
- this.authenticatedPeerIdToValidatorAddress.delete(peerId.toString());
325
+ this.authenticatedPeerIdToValidatorAddress.delete(peerIdStr);
326
+ }
327
+
328
+ if (this.peerScoring.getScoreState(peerIdStr) === PeerScoreState.Healthy) {
329
+ this.peerScoring.removePeer(peerIdStr);
315
330
  }
316
331
  }
317
332
 
@@ -713,6 +728,12 @@ export class PeerManager implements PeerManagerInterface {
713
728
  return;
714
729
  }
715
730
 
731
+ // Don't dial peers that have exceeded the auth failure threshold
732
+ if (!this.isNodeAllowedToConnect(peerId)) {
733
+ this.logger.trace(`Skipping peer ${peerId} due to failed auth handshake attempts`);
734
+ return;
735
+ }
736
+
716
737
  const [multiaddrTcp] = await Promise.all([enr.getFullMultiaddr('tcp')]);
717
738
 
718
739
  this.logger.trace(`Handling discovered peer ${peerId} at ${multiaddrTcp?.toString() ?? 'undefined address'}`);
@@ -939,6 +960,8 @@ export class PeerManager implements PeerManagerInterface {
939
960
  `Received auth for validator ${sender.toString()} from peer ${peerIdString}, but this validator is already authenticated to peer ${peerForAddress.toString()}`,
940
961
  { ...logData, address: sender.toString() },
941
962
  );
963
+ this.markAuthHandshakeFailed(peerId);
964
+ this.markPeerForDisconnect(peerId);
942
965
  return;
943
966
  }
944
967
 
@@ -968,14 +991,14 @@ export class PeerManager implements PeerManagerInterface {
968
991
  const peerIdStr = peerId.toString();
969
992
 
970
993
  const existingEntry = this.failedAuthHandshakes.get(peerIdStr);
994
+ const failureCount = (existingEntry?.count || 0) + 1;
971
995
  this.failedAuthHandshakes.set(peerIdStr, {
972
- count: (existingEntry?.count || 0) + 1,
996
+ count: failureCount,
973
997
  lastFailureTimestamp: now,
974
998
  });
975
999
 
976
1000
  const connections = this.libP2PNode.getConnections(peerId);
977
1001
  connections.forEach(conn => {
978
- // We mark the IP address
979
1002
  const address = conn.remoteAddr.nodeAddress().address;
980
1003
  const existingAddressEntry = this.failedAuthHandshakes.get(address);
981
1004
  this.failedAuthHandshakes.set(address, {
@@ -983,6 +1006,15 @@ export class PeerManager implements PeerManagerInterface {
983
1006
  lastFailureTimestamp: now,
984
1007
  });
985
1008
  });
1009
+
1010
+ // Ban the peer from being re-dialed for a cooldown period (exponential backoff)
1011
+ const banTimeMs = this.config.peerFailedBanTimeMs ?? DEFAULT_FAILED_PEER_BAN_TIME_MS;
1012
+ const backoffMs = banTimeMs * Math.pow(2, Math.min(failureCount - 1, 5));
1013
+ this.timedOutPeers.set(peerIdStr, {
1014
+ peerId: peerIdStr,
1015
+ timeoutUntilMs: now + backoffMs,
1016
+ });
1017
+ this.cachedPeers.delete(peerIdStr);
986
1018
  }
987
1019
 
988
1020
  /*
@@ -1,5 +1,6 @@
1
1
  import { median } from '@aztec/foundation/collection';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
+ import { DateProvider } from '@aztec/foundation/timer';
3
4
  import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
4
5
  import {
5
6
  Attributes,
@@ -54,6 +55,7 @@ export enum PeerScoreState {
54
55
  // TODO: move into config / constants
55
56
  const MIN_SCORE_BEFORE_BAN = -100;
56
57
  const MIN_SCORE_BEFORE_DISCONNECT = -50;
58
+ const SCORE_CLEANUP_THRESHOLD = 0.1;
57
59
 
58
60
  export class PeerScoring {
59
61
  private logger = createLogger('p2p:peer-scoring');
@@ -65,7 +67,11 @@ export class PeerScoring {
65
67
 
66
68
  private peerStateCounter: UpDownCounter;
67
69
 
68
- constructor(config: P2PConfig, telemetry: TelemetryClient = getTelemetryClient()) {
70
+ constructor(
71
+ config: P2PConfig,
72
+ telemetry: TelemetryClient = getTelemetryClient(),
73
+ private readonly dateProvider: DateProvider = new DateProvider(),
74
+ ) {
69
75
  const orderedValues = config.peerPenaltyValues?.sort((a, b) => a - b);
70
76
  this.peerPenalties = {
71
77
  [PeerErrorSeverity.HighToleranceError]:
@@ -92,7 +98,7 @@ export class PeerScoring {
92
98
  }
93
99
 
94
100
  updateScore(peerId: string, scoreDelta: number): number {
95
- const currentTime = Date.now();
101
+ const currentTime = this.dateProvider.now();
96
102
  const lastUpdate = this.lastUpdateTime.get(peerId) || currentTime;
97
103
  const timePassed = currentTime - lastUpdate;
98
104
  const decayPeriods = Math.floor(timePassed / this.decayInterval);
@@ -111,19 +117,35 @@ export class PeerScoring {
111
117
  }
112
118
 
113
119
  decayAllScores(): void {
114
- const currentTime = Date.now();
120
+ const currentTime = this.dateProvider.now();
115
121
  for (const [peerId, lastUpdate] of this.lastUpdateTime.entries()) {
116
122
  const timePassed = currentTime - lastUpdate;
117
123
  const decayPeriods = Math.floor(timePassed / this.decayInterval);
118
124
  if (decayPeriods > 0) {
119
125
  let score = this.scores.get(peerId) || 0;
120
126
  score *= Math.pow(this.decayFactor, decayPeriods);
121
- this.scores.set(peerId, score);
122
- this.lastUpdateTime.set(peerId, currentTime);
127
+ if (Math.abs(score) < SCORE_CLEANUP_THRESHOLD) {
128
+ this.scores.delete(peerId);
129
+ this.lastUpdateTime.delete(peerId);
130
+ } else {
131
+ this.scores.set(peerId, score);
132
+ this.lastUpdateTime.set(peerId, currentTime);
133
+ }
123
134
  }
124
135
  }
125
136
  }
126
137
 
138
+ /** Resets all peer scores. Useful for benchmarks to prevent cross-case contamination. */
139
+ resetAllScores(): void {
140
+ this.scores.clear();
141
+ this.lastUpdateTime.clear();
142
+ }
143
+
144
+ removePeer(peerId: string): void {
145
+ this.scores.delete(peerId);
146
+ this.lastUpdateTime.delete(peerId);
147
+ }
148
+
127
149
  getScore(peerId: string): number {
128
150
  return this.scores.get(peerId) || 0;
129
151
  }
@@ -514,6 +514,9 @@ export class BatchTxRequester {
514
514
  });
515
515
 
516
516
  if (hasInvalidTx) {
517
+ this.logger.warn(`Penalizing peer ${peerId.toString()} for sending invalid transactions in batch response`, {
518
+ peerId,
519
+ });
517
520
  this.peers.penalisePeer(peerId, PeerErrorSeverity.LowToleranceError);
518
521
  } else {
519
522
  // If we have received successful response from the peer, they have "redeemed" themselves and not considered bad anymore
@@ -1,4 +1,4 @@
1
- import { type ConfigMapping, booleanConfigHelper, numberConfigHelper } from '@aztec/foundation/config';
1
+ import { type ConfigMappingsType, booleanConfigHelper, numberConfigHelper } from '@aztec/foundation/config';
2
2
 
3
3
  export const DEFAULT_INDIVIDUAL_REQUEST_TIMEOUT_MS = 10_000;
4
4
  export const DEFAULT_OVERALL_REQUEST_TIMEOUT_MS = 10_000; // Not currently used
@@ -27,7 +27,7 @@ export interface P2PReqRespConfig {
27
27
  dialTimeoutMs: number;
28
28
  }
29
29
 
30
- export const p2pReqRespConfigMappings: Record<keyof P2PReqRespConfig, ConfigMapping> = {
30
+ export const p2pReqRespConfigMappings: ConfigMappingsType<P2PReqRespConfig> = {
31
31
  overallRequestTimeoutMs: {
32
32
  env: 'P2P_REQRESP_OVERALL_REQUEST_TIMEOUT_MS',
33
33
  description: 'The overall timeout for a request response operation.',