@aztec/p2p 0.0.1-commit.db765a8 → 0.0.1-commit.df81a97b5

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 (208) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +2 -2
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +21 -8
  5. package/dest/client/p2p_client.d.ts +1 -1
  6. package/dest/client/p2p_client.d.ts.map +1 -1
  7. package/dest/client/p2p_client.js +22 -34
  8. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +3 -3
  9. package/dest/config.d.ts +24 -2
  10. package/dest/config.d.ts.map +1 -1
  11. package/dest/config.js +66 -7
  12. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +3 -3
  13. package/dest/mem_pools/attestation_pool/attestation_pool.js +3 -3
  14. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
  15. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  16. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  17. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
  18. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  19. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  20. package/dest/mem_pools/tx_pool/priority.js +4 -4
  21. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  22. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  25. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +2 -1
  27. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  28. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  32. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  33. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  35. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +9 -5
  36. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  38. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +25 -10
  39. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +33 -10
  41. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  42. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -43
  44. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +4 -2
  45. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  47. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
  48. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +21 -6
  50. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  51. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  52. package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
  53. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  54. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  55. package/dest/msg_validators/clock_tolerance.js +4 -3
  56. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
  57. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  58. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  59. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
  60. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  62. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
  63. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  64. package/dest/msg_validators/proposal_validator/proposal_validator.js +51 -49
  65. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  66. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  67. package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
  68. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  69. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  70. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  71. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  72. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  73. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  74. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  75. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  76. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  77. package/dest/msg_validators/tx_validator/factory.d.ts +23 -4
  78. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  79. package/dest/msg_validators/tx_validator/factory.js +36 -10
  80. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  81. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  82. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  83. package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
  84. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  85. package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
  86. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  87. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  88. package/dest/msg_validators/tx_validator/index.js +1 -0
  89. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  90. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  92. package/dest/msg_validators/tx_validator/phases_validator.d.ts +21 -1
  93. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  94. package/dest/msg_validators/tx_validator/phases_validator.js +49 -2
  95. package/dest/services/encoding.d.ts +5 -1
  96. package/dest/services/encoding.d.ts.map +1 -1
  97. package/dest/services/encoding.js +7 -1
  98. package/dest/services/libp2p/libp2p_service.d.ts +4 -9
  99. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  100. package/dest/services/libp2p/libp2p_service.js +125 -68
  101. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  102. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  103. package/dest/services/peer-manager/peer_manager.js +4 -2
  104. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
  105. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  106. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +69 -65
  107. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
  108. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  109. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  110. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  111. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  112. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +3 -1
  113. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  114. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +3 -0
  115. package/dest/services/reqresp/reqresp.d.ts +1 -1
  116. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  117. package/dest/services/reqresp/reqresp.js +17 -9
  118. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
  119. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  120. package/dest/services/tx_collection/fast_tx_collection.js +57 -73
  121. package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
  122. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  123. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  124. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  125. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  126. package/dest/services/tx_collection/request_tracker.js +84 -0
  127. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  128. package/dest/services/tx_collection/tx_collection.d.ts +3 -6
  129. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  130. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  131. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  132. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  133. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  134. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  135. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  136. package/dest/test-helpers/testbench-utils.js +22 -3
  137. package/dest/testbench/p2p_client_testbench_worker.js +5 -4
  138. package/dest/testbench/worker_client_manager.d.ts +3 -1
  139. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  140. package/dest/testbench/worker_client_manager.js +6 -2
  141. package/dest/util.d.ts +1 -1
  142. package/package.json +14 -14
  143. package/src/client/factory.ts +36 -12
  144. package/src/client/p2p_client.ts +22 -34
  145. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +4 -6
  146. package/src/config.ts +92 -4
  147. package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -3
  148. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  149. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  150. package/src/mem_pools/tx_pool/priority.ts +4 -4
  151. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  152. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  153. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  154. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  155. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  156. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  157. package/src/mem_pools/tx_pool_v2/interfaces.ts +9 -4
  158. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +52 -12
  159. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
  160. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +13 -1
  161. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +23 -6
  162. package/src/msg_validators/attestation_validator/README.md +49 -0
  163. package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
  164. package/src/msg_validators/clock_tolerance.ts +4 -3
  165. package/src/msg_validators/proposal_validator/README.md +123 -0
  166. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
  167. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
  168. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -53
  169. package/src/msg_validators/tx_validator/README.md +5 -1
  170. package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
  171. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  172. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  173. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  174. package/src/msg_validators/tx_validator/factory.ts +43 -3
  175. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  176. package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
  177. package/src/msg_validators/tx_validator/index.ts +1 -0
  178. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  179. package/src/msg_validators/tx_validator/phases_validator.ts +60 -1
  180. package/src/services/encoding.ts +9 -1
  181. package/src/services/libp2p/libp2p_service.ts +118 -78
  182. package/src/services/peer-manager/peer_manager.ts +5 -2
  183. package/src/services/reqresp/README.md +229 -0
  184. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  185. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +64 -69
  186. package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
  187. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  188. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +5 -0
  189. package/src/services/reqresp/reqresp.ts +19 -11
  190. package/src/services/tx_collection/fast_tx_collection.ts +57 -83
  191. package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
  192. package/src/services/tx_collection/request_tracker.ts +127 -0
  193. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  194. package/src/services/tx_collection/tx_collection.ts +3 -5
  195. package/src/test-helpers/make-test-p2p-clients.ts +1 -1
  196. package/src/test-helpers/reqresp-nodes.ts +1 -1
  197. package/src/test-helpers/testbench-utils.ts +29 -3
  198. package/src/testbench/p2p_client_testbench_worker.ts +5 -6
  199. package/src/testbench/worker_client_manager.ts +13 -5
  200. package/src/util.ts +1 -1
  201. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
  202. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  203. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
  204. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  205. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  206. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  207. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
  208. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
