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