@aztec/p2p 0.0.1-commit.cb6bed7c2 → 0.0.1-commit.cbf2c2d5d

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 (147) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +1 -1
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +19 -7
  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 -10
  8. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +3 -3
  9. package/dest/config.d.ts +13 -1
  10. package/dest/config.d.ts.map +1 -1
  11. package/dest/config.js +20 -0
  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/interfaces.d.ts +7 -5
  28. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +9 -2
  30. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +7 -1
  32. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +4 -2
  33. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  35. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
  36. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +19 -5
  38. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  39. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  40. package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
  41. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  42. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  43. package/dest/msg_validators/clock_tolerance.js +4 -3
  44. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +1 -1
  45. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  46. package/dest/msg_validators/proposal_validator/proposal_validator.js +5 -5
  47. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  48. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  49. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  50. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  51. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  52. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  53. package/dest/msg_validators/tx_validator/factory.d.ts +23 -4
  54. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  55. package/dest/msg_validators/tx_validator/factory.js +36 -10
  56. package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
  57. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  58. package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
  59. package/dest/msg_validators/tx_validator/phases_validator.d.ts +21 -1
  60. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/tx_validator/phases_validator.js +28 -1
  62. package/dest/services/encoding.d.ts +5 -1
  63. package/dest/services/encoding.d.ts.map +1 -1
  64. package/dest/services/encoding.js +7 -1
  65. package/dest/services/libp2p/libp2p_service.d.ts +4 -9
  66. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  67. package/dest/services/libp2p/libp2p_service.js +115 -59
  68. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  69. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  70. package/dest/services/peer-manager/peer_manager.js +4 -2
  71. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
  72. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  73. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +69 -65
  74. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
  75. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  76. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  77. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  78. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  79. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +3 -1
  80. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  81. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +3 -0
  82. package/dest/services/reqresp/reqresp.d.ts +1 -1
  83. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  84. package/dest/services/reqresp/reqresp.js +17 -9
  85. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
  86. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  87. package/dest/services/tx_collection/fast_tx_collection.js +57 -73
  88. package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
  89. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  90. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  91. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  92. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  93. package/dest/services/tx_collection/request_tracker.js +84 -0
  94. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  95. package/dest/services/tx_collection/tx_collection.d.ts +3 -6
  96. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  97. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  98. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  99. package/dest/test-helpers/testbench-utils.js +22 -3
  100. package/dest/testbench/p2p_client_testbench_worker.js +3 -3
  101. package/package.json +14 -14
  102. package/src/client/factory.ts +34 -11
  103. package/src/client/p2p_client.ts +22 -12
  104. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +3 -5
  105. package/src/config.ts +33 -0
  106. package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -3
  107. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  108. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  109. package/src/mem_pools/tx_pool/priority.ts +4 -4
  110. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  111. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  112. package/src/mem_pools/tx_pool_v2/interfaces.ts +6 -4
  113. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +11 -1
  114. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +13 -1
  115. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +20 -5
  116. package/src/msg_validators/attestation_validator/README.md +49 -0
  117. package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
  118. package/src/msg_validators/clock_tolerance.ts +4 -3
  119. package/src/msg_validators/proposal_validator/README.md +123 -0
  120. package/src/msg_validators/proposal_validator/proposal_validator.ts +6 -5
  121. package/src/msg_validators/tx_validator/README.md +5 -1
  122. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  123. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  124. package/src/msg_validators/tx_validator/factory.ts +43 -3
  125. package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
  126. package/src/msg_validators/tx_validator/phases_validator.ts +31 -1
  127. package/src/services/encoding.ts +9 -1
  128. package/src/services/libp2p/libp2p_service.ts +108 -70
  129. package/src/services/peer-manager/peer_manager.ts +5 -2
  130. package/src/services/reqresp/README.md +229 -0
  131. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  132. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +64 -69
  133. package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
  134. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  135. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +5 -0
  136. package/src/services/reqresp/reqresp.ts +19 -11
  137. package/src/services/tx_collection/fast_tx_collection.ts +57 -83
  138. package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
  139. package/src/services/tx_collection/request_tracker.ts +127 -0
  140. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  141. package/src/services/tx_collection/tx_collection.ts +3 -5
  142. package/src/test-helpers/testbench-utils.ts +29 -3
  143. package/src/testbench/p2p_client_testbench_worker.ts +3 -5
  144. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  145. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  146. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  147. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