@@ -1,5 +1,6 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { maxBy } from '@aztec/foundation/collection';
3
4
  import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -17,8 +18,8 @@ import {
17
18
  type CheckpointProposalCore,
18
19
  type Gossipable,
19
20
  P2PMessage,
20
- type ValidationResult as P2PValidationResult,
21
21
  PeerErrorSeverity,
22
+ PeerErrorSeverityByHarshness,
22
23
  TopicType,
23
24
  createTopicString,
24
25
  getTopicsForConfig,
@@ -129,7 +130,7 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
129
130
  // REFACTOR: Unify with the type above
130
131
  type ReceivedMessageValidationResult<T, M = undefined> =
131
132
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
132
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
133
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
133
134
 
134
135
  /**
135
136
  * Lib P2P implementation of the P2PService interface.
@@ -222,14 +223,12 @@ export class LibP2PService extends WithTracer implements P2PService {
222
223
  this.protocolVersion,
223
224
  );
224
225
 
225
- this.blockProposalValidator = new BlockProposalValidator(epochCache, {
226
+ const proposalValidatorOpts = {
226
227
  txsPermitted: !config.disableTransactions,
227
- maxTxsPerBlock: config.maxTxsPerBlock,
228
- });
229
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
230
- txsPermitted: !config.disableTransactions,
231
- maxTxsPerBlock: config.maxTxsPerBlock,
232
- });
228
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
229
+ };
230
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
231
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
233
232
  this.checkpointAttestationValidator = config.fishermanMode
234
233
  ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
235
234
  : new CheckpointAttestationValidator(epochCache);
@@ -237,11 +236,11 @@ export class LibP2PService extends WithTracer implements P2PService {
237
236
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
238
237
 
239
238
  this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
240
- this.logger.debug(
241
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
239
+ this.logger.warn(
240
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
242
241
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
243
242
  );
244
- return false;
243
+ return true;
245
244
  };
246
245
 
247
246
  this.checkpointReceivedCallback = (
@@ -754,6 +753,9 @@ export class LibP2PService extends WithTracer implements P2PService {
754
753
  if (!validator || !validator.addMessage(msgId)) {
755
754
  this.instrumentation.incMessagePrevalidationStatus(false, topicType);
756
755
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Ignore);
756
+ if (topicType === TopicType.tx) {
757
+ this.logger.verbose(`Ignoring already-seen tx gossip message`, { msgId, source: source.toString() });
758
+ }
757
759
  return { result: false, topicType };
758
760
  }
759
761
 
@@ -880,30 +882,56 @@ export class LibP2PService extends WithTracer implements P2PService {
880
882
  source: PeerId,
881
883
  topicType: TopicType,
882
884
  ): Promise<ReceivedMessageValidationResult<T, M>> {
883
- let resultAndObj: ReceivedMessageValidationResult<T, M> = { result: TopicValidatorResult.Reject };
885
+ // Default to reject result with a penalty if validation function throws an error
886
+ let resultAndObj: ReceivedMessageValidationResult<T, M> = {
887
+ result: TopicValidatorResult.Reject,
888
+ severity: PeerErrorSeverity.MidToleranceError,
889
+ };
884
890
  const timer = new Timer();
885
891
  try {
886
892
  resultAndObj = await validationFunc();
887
893
  } catch (err) {
888
- this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
889
- this.logger.error(`Error deserializing and validating gossipsub message`, err, {
890
- msgId,
891
- source: source.toString(),
892
- topicType,
893
- });
894
+ this.logger.error(`Error validating gossipsub message`, err, { msgId, source: source.toString(), topicType });
894
895
  }
895
896
 
896
897
  if (resultAndObj.result === TopicValidatorResult.Accept) {
898
+ this.logger.debug(`Message ${topicType} accepted by validator`, { msgId, source: source.toString(), topicType });
897
899
  this.instrumentation.recordMessageValidation(topicType, timer);
900
+ } else if (resultAndObj.result === TopicValidatorResult.Reject) {
901
+ this.logger.warn(`Message ${topicType} rejected by validator with severity ${resultAndObj.severity}`, {
902
+ msgId,
903
+ source: source.toString(),
904
+ topicType,
905
+ severity: resultAndObj.severity,
906
+ });
907
+ this.peerManager.penalizePeer(source, resultAndObj.severity);
908
+ } else {
909
+ this.logger.trace(`Message ${topicType} ignored by validator`, { msgId, source: source.toString(), topicType });
898
910
  }
899
911
 
900
912
  this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
901
913
  return resultAndObj;
902
914
  }
903
915
 
916
+ private tryDeserialize<T>(deserializeFunc: () => T, msgId: string, source: PeerId): T | undefined {
917
+ try {
918
+ return deserializeFunc();
919
+ } catch (err) {
920
+ this.logger.warn(`Failed to deserialize gossipsub message from buffer`, {
921
+ err,
922
+ msgId,
923
+ source: source.toString(),
924
+ });
925
+ return undefined;
926
+ }
927
+ }
928
+
904
929
  protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
905
930
  const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
906
- const tx = Tx.fromBuffer(payloadData);
931
+ const tx = this.tryDeserialize(() => Tx.fromBuffer(payloadData), msgId, source);
932
+ if (!tx) {
933
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.LowToleranceError };
934
+ }
907
935
 
908
936
  const currentBlockNumber = await this.archiver.getBlockNumber();
909
937
  const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
@@ -923,13 +951,20 @@ export class LibP2PService extends WithTracer implements P2PService {
923
951
  severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
924
952
  }
925
953
 
926
- this.peerManager.penalizePeer(source, severity);
927
- return { result: TopicValidatorResult.Reject };
954
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
955
+ validator: name,
956
+ severity,
957
+ source: source.toString(),
958
+ });
959
+ return { result: TopicValidatorResult.Reject, severity };
928
960
  }
929
961
 
930
962
  // Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
931
963
  const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
932
964
  if (canAdd === 'ignored') {
965
+ this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
966
+ source: source.toString(),
967
+ });
933
968
  return { result: TopicValidatorResult.Ignore, obj: tx };
934
969
  }
935
970
 
@@ -937,9 +972,13 @@ export class LibP2PService extends WithTracer implements P2PService {
937
972
  const secondStageValidators = this.createSecondStageMessageValidators();
938
973
  const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
939
974
  if (!secondStageOutcome.allPassed) {
940
- const { severity } = secondStageOutcome.failure;
941
- this.peerManager.penalizePeer(source, severity);
942
- return { result: TopicValidatorResult.Reject };
975
+ const { severity, name } = secondStageOutcome.failure;
976
+ this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
977
+ validator: name,
978
+ severity,
979
+ source: source.toString(),
980
+ });
981
+ return { result: TopicValidatorResult.Reject, severity };
943
982
  }
944
983
 
945
984
  // Pool add: persist the tx
@@ -949,7 +988,7 @@ export class LibP2PService extends WithTracer implements P2PService {
949
988
  const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
950
989
  const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
951
990
 
952
- this.logger.trace(`Validate propagated tx`, {
991
+ this.logger.verbose(`Validate propagated tx ${txHash.toString()}`, {
953
992
  wasAccepted,
954
993
  wasIgnored,
955
994
  [Attributes.P2P_ID]: source.toString(),
@@ -960,7 +999,11 @@ export class LibP2PService extends WithTracer implements P2PService {
960
999
  } else if (wasIgnored) {
961
1000
  return { result: TopicValidatorResult.Ignore, obj: tx };
962
1001
  } else {
963
- return { result: TopicValidatorResult.Reject };
1002
+ this.logger.warn(`Gossiped tx ${txHash.toString()} unexpectedly rejected by pool`, {
1003
+ source: source.toString(),
1004
+ txHash: txHash.toString(),
1005
+ });
1006
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
964
1007
  }
965
1008
  };
966
1009
 
@@ -990,7 +1033,16 @@ export class LibP2PService extends WithTracer implements P2PService {
990
1033
  source: PeerId,
991
1034
  ): Promise<void> {
992
1035
  const { result, obj: attestation } = await this.validateReceivedMessage<CheckpointAttestation>(
993
- () => this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)),
1036
+ () => {
1037
+ const attestation = this.tryDeserialize(() => CheckpointAttestation.fromBuffer(payloadData), msgId, source);
1038
+ if (!attestation) {
1039
+ return Promise.resolve({
1040
+ result: TopicValidatorResult.Reject,
1041
+ severity: PeerErrorSeverity.LowToleranceError,
1042
+ });
1043
+ }
1044
+ return this.validateAndStoreCheckpointAttestation(source, attestation);
1045
+ },
994
1046
  msgId,
995
1047
  source,
996
1048
  TopicType.checkpoint_attestation,
@@ -1023,8 +1075,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1023
1075
 
1024
1076
  if (validationResult.result === 'reject') {
1025
1077
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1026
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1027
- return { result: TopicValidatorResult.Reject };
1078
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1028
1079
  }
1029
1080
 
1030
1081
  if (validationResult.result === 'ignore') {
@@ -1050,16 +1101,16 @@ export class LibP2PService extends WithTracer implements P2PService {
1050
1101
  return { result: TopicValidatorResult.Ignore, obj: attestation };
1051
1102
  }
1052
1103
 
1053
- // Could not add (cap reached for signer), no need to re-broadcast
1104
+ // Could not add (cap reached for signer), penalize and do not re-broadcast
1054
1105
  if (!added) {
1055
- this.logger.warn(`Dropping checkpoint attestation due to cap`, {
1106
+ this.logger.warn(`Rejecting checkpoint attestation due to cap`, {
1056
1107
  slot: slot.toString(),
1057
1108
  archive: attestation.archive.toString(),
1058
1109
  source: peerId.toString(),
1059
1110
  attester: attestation.getSender()?.toString(),
1060
1111
  count,
1061
1112
  });
1062
- return { result: TopicValidatorResult.Ignore, obj: attestation };
1113
+ return { result: TopicValidatorResult.Reject, severity: PeerErrorSeverity.HighToleranceError };
1063
1114
  }
1064
1115
 
1065
1116
  // Check if this is a duplicate attestation (signer attested to a different proposal at the same slot)
@@ -1114,8 +1165,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1114
1165
 
1115
1166
  if (validationResult.result === 'reject') {
1116
1167
  this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
1117
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1118
- return { result: TopicValidatorResult.Reject };
1168
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1119
1169
  }
1120
1170
 
1121
1171
  if (validationResult.result === 'ignore') {
@@ -1139,7 +1189,6 @@ export class LibP2PService extends WithTracer implements P2PService {
1139
1189
 
1140
1190
  // Too many blocks received for this slot and index, penalize peer and do not re-broadcast
1141
1191
  if (!added) {
1142
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1143
1192
  this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
1144
1193
  ...block.toBlockInfo(),
1145
1194
  indexWithinCheckpoint: block.indexWithinCheckpoint,
@@ -1147,7 +1196,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1147
1196
  proposer: block.getSender()?.toString(),
1148
1197
  source: peerId.toString(),
1149
1198
  });
1150
- return { result: TopicValidatorResult.Reject, metadata: { isEquivocated } };
1199
+ return {
1200
+ result: TopicValidatorResult.Reject,
1201
+ metadata: { isEquivocated },
1202
+ severity: PeerErrorSeverity.HighToleranceError,
1203
+ };
1151
1204
  }
1152
1205
 
1153
1206
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1192,7 +1245,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1192
1245
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1193
1246
  const isValid = await this.blockReceivedCallback(block, sender);
1194
1247
  if (!isValid) {
1195
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1248
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1196
1249
  }
1197
1250
  }
1198
1251
 
@@ -1240,8 +1293,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1240
1293
 
1241
1294
  if (validationResult.result === 'reject') {
1242
1295
  this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
1243
- this.peerManager.penalizePeer(peerId, validationResult.severity);
1244
- return { result: TopicValidatorResult.Reject };
1296
+ return { result: TopicValidatorResult.Reject, severity: validationResult.severity };
1245
1297
  }
1246
1298
 
1247
1299
  if (validationResult.result === 'ignore') {
@@ -1256,20 +1308,21 @@ export class LibP2PService extends WithTracer implements P2PService {
1256
1308
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1257
1309
  [Attributes.P2P_ID]: peerId.toString(),
1258
1310
  });
1259
- const {
1260
- result,
1261
- obj,
1262
- metadata: { isEquivocated } = {},
1263
- } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1264
- if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1311
+ const blockProposalResult = await this.validateAndStoreBlockProposal(peerId, blockProposal);
1312
+ const { obj, metadata: { isEquivocated } = {} } = blockProposalResult;
1313
+ if (blockProposalResult.result === TopicValidatorResult.Reject || !obj || isEquivocated) {
1265
1314
  this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
1266
1315
  [Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
1267
1316
  [Attributes.P2P_ID]: peerId.toString(),
1268
1317
  isEquivocated,
1269
- result,
1318
+ result: blockProposalResult.result,
1270
1319
  });
1271
- return { result: TopicValidatorResult.Reject };
1272
- } else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1320
+ return {
1321
+ result: TopicValidatorResult.Reject,
1322
+ severity:
1323
+ 'severity' in blockProposalResult ? blockProposalResult.severity : PeerErrorSeverity.MidToleranceError,
1324
+ };
1325
+ } else if (blockProposalResult.result === TopicValidatorResult.Accept && obj && !isEquivocated) {
1273
1326
  processBlock = true;
1274
1327
  }
1275
1328
  }
@@ -1296,13 +1349,17 @@ export class LibP2PService extends WithTracer implements P2PService {
1296
1349
  // Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
1297
1350
  // Note: We still return the checkpoint obj so the lastBlock can be processed if valid
1298
1351
  if (!added) {
1299
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
1300
1352
  this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
1301
1353
  ...checkpoint.toCheckpointInfo(),
1302
1354
  count,
1303
1355
  source: peerId.toString(),
1304
1356
  });
1305
- return { result: TopicValidatorResult.Reject, obj: checkpoint, metadata: { isEquivocated, processBlock } };
1357
+ return {
1358
+ result: TopicValidatorResult.Reject,
1359
+ obj: checkpoint,
1360
+ metadata: { isEquivocated, processBlock },
1361
+ severity: PeerErrorSeverity.HighToleranceError,
1362
+ };
1306
1363
  }
1307
1364
 
1308
1365
  // If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
@@ -1626,6 +1683,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1626
1683
  ...(this.config.txPublicSetupAllowListExtend ?? []),
1627
1684
  ];
1628
1685
  const blockNumber = BlockNumber(currentBlockNumber + 1);
1686
+ const l1Constants = await this.archiver.getL1Constants();
1629
1687
 
1630
1688
  return createFirstStageTxValidationsForGossipedTransactions(
1631
1689
  nextSlotTimestamp,
@@ -1639,6 +1697,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1639
1697
  !this.config.disableTransactions,
1640
1698
  allowedInSetup,
1641
1699
  this.logger.getBindings(),
1700
+ {
1701
+ rollupManaLimit: l1Constants.rollupManaLimit,
1702
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1703
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1704
+ },
1642
1705
  );
1643
1706
  }
1644
1707
 
@@ -1664,8 +1727,10 @@ export class LibP2PService extends WithTracer implements P2PService {
1664
1727
 
1665
1728
  // A promise that resolves when all validations have been run
1666
1729
  const allValidations = await Promise.all(validationPromises);
1667
- const failed = allValidations.find(x => !x.isValid);
1668
- if (failed) {
1730
+ const failures = allValidations.filter(x => !x.isValid);
1731
+ if (failures.length > 0) {
1732
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1733
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1669
1734
  return {
1670
1735
  allPassed: false,
1671
1736
  failure: {
@@ -1718,31 +1783,6 @@ export class LibP2PService extends WithTracer implements P2PService {
1718
1783
  return PeerErrorSeverity.HighToleranceError;
1719
1784
  }
1720
1785
 
1721
- /**
1722
- * Validate a checkpoint attestation.
1723
- *
1724
- * @param attestation - The checkpoint attestation to validate.
1725
- * @returns True if the checkpoint attestation is valid, false otherwise.
1726
- */
1727
- @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1728
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1729
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1730
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1731
- }))
1732
- public async validateCheckpointAttestation(
1733
- peerId: PeerId,
1734
- attestation: CheckpointAttestation,
1735
- ): Promise<P2PValidationResult> {
1736
- const result = await this.checkpointAttestationValidator.validate(attestation);
1737
-
1738
- if (result.result === 'reject') {
1739
- this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1740
- this.peerManager.penalizePeer(peerId, result.severity);
1741
- }
1742
-
1743
- return result;
1744
- }
1745
-
1746
1786
  public getPeerScore(peerId: PeerId): number {
1747
1787
  return this.node.services.pubsub.score.score(peerId.toString());
1748
1788
  }
