@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.
- package/README.md +129 -3
- package/dest/client/factory.d.ts +2 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +21 -8
- package/dest/client/p2p_client.d.ts +1 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +22 -34
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +3 -3
- package/dest/config.d.ts +24 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +66 -7
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +3 -3
- package/dest/mem_pools/attestation_pool/attestation_pool.js +3 -3
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
- package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +4 -4
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +9 -5
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +25 -10
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +33 -10
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -43
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +4 -2
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +21 -6
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
- package/dest/msg_validators/clock_tolerance.d.ts +1 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +4 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +51 -49
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
- package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +35 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +23 -4
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +36 -10
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
- package/dest/msg_validators/tx_validator/index.d.ts +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +21 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +49 -2
- package/dest/services/encoding.d.ts +5 -1
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +7 -1
- package/dest/services/libp2p/libp2p_service.d.ts +4 -9
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +125 -68
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +4 -2
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +69 -65
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +3 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +3 -0
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +17 -9
- package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +57 -73
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/slow_tx_collection.js +1 -1
- package/dest/services/tx_collection/tx_collection.d.ts +3 -6
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.d.ts +1 -1
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +22 -3
- package/dest/testbench/p2p_client_testbench_worker.js +5 -4
- package/dest/testbench/worker_client_manager.d.ts +3 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +6 -2
- package/dest/util.d.ts +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +36 -12
- package/src/client/p2p_client.ts +22 -34
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +4 -6
- package/src/config.ts +92 -4
- package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -3
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
- package/src/mem_pools/tx_pool/priority.ts +4 -4
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
- package/src/mem_pools/tx_pool_v2/README.md +9 -1
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +2 -1
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
- package/src/mem_pools/tx_pool_v2/interfaces.ts +9 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +52 -12
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +13 -1
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +23 -6
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
- package/src/msg_validators/clock_tolerance.ts +4 -3
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
- package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -53
- package/src/msg_validators/tx_validator/README.md +5 -1
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +42 -1
- package/src/msg_validators/tx_validator/factory.ts +43 -3
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/phases_validator.ts +60 -1
- package/src/services/encoding.ts +9 -1
- package/src/services/libp2p/libp2p_service.ts +118 -78
- package/src/services/peer-manager/peer_manager.ts +5 -2
- package/src/services/reqresp/README.md +229 -0
- package/src/services/reqresp/batch-tx-requester/README.md +46 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +64 -69
- package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +5 -0
- package/src/services/reqresp/reqresp.ts +19 -11
- package/src/services/tx_collection/fast_tx_collection.ts +57 -83
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/slow_tx_collection.ts +1 -1
- package/src/services/tx_collection/tx_collection.ts +3 -5
- package/src/test-helpers/make-test-p2p-clients.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +1 -1
- package/src/test-helpers/testbench-utils.ts +29 -3
- package/src/testbench/p2p_client_testbench_worker.ts +5 -6
- package/src/testbench/worker_client_manager.ts +13 -5
- package/src/util.ts +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
- package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
- package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
- 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
|
-
|
|
226
|
+
const proposalValidatorOpts = {
|
|
226
227
|
txsPermitted: !config.disableTransactions,
|
|
227
|
-
maxTxsPerBlock: config.
|
|
228
|
-
}
|
|
229
|
-
this.
|
|
230
|
-
|
|
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.
|
|
241
|
-
`Handler not yet registered
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
927
|
-
|
|
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.
|
|
942
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
() =>
|
|
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
|
-
|
|
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),
|
|
1104
|
+
// Could not add (cap reached for signer), penalize and do not re-broadcast
|
|
1054
1105
|
if (!added) {
|
|
1055
|
-
this.logger.warn(`
|
|
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.
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
1261
|
-
|
|
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 {
|
|
1272
|
-
|
|
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 {
|
|
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
|
|
1668
|
-
if (
|
|
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
|
|
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:
|
|
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
|
+
|