@@ -1,4 +1,5 @@
1
1
  import {
2
+ MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT,
2
3
  MAX_PROCESSABLE_L2_GAS,
3
4
  PRIVATE_TX_L2_GAS_OVERHEAD,
4
5
  PUBLIC_TX_L2_GAS_OVERHEAD,
@@ -49,16 +50,31 @@ export interface HasGasLimitData {
49
50
  */
50
51
  export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidator<T> {
51
52
  #log: Logger;
52
-
53
- constructor(bindings?: LoggerBindings) {
54
- this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
53
+ #effectiveMaxL2Gas: number;
54
+ #effectiveMaxDAGas: number;
55
+ #rollupManaLimit: number;
56
+ #maxBlockL2Gas: number;
57
+ #maxBlockDAGas: number;
58
+
59
+ constructor(opts?: {
60
+ rollupManaLimit?: number;
61
+ maxBlockL2Gas?: number;
62
+ maxBlockDAGas?: number;
63
+ bindings?: LoggerBindings;
64
+ }) {
65
+ this.#log = createLogger('sequencer:tx_validator:tx_gas', opts?.bindings);
66
+ this.#rollupManaLimit = opts?.rollupManaLimit ?? Infinity;
67
+ this.#maxBlockL2Gas = opts?.maxBlockL2Gas ?? Infinity;
68
+ this.#maxBlockDAGas = opts?.maxBlockDAGas ?? Infinity;
69
+ this.#effectiveMaxL2Gas = Math.min(MAX_PROCESSABLE_L2_GAS, this.#rollupManaLimit, this.#maxBlockL2Gas);
70
+ this.#effectiveMaxDAGas = Math.min(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, this.#maxBlockDAGas);
55
71
  }
56
72
 
57
73
  validateTx(tx: T): Promise<TxValidationResult> {
58
74
  return Promise.resolve(this.validateGasLimit(tx));
59
75
  }
60
76
 
61
- /** Checks gas limits are >= fixed minimums and <= AVM max processable L2 gas. */
77
+ /** Checks gas limits are >= fixed minimums and <= effective max gas (L2 and DA). */
62
78
  validateGasLimit(tx: T): TxValidationResult {
63
79
  const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
64
80
  const minGasLimits = new Gas(
@@ -74,10 +90,21 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
74
90
  return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
75
91
  }
76
92
 
77
- if (gasLimits.l2Gas > MAX_PROCESSABLE_L2_GAS) {
78
- this.#log.verbose(`Rejecting transaction due to the gas limit(s) being higher than the maximum processable gas`, {
93
+ if (gasLimits.l2Gas > this.#effectiveMaxL2Gas) {
94
+ this.#log.verbose(`Rejecting transaction due to the L2 gas limit being higher than the effective maximum`, {
79
95
  gasLimits,
80
- minGasLimits,
96
+ effectiveMaxL2Gas: this.#effectiveMaxL2Gas,
97
+ rollupManaLimit: this.#rollupManaLimit,
98
+ maxBlockL2Gas: this.#maxBlockL2Gas,
99
+ });
100
+ return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
101
+ }
102
+
103
+ if (gasLimits.daGas > this.#effectiveMaxDAGas) {
104
+ this.#log.verbose(`Rejecting transaction due to the DA gas limit being higher than the effective maximum`, {
105
+ gasLimits,
106
+ effectiveMaxDAGas: this.#effectiveMaxDAGas,
107
+ maxBlockDAGas: this.#maxBlockDAGas,
81
108
  });
82
109
  return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
83
110
  }
@@ -106,21 +133,27 @@ export class GasTxValidator implements TxValidator<Tx> {
106
133
  #publicDataSource: PublicStateSource;
107
134
  #feeJuiceAddress: AztecAddress;
108
135
  #gasFees: GasFees;
136
+ #gasLimitOpts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number };
109
137
 
110
138
  constructor(
111
139
  publicDataSource: PublicStateSource,
112
140
  feeJuiceAddress: AztecAddress,
113
141
  gasFees: GasFees,
114
142
  private bindings?: LoggerBindings,
143
+ opts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
115
144
  ) {
116
145
  this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
117
146
  this.#publicDataSource = publicDataSource;
118
147
  this.#feeJuiceAddress = feeJuiceAddress;
119
148
  this.#gasFees = gasFees;
149
+ this.#gasLimitOpts = opts;
120
150
  }
121
151
 
122
152
  async validateTx(tx: Tx): Promise<TxValidationResult> {
123
- const gasLimitValidation = new GasLimitsValidator(this.bindings).validateGasLimit(tx);
153
+ const gasLimitValidation = new GasLimitsValidator({
154
+ ...this.#gasLimitOpts,
155
+ bindings: this.bindings,
156
+ }).validateGasLimit(tx);
124
157
  if (gasLimitValidation.result === 'invalid') {
125
158
  return Promise.resolve(gasLimitValidation);
126
159
  }
@@ -40,7 +40,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
40
40
  // which are needed for public FPC flows, but fail if the account contract hasnt been deployed yet,
41
41
  // which is what we're trying to do as part of the current txs.
42
42
  // We only need to create/revert checkpoint here because of this addNewContracts call.
43
- await this.contractsDB.addNewContracts(tx);
43
+ this.contractsDB.addNewContracts(tx);
44
44
 
45
45
  if (!tx.data.forPublic) {
46
46
  this.#log.debug(
@@ -141,3 +141,33 @@ export class PhasesTxValidator implements TxValidator<Tx> {
141
141
  return TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED;
142
142
  }
143
143
  }
144
+
145
+ /** Structural interface for the allowed-setup-calls flag check. */
146
+ export interface HasAllowedSetupCallsData {
147
+ txHash: { toString(): string };
148
+ allowedSetupCalls: boolean;
149
+ }
150
+
151
+ /**
152
+ * Validates that a transaction's setup-phase calls were allowed at receipt time.
153
+ *
154
+ * Checks the precomputed `allowedSetupCalls` flag on TxMetaData. The flag is
155
+ * computed by running the PhasesTxValidator on the full Tx when it first enters
156
+ * the pool. This lightweight validator is used during pending pool migration to
157
+ * reject txs whose setup calls are not on the allow list.
158
+ */
159
+ export class AllowedSetupCallsMetaValidator<T extends HasAllowedSetupCallsData> implements TxValidator<T> {
160
+ #log: Logger;
161
+
162
+ constructor(bindings?: LoggerBindings) {
163
+ this.#log = createLogger('sequencer:tx_validator:tx_phases_meta', bindings);
164
+ }
165
+
166
+ validateTx(tx: T): Promise<TxValidationResult> {
167
+ if (!tx.allowedSetupCalls) {
168
+ this.#log.verbose(`Rejecting tx ${tx.txHash} because its setup calls are not on the allow list`);
169
+ return Promise.resolve({ result: 'invalid', reason: [TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED] });
170
+ }
171
+ return Promise.resolve({ result: 'valid' });
172
+ }
173
+ }
@@ -9,6 +9,14 @@ import { webcrypto } from 'node:crypto';
9
9
  import { compressSync, uncompressSync } from 'snappy';
10
10
  import xxhashFactory from 'xxhash-wasm';
11
11
 
12
+ /** Thrown when a Snappy-compressed response exceeds the allowed decompressed size. */
13
+ export class OversizedSnappyResponseError extends Error {
14
+ constructor(decompressedSize: number, maxSizeKb: number) {
15
+ super(`Decompressed size ${decompressedSize} exceeds maximum allowed size of ${maxSizeKb}kb`);
16
+ this.name = 'OversizedSnappyResponseError';
17
+ }
18
+ }
19
+
12
20
  // Load WASM
13
21
  const xxhash = await xxhashFactory();
14
22
 
@@ -86,7 +94,7 @@ export class SnappyTransform implements DataTransform {
86
94
  const { decompressedSize } = readSnappyPreamble(data);
87
95
  if (decompressedSize > maxSizeKb * 1024) {
88
96
  this.logger.warn(`Decompressed size ${decompressedSize} exceeds maximum allowed size of ${maxSizeKb}kb`);
89
- throw new Error(`Decompressed size ${decompressedSize} exceeds maximum allowed size of ${maxSizeKb}kb`);
97
+ throw new OversizedSnappyResponseError(decompressedSize, maxSizeKb);
90
98
  }
91
99
 
92
100
  return Buffer.from(uncompressSync(data, { asBuffer: true }));
@@ -18,7 +18,6 @@ import {
18
18
  type CheckpointProposalCore,
19
19
  type Gossipable,
20
20
  P2PMessage,
21
- type ValidationResult as P2PValidationResult,
22
21
  PeerErrorSeverity,
23
22
  PeerErrorSeverityByHarshness,
24
23
  TopicType,
@@ -131,7 +130,7 @@ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: Vali
131
130
  // REFACTOR: Unify with the type above
132
131
  type ReceivedMessageValidationResult<T, M = undefined> =
133
132
  | { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject>; metadata?: M }
134
- | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M };
133
+ | { obj?: T; result: TopicValidatorResult.Reject; metadata?: M; severity: PeerErrorSeverity };
135
134
 
136
135
  /**
137
136
  * Lib P2P implementation of the P2PService interface.
@@ -226,7 +225,7 @@ export class LibP2PService extends WithTracer implements P2PService {
226
225
 
227
226
  const proposalValidatorOpts = {
228
227
  txsPermitted: !config.disableTransactions,
229
- maxTxsPerBlock: config.validateMaxTxsPerBlock,
228
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
230
229
  };
231
230
  this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
232
231
  this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
@@ -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
 
@@ -1720,31 +1783,6 @@ export class LibP2PService extends WithTracer implements P2PService {
1720
1783
  return PeerErrorSeverity.HighToleranceError;
1721
1784
  }
1722
1785
 
1723
- /**
1724
- * Validate a checkpoint attestation.
1725
- *
1726
- * @param attestation - The checkpoint attestation to validate.
1727
- * @returns True if the checkpoint attestation is valid, false otherwise.
1728
- */
1729
- @trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
1730
- [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
1731
- [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1732
- [Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
1733
- }))
1734
- public async validateCheckpointAttestation(
1735
- peerId: PeerId,
1736
- attestation: CheckpointAttestation,
1737
- ): Promise<P2PValidationResult> {
1738
- const result = await this.checkpointAttestationValidator.validate(attestation);
1739
-
1740
- if (result.result === 'reject') {
1741
- this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
1742
- this.peerManager.penalizePeer(peerId, result.severity);
1743
- }
1744
-
1745
- return result;
1746
- }
1747
-
1748
1786
  public getPeerScore(peerId: PeerId): number {
1749
1787
  return this.node.services.pubsub.score.score(peerId.toString());
1750
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