@@ -32,7 +32,7 @@ import { PeerScoreState, type PeerScoring } from './peer_scoring.js';
32
32
  const MAX_DIAL_ATTEMPTS = 3;
33
33
  const MAX_CACHED_PEERS = 100;
34
34
  const MAX_CACHED_PEER_AGE_MS = 5 * 60 * 1000; // 5 minutes
35
- const FAILED_PEER_BAN_TIME_MS = 5 * 60 * 1000; // 5 minutes timeout after failing MAX_DIAL_ATTEMPTS
35
+ const DEFAULT_FAILED_PEER_BAN_TIME_MS = 5 * 60 * 1000; // 5 minutes timeout after failing MAX_DIAL_ATTEMPTS
36
36
  const GOODBYE_DIAL_TIMEOUT_MS = 1000;
37
37
  const FAILED_AUTH_HANDSHAKE_EXPIRY_MS = 60 * 60 * 1000; // 1 hour
38
38
 
@@ -776,7 +776,8 @@ export class PeerManager implements PeerManagerInterface {
776
776
  // Add to timed out peers
777
777
  this.timedOutPeers.set(id, {
778
778
  peerId: id,
779
- timeoutUntilMs: this.dateProvider.now() + FAILED_PEER_BAN_TIME_MS,
779
+ timeoutUntilMs:
780
+ this.dateProvider.now() + (this.config.peerFailedBanTimeMs ?? DEFAULT_FAILED_PEER_BAN_TIME_MS),
780
781
  });
781
782
  }
782
783
  }
@@ -938,6 +939,8 @@ export class PeerManager implements PeerManagerInterface {
938
939
  `Received auth for validator ${sender.toString()} from peer ${peerIdString}, but this validator is already authenticated to peer ${peerForAddress.toString()}`,
939
940
  { ...logData, address: sender.toString() },
940
941
  );
942
+ this.markAuthHandshakeFailed(peerId);
943
+ this.markPeerForDisconnect(peerId);
941
944
  return;
942
945
  }
943
946
 
@@ -0,0 +1,229 @@
1
+ # ReqResp Protocols
2
+
3
+ This module implements libp2p request-response protocols for the Aztec P2P network. All protocols share common transport-level validation (rate limiting, timeouts, Snappy decompression, error penalties) with protocol-specific logic layered on top.
4
+
5
+ ## Common Transport Validation
6
+
7
+ ### Rate Limiting (Responder Side)
8
+
9
+ Applied before the protocol handler runs.
10
+
11
+ | Protocol | Peer Limit | Global Limit | File |
12
+ |----------|-----------|-------------|------|
13
+ | PING | 5/s | 10/s | `rate-limiter/rate_limits.ts` |
14
+ | STATUS | 5/s | 10/s | same |
15
+ | AUTH | 5/s | 10/s | same |
16
+ | GOODBYE | 5/s | 10/s | same |
17
+ | BLOCK | 2/s | 5/s | same |
18
+ | BLOCK_TXS | 10/s | 200/s | same |
19
+ | TX | (see rate limits file) | (see rate limits file) | same |
20
+
21
+ - Per-peer limit exceeded: `HighToleranceError` penalty + `RATE_LIMIT_EXCEEDED` status. Penalty fires inside `RequestResponseRateLimiter.allow()`, not the stream handler.
22
+ - Global limit exceeded: `RATE_LIMIT_EXCEEDED` status only (no peer penalty).
23
+
24
+ ### Response Status Byte (Requester Side)
25
+
26
+ | Rule | Consequence | File |
27
+ |------|-------------|------|
28
+ | First chunk must be exactly 1 byte | `ReqRespStatusError(UNKNOWN)` | `status.ts` |
29
+ | Byte must be valid `ReqRespStatus` enum (0-4, 126, 127) | `ReqRespStatusError(UNKNOWN)` | same |
30
+
31
+ Note: `prettyPrintReqRespStatus` is missing a `NOT_FOUND` case (minor logging bug).
32
+
33
+ ### Snappy Decompression (Requester Side)
34
+
35
+ Per-protocol size limits checked via preamble before decompression.
36
+
37
+ ### Timeouts (Requester Side)
38
+
39
+ | Timeout | Default | Penalty |
40
+ |---------|---------|---------|
41
+ | Individual request | 10s | HighToleranceError |
42
+ | Dial | 5s | HighToleranceError |
43
+
44
+ ### Error Penalty Categorization (Requester Side)
45
+
46
+ | Error Type | Severity |
47
+ |------------|----------|
48
+ | GOODBYE subprotocol errors | None |
49
+ | `CollectiveReqRespTimeoutError` / `InvalidResponseError` | None |
50
+ | `AbortError` / connection close / muxer closed | None |
51
+ | `ECONNRESET` / `EPIPE` / `ECONNREFUSED` / `ERR_UNEXPECTED_EOF` | HighToleranceError |
52
+ | `ERR_UNSUPPORTED_PROTOCOL` | HighToleranceError |
53
+ | `IndividualReqRespTimeoutError` / `TimeoutError` | HighToleranceError |
54
+ | Catch-all | HighToleranceError |
55
+
56
+ ### Request Error Penalty (Responder Side)
57
+
58
+ | Error Type | Severity |
59
+ |------------|----------|
60
+ | `BADLY_FORMED_REQUEST` | LowToleranceError |
61
+ | All others | None |
62
+
63
+ ### Notes
64
+
65
+ - Request payloads are NOT snappy-compressed (asymmetric: only responses use snappy).
66
+
67
+ ---
68
+
69
+ ## Handshake Protocols
70
+
71
+ ### Connection-Level Gating (Before Any Handshake)
72
+
73
+ | Rule | Consequence | File |
74
+ |------|-------------|------|
75
+ | Deny inbound connection from IP/peerId with too many failed auth handshakes | Connection denied | `libp2p_service.ts` |
76
+ | Threshold: `p2pMaxFailedAuthAttemptsAllowed` (default 3) | Tracked per peerId AND per IP | `peer_manager.ts` |
77
+ | Failed auth entries expire after 1 hour | Peer can reconnect; no escalating penalty for repeat offenders | same |
78
+
79
+ ### Handshake Trigger Logic (`peer:connect`)
80
+
81
+ 1. `p2pDisableStatusHandshake` = true: no handshake
82
+ 2. `p2pAllowOnlyValidators` = false: STATUS handshake
83
+ 3. Peer is protected (trusted/private/preferred): STATUS handshake
84
+ 4. Otherwise: AUTH handshake (superset of STATUS)
85
+
86
+ Config constraint: `p2pDisableStatusHandshake && p2pAllowOnlyValidators` is disallowed.
87
+
88
+ ### STATUS Protocol (`/aztec/req/status/1.0.0`)
89
+
90
+ **Requester side** (`peer_manager.ts`):
91
+
92
+ | Rule | Consequence |
93
+ |------|-------------|
94
+ | Response status must be SUCCESS | Peer scheduled for disconnect |
95
+ | `compressedComponentsVersion` must match | Peer scheduled for disconnect |
96
+ | Any exception | Peer scheduled for disconnect |
97
+
98
+ `StatusMessage.validate()` currently only checks `compressedComponentsVersion`. Fields `latestBlockNumber`, `latestBlockHash`, `finalizedBlockNumber` are NOT validated (TODO in code).
99
+
100
+ **Responder side**: no validation of incoming request content (always responds with own status). This means the requester leaks its blockchain state to any peer before validation.
101
+
102
+ **Deserialization bounds**: `MAX_VERSION_STRING_LENGTH` = 64 bytes, `MAX_BLOCK_HASH_STRING_LENGTH` = 128 bytes. Expected response size: 1 KB.
103
+
104
+ ### AUTH Protocol (`/aztec/req/auth/1.0.0`)
105
+
106
+ **Requester side** (`peer_manager.ts`):
107
+
108
+ | # | Rule | Consequence |
109
+ |---|------|-------------|
110
+ | 1 | Response status is SUCCESS | `markAuthHandshakeFailed` + disconnect |
111
+ | 2 | `compressedComponentsVersion` match | `markAuthHandshakeFailed` + disconnect |
112
+ | 3 | Valid ECDSA signature recovery from challenge response | `markAuthHandshakeFailed` + disconnect |
113
+ | 4 | Recovered address is a registered validator | `markAuthHandshakeFailed` + disconnect |
114
+ | 5 | Validator address not already authenticated to different peerId | Silent return (no disconnect, no failure marking -- peer stays connected but unauthenticated) |
115
+ | 6 | Any exception | `markAuthHandshakeFailed` + disconnect |
116
+
117
+ Challenge: random `Fr`, payload = `keccak256("Aztec Validator Challenge:" + challenge)`, signed with `eth_sign` style. Challenge is NOT bound to peer identity (transport encryption via Noise is the binding layer).
118
+
119
+ On success: peer added to authenticated maps, prior failures cleared (including IP-based ones -- shared-IP peers benefit from a legitimate validator's success).
120
+
121
+ **Responder side** (`validator-client/src/validator.ts` + `peer_manager.ts`):
122
+
123
+ | # | Rule | Consequence |
124
+ |---|------|-------------|
125
+ | 1 | Peer must be protected (`shouldTrustWithIdentity` in `peer_manager.ts`) | Returns empty buffer (SUCCESS status + empty payload -> requester gets parse error -> `markAuthHandshakeFailed`) |
126
+ | 2 | Node must have registered validator address | Returns empty buffer (same consequence) |
127
+
128
+ **Unauthenticated peer gossip**: when `p2pAllowOnlyValidators` is true, unauthenticated peers get `appSpecificScore = -Infinity`, completely excluding them from all gossip.
129
+
130
+ ### PING Protocol (`/aztec/req/ping/1.0.0`)
131
+
132
+ No validation on either side. Responder returns `Buffer.from('pong')`. Expected response: 1 KB.
133
+
134
+ ### GOODBYE Protocol (`/aztec/req/goodbye/1.0.0`)
135
+
136
+ **Responder**: buffer must be 1 byte (defaults to `UNKNOWN` on invalid length). Goodbye reason byte is NOT validated against the enum -- any byte 0-255 accepted. Peer scheduled for disconnect regardless of reason.
137
+
138
+ **Requester**: response errors are never penalized (GOODBYE subprotocol exempt from error categorization).
139
+
140
+ ### Periodic Re-validation
141
+
142
+ | Rule | Interval | File |
143
+ |------|----------|------|
144
+ | Authenticated validators re-checked against current validator set | Every heartbeat (`peerCheckIntervalMS`) | `peer_manager.ts` |
145
+ | If validator address no longer registered, auth entry removed | Same | same |
146
+
147
+ Protected peers (private/trusted/preferred) are always considered "authenticated" without AUTH handshake.
148
+
149
+ ---
150
+
151
+ ## Block Data Protocols
152
+
153
+ ### BLOCK Protocol (`/aztec/req/block/1.0.0`)
154
+
155
+ **Server side**:
156
+
157
+ | Rule | Consequence | File |
158
+ |------|-------------|------|
159
+ | Request must parse as `Fr` | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/block.ts` |
160
+ | Block lookup throws | `INTERNAL_ERROR` status | same |
161
+ | Block not found | SUCCESS + empty buffer (design choice; no `NOT_FOUND` status used) | same |
162
+
163
+ **Requester side** (Snappy limit: 3 MB):
164
+
165
+ | Rule | Consequence | File |
166
+ |------|-------------|------|
167
+ | Response block number must match requested | LowToleranceError; rejected | `libp2p_service.ts` (`validateRequestedBlock`) |
168
+ | Local block must exist for hash verification | Rejected (no penalty) | same |
169
+ | Response block hash must equal local block hash | MidToleranceError; rejected | same |
170
+
171
+ **Limitation**: the local-block requirement means BLOCK req/resp is unusable for initial P2P-only sync (before L1 sync provides local copies for verification). A TODO in the code acknowledges this.
172
+
173
+ ### BLOCK_TXS Protocol (`/aztec/req/block_txs/1.0.0`)
174
+
175
+ **Server side**:
176
+
177
+ | Rule | Consequence | File |
178
+ |------|-------------|------|
179
+ | Request must parse as `BlockTxsRequest` (Fr + TxHashArray + BitVector) | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/block_txs/block_txs_handler.ts` |
180
+ | BitVector length: non-negative and <= `MAX_TXS_PER_BLOCK` (65536) | Deserialization throws -> `BADLY_FORMED_REQUEST` | `protocols/block_txs/bitvector.ts` |
181
+ | Archive root not found and no explicit txHashes | `NOT_FOUND` status | handler |
182
+ | Internal error during lookup | Unhandled exception -> stream abort (no `INTERNAL_ERROR` status, unlike BLOCK) | handler |
183
+
184
+ Conditional registration: BLOCK_TXS handler only registered when `config.disableTransactions` is false. Otherwise peers get `ERR_UNSUPPORTED_PROTOCOL`.
185
+
186
+ **Requester side via `sendBatchRequest`** (Snappy limit: `max(N, 1) * 512 + 1` KB):
187
+
188
+ | Rule | Consequence | File |
189
+ |------|-------------|------|
190
+ | Archive root must match request | MidToleranceError | `libp2p_service.ts` (`validateRequestedBlockTxs`) |
191
+ | BitVector length must match request | MidToleranceError | same |
192
+ | No duplicate tx hashes | MidToleranceError | same |
193
+ | Tx count within bounds | MidToleranceError | same |
194
+ | Local block proposal must exist for archive root | Rejected (no penalty) | same |
195
+ | All tx hashes must be in proposal's tx list at allowed indices | LowToleranceError | same |
196
+ | Txs in strictly increasing index order | LowToleranceError | same |
197
+ | Each tx passes well-formedness (Metadata [4 fields], Size, Data, Proof) | LowToleranceError | same |
198
+
199
+ **Requester side via `BatchTxRequester`** (separate validation path):
200
+
201
+ | Rule | Consequence | File |
202
+ |------|-------------|------|
203
+ | Non-SUCCESS status: `FAILURE`/`UNKNOWN` | HighToleranceError + "bad peer" tracking | `batch-tx-requester/batch_tx_requester.ts` |
204
+ | `RATE_LIMIT_EXCEEDED` | Peer marked rate-limited (cooldown) | same |
205
+ | `NOT_FOUND` / `BADLY_FORMED_REQUEST` / `INTERNAL_ERROR` | Falls through silently (no penalty) | same |
206
+ | Each tx validated (Metadata + Size + Data + Proof) | LowToleranceError per invalid tx; valid txs from same response still accepted | same |
207
+ | Archive root match + non-empty txIndices | No penalty on mismatch; peer not promoted to "smart" | same |
208
+
209
+ **Double penalty on transport errors**: when `BatchTxRequester` encounters a transport error (e.g., ECONNRESET), both `sendRequestToPeer`'s internal handler and the `BatchTxRequester`'s catch block penalize the peer, resulting in double HighToleranceError.
210
+
211
+ See [BatchTxRequester README](batch-tx-requester/README.md) for the full architecture (peer classification, worker model, wire protocol).
212
+
213
+ ### TX Protocol (`/aztec/req/tx/1.0.0`)
214
+
215
+ **Server side**:
216
+
217
+ | Rule | Consequence | File |
218
+ |------|-------------|------|
219
+ | Request must parse as `TxHashArray` | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/tx.ts` |
220
+
221
+ **Requester side** (validator registered at startup, not the default noop):
222
+
223
+ | Rule | Consequence | File |
224
+ |------|-------------|------|
225
+ | Each returned tx hash must be in the requested set | MidToleranceError | `libp2p_service.ts` (`validateRequestedTxs`) |
226
+ | Each tx passes well-formedness (Metadata + Size + Data + Proof) | LowToleranceError | same |
227
+
228
+ Snappy limit: `max(N, 1) * 512 + 1` KB.
229
+