@aztec/p2p 0.0.1-commit.88e6f9396 → 0.0.1-commit.8c0b8ff
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 +2 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +5 -5
- 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 +4 -6
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +5 -6
- package/dest/config.d.ts +6 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -6
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -4
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +4 -8
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
- package/dest/mem_pools/instrumentation.d.ts +2 -4
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +14 -16
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +5 -7
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +0 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +6 -5
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- 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 +43 -26
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
- 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 +0 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -2
- 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 +1 -18
- 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 +4 -5
- 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 +3 -4
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +5 -5
- 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/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.js +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts +9 -2
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +25 -22
- package/dest/services/peer-manager/metrics.d.ts +1 -3
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +0 -6
- 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 +3 -6
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +8 -11
- 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 +101 -79
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -3
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +4 -5
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +7 -13
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +11 -19
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +15 -52
- 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/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +3 -4
- package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +73 -57
- 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/missing_txs_tracker.d.ts +32 -0
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
- 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/slow_tx_collection.js +1 -1
- package/dest/services/tx_collection/tx_collection.d.ts +6 -3
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- 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/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 +2 -20
- 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 +5 -6
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +1 -2
- package/dest/util.d.ts +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +8 -4
- package/src/client/p2p_client.ts +4 -6
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +8 -7
- package/src/config.ts +10 -10
- package/src/mem_pools/attestation_pool/attestation_pool.ts +7 -8
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
- package/src/mem_pools/instrumentation.ts +13 -17
- package/src/mem_pools/tx_pool_v2/interfaces.ts +4 -7
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +4 -4
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +43 -29
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +0 -3
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1 -19
- package/src/msg_validators/attestation_validator/README.md +1 -1
- package/src/msg_validators/attestation_validator/attestation_validator.ts +4 -5
- package/src/msg_validators/clock_tolerance.ts +3 -4
- package/src/msg_validators/proposal_validator/README.md +3 -3
- package/src/msg_validators/proposal_validator/proposal_validator.ts +5 -6
- 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/metadata_validator.ts +4 -12
- package/src/msg_validators/tx_validator/phases_validator.ts +1 -1
- package/src/services/libp2p/libp2p_service.ts +28 -18
- package/src/services/peer-manager/metrics.ts +0 -7
- package/src/services/peer-manager/peer_manager.ts +3 -7
- package/src/services/reqresp/batch-tx-requester/README.md +7 -46
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +111 -75
- package/src/services/reqresp/batch-tx-requester/interface.ts +1 -2
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +6 -13
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +24 -68
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
- package/src/services/reqresp/reqresp.ts +3 -5
- package/src/services/tx_collection/fast_tx_collection.ts +83 -57
- package/src/services/tx_collection/file_store_tx_source.ts +43 -31
- package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +13 -8
- package/src/services/tx_collection/slow_tx_collection.ts +1 -1
- package/src/services/tx_collection/tx_collection.ts +5 -3
- package/src/services/tx_collection/tx_source.ts +8 -7
- 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 +3 -28
- package/src/testbench/p2p_client_testbench_worker.ts +9 -7
- package/src/testbench/worker_client_manager.ts +1 -2
- package/src/util.ts +1 -1
- package/dest/services/tx_collection/request_tracker.d.ts +0 -53
- package/dest/services/tx_collection/request_tracker.d.ts.map +0 -1
- package/dest/services/tx_collection/request_tracker.js +0 -84
- package/src/services/tx_collection/request_tracker.ts +0 -127
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { insertIntoSortedArray, removeFromSortedArray } from '@aztec/foundation/array';
|
|
2
1
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
2
|
import type { L2BlockId } from '@aztec/stdlib/block';
|
|
4
3
|
|
|
5
|
-
import { type
|
|
4
|
+
import { type TxMetaData, type TxState, compareFee, compareTxHash, txHashFromBigInt } from './tx_metadata.js';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Manages in-memory indices for the transaction pool.
|
|
@@ -23,8 +22,8 @@ export class TxPoolIndices {
|
|
|
23
22
|
#nullifierToTxHash: Map<string, string> = new Map();
|
|
24
23
|
/** Fee payer to txHashes index (pending txs only) */
|
|
25
24
|
#feePayerToTxHashes: Map<string, Set<string>> = new Map();
|
|
26
|
-
/** Pending
|
|
27
|
-
#pendingByPriority:
|
|
25
|
+
/** Pending txHash bigints grouped by priority fee */
|
|
26
|
+
#pendingByPriority: Map<bigint, Set<bigint>> = new Map();
|
|
28
27
|
/** Protected transactions: txHash -> slotNumber */
|
|
29
28
|
#protectedTransactions: Map<string, SlotNumber> = new Map();
|
|
30
29
|
|
|
@@ -74,14 +73,20 @@ export class TxPoolIndices {
|
|
|
74
73
|
* @param order - 'desc' for highest priority first, 'asc' for lowest priority first
|
|
75
74
|
*/
|
|
76
75
|
*iteratePendingByPriority(order: 'asc' | 'desc', filter?: (hash: string) => boolean): Generator<string> {
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
const feeCompareFn = order === 'desc' ? (a: bigint, b: bigint) => compareFee(b, a) : compareFee;
|
|
77
|
+
const hashCompareFn =
|
|
78
|
+
order === 'desc' ? (a: bigint, b: bigint) => compareTxHash(b, a) : (a: bigint, b: bigint) => compareTxHash(a, b);
|
|
79
|
+
|
|
80
|
+
const sortedFees = [...this.#pendingByPriority.keys()].sort(feeCompareFn);
|
|
81
|
+
|
|
82
|
+
for (const fee of sortedFees) {
|
|
83
|
+
const hashesAtFee = this.#pendingByPriority.get(fee)!;
|
|
84
|
+
const sortedHashes = [...hashesAtFee].sort(hashCompareFn);
|
|
85
|
+
for (const hashBigInt of sortedHashes) {
|
|
86
|
+
const hash = txHashFromBigInt(hashBigInt);
|
|
87
|
+
if (filter === undefined || filter(hash)) {
|
|
88
|
+
yield hash;
|
|
89
|
+
}
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
}
|
|
@@ -222,7 +227,11 @@ export class TxPoolIndices {
|
|
|
222
227
|
|
|
223
228
|
/** Gets the count of pending transactions */
|
|
224
229
|
getPendingTxCount(): number {
|
|
225
|
-
|
|
230
|
+
let count = 0;
|
|
231
|
+
for (const hashes of this.#pendingByPriority.values()) {
|
|
232
|
+
count += hashes.size;
|
|
233
|
+
}
|
|
234
|
+
return count;
|
|
226
235
|
}
|
|
227
236
|
|
|
228
237
|
/** Gets the lowest priority pending transaction hashes (up to limit) */
|
|
@@ -255,10 +264,12 @@ export class TxPoolIndices {
|
|
|
255
264
|
/** Gets all pending transactions */
|
|
256
265
|
getPendingTxs(): TxMetaData[] {
|
|
257
266
|
const result: TxMetaData[] = [];
|
|
258
|
-
for (const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
267
|
+
for (const hashSet of this.#pendingByPriority.values()) {
|
|
268
|
+
for (const txHashBigInt of hashSet) {
|
|
269
|
+
const meta = this.#metadata.get(txHashFromBigInt(txHashBigInt));
|
|
270
|
+
if (meta) {
|
|
271
|
+
result.push(meta);
|
|
272
|
+
}
|
|
262
273
|
}
|
|
263
274
|
}
|
|
264
275
|
return result;
|
|
@@ -397,12 +408,13 @@ export class TxPoolIndices {
|
|
|
397
408
|
}
|
|
398
409
|
feePayerSet.add(meta.txHash);
|
|
399
410
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
411
|
+
// Add to priority bucket
|
|
412
|
+
let prioritySet = this.#pendingByPriority.get(meta.priorityFee);
|
|
413
|
+
if (!prioritySet) {
|
|
414
|
+
prioritySet = new Set();
|
|
415
|
+
this.#pendingByPriority.set(meta.priorityFee, prioritySet);
|
|
416
|
+
}
|
|
417
|
+
prioritySet.add(meta.txHashBigInt);
|
|
406
418
|
}
|
|
407
419
|
|
|
408
420
|
#removeFromPendingIndices(meta: TxMetaData): void {
|
|
@@ -420,11 +432,13 @@ export class TxPoolIndices {
|
|
|
420
432
|
}
|
|
421
433
|
}
|
|
422
434
|
|
|
423
|
-
// Remove from priority
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
435
|
+
// Remove from priority map
|
|
436
|
+
const hashSet = this.#pendingByPriority.get(meta.priorityFee);
|
|
437
|
+
if (hashSet) {
|
|
438
|
+
hashSet.delete(meta.txHashBigInt);
|
|
439
|
+
if (hashSet.size === 0) {
|
|
440
|
+
this.#pendingByPriority.delete(meta.priorityFee);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
429
443
|
}
|
|
430
444
|
}
|
|
@@ -65,9 +65,6 @@ export class AztecKVTxPoolV2 extends (EventEmitter as new () => TypedEventEmitte
|
|
|
65
65
|
const hashes = txHashes.map(h => (typeof h === 'string' ? TxHash.fromString(h) : TxHash.fromBigInt(h)));
|
|
66
66
|
this.emit('txs-removed', { txHashes: hashes });
|
|
67
67
|
},
|
|
68
|
-
onTxsMined: (txHashes: string[]) => {
|
|
69
|
-
this.#metrics?.transactionsRemoved(txHashes);
|
|
70
|
-
},
|
|
71
68
|
};
|
|
72
69
|
|
|
73
70
|
// Create the implementation
|
|
@@ -45,7 +45,6 @@ import { TxPoolIndices } from './tx_pool_indices.js';
|
|
|
45
45
|
export interface TxPoolV2Callbacks {
|
|
46
46
|
onTxsAdded: (txs: Tx[], opts: { source?: string }) => void;
|
|
47
47
|
onTxsRemoved: (txHashes: string[] | bigint[]) => void;
|
|
48
|
-
onTxsMined: (txHashes: string[]) => void;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -340,12 +339,6 @@ export class TxPoolV2Impl {
|
|
|
340
339
|
}
|
|
341
340
|
}
|
|
342
341
|
|
|
343
|
-
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
344
|
-
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
345
|
-
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
346
|
-
return { status: 'accepted' };
|
|
347
|
-
}
|
|
348
|
-
|
|
349
342
|
// Add the transaction
|
|
350
343
|
await this.#addTx(tx, 'pending', opts, precomputedMeta);
|
|
351
344
|
return { status: 'accepted' };
|
|
@@ -356,7 +349,6 @@ export class TxPoolV2Impl {
|
|
|
356
349
|
|
|
357
350
|
// Check if already in pool
|
|
358
351
|
if (this.#indices.has(txHashStr)) {
|
|
359
|
-
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
|
|
360
352
|
return 'ignored';
|
|
361
353
|
}
|
|
362
354
|
|
|
@@ -365,13 +357,7 @@ export class TxPoolV2Impl {
|
|
|
365
357
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
366
358
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
367
359
|
|
|
368
|
-
|
|
369
|
-
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
|
|
370
|
-
reason: preAddResult.reason?.message ?? 'no reason provided',
|
|
371
|
-
});
|
|
372
|
-
return 'ignored';
|
|
373
|
-
}
|
|
374
|
-
return 'accepted';
|
|
360
|
+
return preAddResult.shouldIgnore ? 'ignored' : 'accepted';
|
|
375
361
|
}
|
|
376
362
|
|
|
377
363
|
async addProtectedTxs(txs: Tx[], block: BlockHeader, opts: { source?: string }): Promise<void> {
|
|
@@ -515,10 +501,6 @@ export class TxPoolV2Impl {
|
|
|
515
501
|
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
516
502
|
});
|
|
517
503
|
|
|
518
|
-
if (found.length > 0) {
|
|
519
|
-
this.#callbacks.onTxsMined(found.map(m => m.txHash));
|
|
520
|
-
}
|
|
521
|
-
|
|
522
504
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
523
505
|
}
|
|
524
506
|
|
|
@@ -24,7 +24,7 @@ This module validates `CheckpointAttestation` gossipsub messages. Attestations a
|
|
|
24
24
|
|---|------|-------------|
|
|
25
25
|
| 8 | Sender recoverable (pool-side) | Silent drop |
|
|
26
26
|
| 9 | Not a duplicate (same slot + proposalId + signer) | IGNORE |
|
|
27
|
-
| 10 | Per-signer cap: `MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER` =
|
|
27
|
+
| 10 | Per-signer cap: `MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER` = 3 | IGNORE |
|
|
28
28
|
|
|
29
29
|
Own attestations added via `addOwnCheckpointAttestations` bypass the per-signer cap.
|
|
30
30
|
|
|
@@ -23,14 +23,13 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
|
|
|
23
23
|
const slotNumber = message.payload.header.slotNumber;
|
|
24
24
|
|
|
25
25
|
try {
|
|
26
|
-
|
|
27
|
-
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
|
|
26
|
+
const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
|
|
28
27
|
|
|
29
|
-
if (slotNumber !==
|
|
28
|
+
if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
|
|
30
29
|
// Check if message is for previous slot and within clock tolerance
|
|
31
|
-
if (!isWithinClockTolerance(slotNumber,
|
|
30
|
+
if (!isWithinClockTolerance(slotNumber, currentSlot, this.epochCache)) {
|
|
32
31
|
this.logger.warn(
|
|
33
|
-
`Checkpoint attestation slot ${slotNumber} is not current (${
|
|
32
|
+
`Checkpoint attestation slot ${slotNumber} is not current (${currentSlot}) or next (${nextSlot}) slot`,
|
|
34
33
|
);
|
|
35
34
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
36
35
|
}
|
|
@@ -36,11 +36,10 @@ export function isWithinClockTolerance(
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Check how far we are into the current slot (in milliseconds)
|
|
39
|
-
const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
|
|
40
|
-
const targetSlot = epochCache.getTargetSlot();
|
|
39
|
+
const { ts: slotStartTs, nowMs, slot } = epochCache.getEpochAndSlotNow();
|
|
41
40
|
|
|
42
|
-
// Sanity check: ensure the epoch cache's
|
|
43
|
-
if (
|
|
41
|
+
// Sanity check: ensure the epoch cache's current slot matches the expected current slot
|
|
42
|
+
if (slot !== currentSlot) {
|
|
44
43
|
return false;
|
|
45
44
|
}
|
|
46
45
|
|
|
@@ -28,7 +28,7 @@ Deserialization guards: `BlockProposal.fromBuffer` and `SignedTxs.fromBuffer` bo
|
|
|
28
28
|
| # | Rule | Consequence |
|
|
29
29
|
|---|------|-------------|
|
|
30
30
|
| 9 | **Duplicate**: same archive root already stored | IGNORE (no penalty) |
|
|
31
|
-
| 10 | **Per-position cap**: max
|
|
31
|
+
| 10 | **Per-position cap**: max 3 proposals per (slot, indexWithinCheckpoint) | REJECT + HighToleranceError |
|
|
32
32
|
| 11 | **Equivocation**: >1 distinct proposal for same (slot, index) | ACCEPT (rebroadcast for detection). At count=2: `duplicateProposalCallback` fires -> slash event (`OffenseType.DUPLICATE_PROPOSAL`, configured via `slashDuplicateProposalPenalty`) |
|
|
33
33
|
|
|
34
34
|
### Stage 3: Validator-Client Processing (BlockProposalHandler)
|
|
@@ -84,7 +84,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
|
|
|
84
84
|
| Rule | Consequence | File |
|
|
85
85
|
|------|-------------|------|
|
|
86
86
|
| Block proposal must pass `BlockProposalValidator.validate()` | If REJECT: entire checkpoint REJECTED | `libp2p_service.ts` |
|
|
87
|
-
| Block proposal must not exceed per-position cap (
|
|
87
|
+
| Block proposal must not exceed per-position cap (3) | Checkpoint REJECTED + HighToleranceError | same |
|
|
88
88
|
| Block equivocation detected (>1 proposals for same slot+index) | Checkpoint REJECTED (block itself is ACCEPT for re-broadcast) | same |
|
|
89
89
|
|
|
90
90
|
### Stage 3: Mempool (Attestation Pool)
|
|
@@ -92,7 +92,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
|
|
|
92
92
|
| Rule | Consequence | File |
|
|
93
93
|
|------|-------------|------|
|
|
94
94
|
| Duplicate (same archive ID) | IGNORE (no penalty). Embedded block still processed if valid. | `attestation_pool.ts` |
|
|
95
|
-
| Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` =
|
|
95
|
+
| Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` = 5 | REJECT + HighToleranceError. Embedded block still processed. | same |
|
|
96
96
|
|
|
97
97
|
### Stage 4: Equivocation Detection
|
|
98
98
|
|
|
@@ -31,14 +31,13 @@ export class ProposalValidator {
|
|
|
31
31
|
/** Validates header-level fields: slot, signature, and proposer. */
|
|
32
32
|
public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
|
|
33
33
|
try {
|
|
34
|
-
// Slot check
|
|
35
|
-
const {
|
|
36
|
-
|
|
34
|
+
// Slot check
|
|
35
|
+
const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
|
|
37
36
|
const slotNumber = proposal.slotNumber;
|
|
38
|
-
if (slotNumber !==
|
|
37
|
+
if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
|
|
39
38
|
// Check if message is for previous slot and within clock tolerance
|
|
40
|
-
if (!isWithinClockTolerance(slotNumber,
|
|
41
|
-
this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, {
|
|
39
|
+
if (!isWithinClockTolerance(slotNumber, currentSlot, this.epochCache)) {
|
|
40
|
+
this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { currentSlot, nextSlot });
|
|
42
41
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
43
42
|
}
|
|
44
43
|
this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { ContractInstancePublishedEvent } from '@aztec/protocol-contracts/instance-registry';
|
|
3
|
+
import { computeContractAddressFromInstance } from '@aztec/stdlib/contract';
|
|
4
|
+
import {
|
|
5
|
+
TX_ERROR_INCORRECT_CONTRACT_ADDRESS,
|
|
6
|
+
TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG,
|
|
7
|
+
type Tx,
|
|
8
|
+
type TxValidationResult,
|
|
9
|
+
type TxValidator,
|
|
10
|
+
} from '@aztec/stdlib/tx';
|
|
11
|
+
|
|
12
|
+
/** Validates that contract instance deployment logs contain correct addresses. */
|
|
13
|
+
export class ContractInstanceTxValidator implements TxValidator<Tx> {
|
|
14
|
+
#log: Logger;
|
|
15
|
+
|
|
16
|
+
constructor(bindings?: LoggerBindings) {
|
|
17
|
+
this.#log = createLogger('p2p:tx_validator:contract_instance', bindings);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
21
|
+
const reason = await this.#hasCorrectContractInstanceAddresses(tx);
|
|
22
|
+
return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async #hasCorrectContractInstanceAddresses(tx: Tx): Promise<string | undefined> {
|
|
26
|
+
const privateLogs = tx.data.getNonEmptyPrivateLogs();
|
|
27
|
+
for (const log of privateLogs) {
|
|
28
|
+
if (!ContractInstancePublishedEvent.isContractInstancePublishedEvent(log)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let event;
|
|
33
|
+
try {
|
|
34
|
+
event = ContractInstancePublishedEvent.fromLog(log);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract instance event: ${e}`);
|
|
37
|
+
return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const instance = event.toContractInstance();
|
|
42
|
+
const computedAddress = await computeContractAddressFromInstance(instance);
|
|
43
|
+
if (!computedAddress.equals(instance.address)) {
|
|
44
|
+
this.#log.warn(
|
|
45
|
+
`Rejecting tx ${tx.getTxHash()}: contract instance address mismatch. Claimed ${instance.address}, computed ${computedAddress}`,
|
|
46
|
+
);
|
|
47
|
+
return TX_ERROR_INCORRECT_CONTRACT_ADDRESS;
|
|
48
|
+
}
|
|
49
|
+
} catch (e) {
|
|
50
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract instance address: ${e}`);
|
|
51
|
+
return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS } from '@aztec/constants';
|
|
2
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
4
|
+
import { computeContractClassId } from '@aztec/stdlib/contract';
|
|
3
5
|
import { computeCalldataHash } from '@aztec/stdlib/hash';
|
|
4
6
|
import {
|
|
5
7
|
TX_ERROR_CALLDATA_COUNT_MISMATCH,
|
|
@@ -9,7 +11,9 @@ import {
|
|
|
9
11
|
TX_ERROR_CONTRACT_CLASS_LOG_LENGTH,
|
|
10
12
|
TX_ERROR_CONTRACT_CLASS_LOG_SORTING,
|
|
11
13
|
TX_ERROR_INCORRECT_CALLDATA,
|
|
14
|
+
TX_ERROR_INCORRECT_CONTRACT_CLASS_ID,
|
|
12
15
|
TX_ERROR_INCORRECT_HASH,
|
|
16
|
+
TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG,
|
|
13
17
|
Tx,
|
|
14
18
|
type TxValidationResult,
|
|
15
19
|
type TxValidator,
|
|
@@ -26,7 +30,8 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
26
30
|
const reason =
|
|
27
31
|
(await this.#hasCorrectHash(tx)) ??
|
|
28
32
|
(await this.#hasCorrectCalldata(tx)) ??
|
|
29
|
-
(await this.#hasCorrectContractClassLogs(tx))
|
|
33
|
+
(await this.#hasCorrectContractClassLogs(tx)) ??
|
|
34
|
+
(await this.#hasCorrectContractClassIds(tx));
|
|
30
35
|
return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -127,4 +132,40 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
127
132
|
|
|
128
133
|
return undefined;
|
|
129
134
|
}
|
|
135
|
+
|
|
136
|
+
async #hasCorrectContractClassIds(tx: Tx): Promise<string | undefined> {
|
|
137
|
+
const contractClassLogs = tx.getContractClassLogs();
|
|
138
|
+
for (const log of contractClassLogs) {
|
|
139
|
+
if (!ContractClassPublishedEvent.isContractClassPublishedEvent(log)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let event;
|
|
144
|
+
try {
|
|
145
|
+
event = ContractClassPublishedEvent.fromLog(log);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract class event: ${e}`);
|
|
148
|
+
return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const { publicBytecodeCommitment } = await event.toContractClassPublicWithBytecodeCommitment();
|
|
153
|
+
const computedClassId = await computeContractClassId({
|
|
154
|
+
artifactHash: event.artifactHash,
|
|
155
|
+
privateFunctionsRoot: event.privateFunctionsRoot,
|
|
156
|
+
publicBytecodeCommitment,
|
|
157
|
+
});
|
|
158
|
+
if (!computedClassId.equals(event.contractClassId)) {
|
|
159
|
+
this.#log.warn(
|
|
160
|
+
`Rejecting tx ${tx.getTxHash()}: contract class id mismatch. Claimed ${event.contractClassId}, computed ${computedClassId}`,
|
|
161
|
+
);
|
|
162
|
+
return TX_ERROR_INCORRECT_CONTRACT_CLASS_ID;
|
|
163
|
+
}
|
|
164
|
+
} catch (e) {
|
|
165
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract class id: ${e}`);
|
|
166
|
+
return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
130
171
|
}
|
|
@@ -53,6 +53,7 @@ import type { TxMetaData } from '../../mem_pools/tx_pool_v2/tx_metadata.js';
|
|
|
53
53
|
import { AggregateTxValidator } from './aggregate_tx_validator.js';
|
|
54
54
|
import { ArchiveCache } from './archive_cache.js';
|
|
55
55
|
import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_validator.js';
|
|
56
|
+
import { ContractInstanceTxValidator } from './contract_instance_validator.js';
|
|
56
57
|
import { DataTxValidator } from './data_validator.js';
|
|
57
58
|
import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
|
|
58
59
|
import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
|
|
@@ -167,6 +168,10 @@ export function createFirstStageTxValidationsForGossipedTransactions(
|
|
|
167
168
|
validator: new DataTxValidator(bindings),
|
|
168
169
|
severity: PeerErrorSeverity.MidToleranceError,
|
|
169
170
|
},
|
|
171
|
+
contractInstanceValidator: {
|
|
172
|
+
validator: new ContractInstanceTxValidator(bindings),
|
|
173
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
174
|
+
},
|
|
170
175
|
};
|
|
171
176
|
}
|
|
172
177
|
|
|
@@ -218,6 +223,7 @@ function createTxValidatorForMinimumTxIntegrityChecks(
|
|
|
218
223
|
),
|
|
219
224
|
new SizeTxValidator(bindings),
|
|
220
225
|
new DataTxValidator(bindings),
|
|
226
|
+
new ContractInstanceTxValidator(bindings),
|
|
221
227
|
new TxProofValidator(verifier, bindings),
|
|
222
228
|
);
|
|
223
229
|
}
|
|
@@ -321,6 +327,7 @@ export function createTxValidatorForAcceptingTxsOverRPC(
|
|
|
321
327
|
new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
|
|
322
328
|
new DoubleSpendTxValidator(new NullifierCache(db), bindings),
|
|
323
329
|
new DataTxValidator(bindings),
|
|
330
|
+
new ContractInstanceTxValidator(bindings),
|
|
324
331
|
];
|
|
325
332
|
|
|
326
333
|
if (!skipFeeEnforcement) {
|
|
@@ -28,24 +28,16 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
28
28
|
validateTx(tx: T): Promise<TxValidationResult> {
|
|
29
29
|
const errors = [];
|
|
30
30
|
if (!this.#hasCorrectL1ChainId(tx)) {
|
|
31
|
-
errors.push(
|
|
32
|
-
`${TX_ERROR_INCORRECT_L1_CHAIN_ID} (tx: ${tx.data.constants.txContext.chainId.toNumber()}, expected: ${this.values.l1ChainId.toNumber()})`,
|
|
33
|
-
);
|
|
31
|
+
errors.push(TX_ERROR_INCORRECT_L1_CHAIN_ID);
|
|
34
32
|
}
|
|
35
33
|
if (!this.#hasCorrectRollupVersion(tx)) {
|
|
36
|
-
errors.push(
|
|
37
|
-
`${TX_ERROR_INCORRECT_ROLLUP_VERSION} (tx: ${tx.data.constants.txContext.version.toNumber()}, expected: ${this.values.rollupVersion.toNumber()})`,
|
|
38
|
-
);
|
|
34
|
+
errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
|
|
39
35
|
}
|
|
40
36
|
if (!this.#hasCorrectVkTreeRoot(tx)) {
|
|
41
|
-
errors.push(
|
|
42
|
-
`${TX_ERROR_INCORRECT_VK_TREE_ROOT} (tx: ${tx.data.constants.vkTreeRoot.toString()}, expected: ${this.values.vkTreeRoot.toString()})`,
|
|
43
|
-
);
|
|
37
|
+
errors.push(TX_ERROR_INCORRECT_VK_TREE_ROOT);
|
|
44
38
|
}
|
|
45
39
|
if (!this.#hasCorrectprotocolContractsHash(tx)) {
|
|
46
|
-
errors.push(
|
|
47
|
-
`${TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH} (tx: ${tx.data.constants.protocolContractsHash.toString()}, expected: ${this.values.protocolContractsHash.toString()})`,
|
|
48
|
-
);
|
|
40
|
+
errors.push(TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH);
|
|
49
41
|
}
|
|
50
42
|
return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
|
|
51
43
|
}
|
|
@@ -40,7 +40,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
40
40
|
// which are needed for public FPC flows, but fail if the account contract hasnt been deployed yet,
|
|
41
41
|
// which is what we're trying to do as part of the current txs.
|
|
42
42
|
// We only need to create/revert checkpoint here because of this addNewContracts call.
|
|
43
|
-
|
|
43
|
+
this.contractsDB.addNewContracts(tx);
|
|
44
44
|
|
|
45
45
|
if (!tx.data.forPublic) {
|
|
46
46
|
this.#log.debug(
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type CheckpointProposalCore,
|
|
19
19
|
type Gossipable,
|
|
20
20
|
P2PMessage,
|
|
21
|
+
type ValidationResult as P2PValidationResult,
|
|
21
22
|
PeerErrorSeverity,
|
|
22
23
|
PeerErrorSeverityByHarshness,
|
|
23
24
|
TopicType,
|
|
@@ -753,9 +754,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
753
754
|
if (!validator || !validator.addMessage(msgId)) {
|
|
754
755
|
this.instrumentation.incMessagePrevalidationStatus(false, topicType);
|
|
755
756
|
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
|
-
}
|
|
759
757
|
return { result: false, topicType };
|
|
760
758
|
}
|
|
761
759
|
|
|
@@ -925,11 +923,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
925
923
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
926
924
|
}
|
|
927
925
|
|
|
928
|
-
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 1 validation failed`, {
|
|
929
|
-
validator: name,
|
|
930
|
-
severity,
|
|
931
|
-
source: source.toString(),
|
|
932
|
-
});
|
|
933
926
|
this.peerManager.penalizePeer(source, severity);
|
|
934
927
|
return { result: TopicValidatorResult.Reject };
|
|
935
928
|
}
|
|
@@ -937,9 +930,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
937
930
|
// Pool pre-check: see if the pool would accept this tx before doing expensive proof verification
|
|
938
931
|
const canAdd = await this.mempools.txPool.canAddPendingTx(tx);
|
|
939
932
|
if (canAdd === 'ignored') {
|
|
940
|
-
this.logger.verbose(`Ignoring gossiped tx ${tx.getTxHash().toString()}: pool pre-check returned ignored`, {
|
|
941
|
-
source: source.toString(),
|
|
942
|
-
});
|
|
943
933
|
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
944
934
|
}
|
|
945
935
|
|
|
@@ -947,12 +937,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
947
937
|
const secondStageValidators = this.createSecondStageMessageValidators();
|
|
948
938
|
const secondStageOutcome = await this.runValidations(tx, secondStageValidators);
|
|
949
939
|
if (!secondStageOutcome.allPassed) {
|
|
950
|
-
const { severity
|
|
951
|
-
this.logger.verbose(`Rejecting gossiped tx ${tx.getTxHash().toString()}: stage 2 validation failed`, {
|
|
952
|
-
validator: name,
|
|
953
|
-
severity,
|
|
954
|
-
source: source.toString(),
|
|
955
|
-
});
|
|
940
|
+
const { severity } = secondStageOutcome.failure;
|
|
956
941
|
this.peerManager.penalizePeer(source, severity);
|
|
957
942
|
return { result: TopicValidatorResult.Reject };
|
|
958
943
|
}
|
|
@@ -964,7 +949,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
964
949
|
const wasAccepted = addResult.accepted.some(h => h.equals(txHash));
|
|
965
950
|
const wasIgnored = addResult.ignored.some(h => h.equals(txHash));
|
|
966
951
|
|
|
967
|
-
this.logger.
|
|
952
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
968
953
|
wasAccepted,
|
|
969
954
|
wasIgnored,
|
|
970
955
|
[Attributes.P2P_ID]: source.toString(),
|
|
@@ -1746,6 +1731,31 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1746
1731
|
return PeerErrorSeverity.HighToleranceError;
|
|
1747
1732
|
}
|
|
1748
1733
|
|
|
1734
|
+
/**
|
|
1735
|
+
* Validate a checkpoint attestation.
|
|
1736
|
+
*
|
|
1737
|
+
* @param attestation - The checkpoint attestation to validate.
|
|
1738
|
+
* @returns True if the checkpoint attestation is valid, false otherwise.
|
|
1739
|
+
*/
|
|
1740
|
+
@trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation) => ({
|
|
1741
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1742
|
+
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1743
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1744
|
+
}))
|
|
1745
|
+
public async validateCheckpointAttestation(
|
|
1746
|
+
peerId: PeerId,
|
|
1747
|
+
attestation: CheckpointAttestation,
|
|
1748
|
+
): Promise<P2PValidationResult> {
|
|
1749
|
+
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1750
|
+
|
|
1751
|
+
if (result.result === 'reject') {
|
|
1752
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1753
|
+
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
return result;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1749
1759
|
public getPeerScore(peerId: PeerId): number {
|
|
1750
1760
|
return this.node.services.pubsub.score.score(peerId.toString());
|
|
1751
1761
|
}
|
|
@@ -18,7 +18,6 @@ export class PeerManagerMetrics {
|
|
|
18
18
|
private sentGoodbyes: UpDownCounter;
|
|
19
19
|
private receivedGoodbyes: UpDownCounter;
|
|
20
20
|
private peerCount: Gauge;
|
|
21
|
-
private healthyPeerCount: Gauge;
|
|
22
21
|
private lowScoreDisconnects: UpDownCounter;
|
|
23
22
|
private peerConnectionDuration: Histogram;
|
|
24
23
|
|
|
@@ -50,7 +49,6 @@ export class PeerManagerMetrics {
|
|
|
50
49
|
goodbyeReasonAttrs,
|
|
51
50
|
);
|
|
52
51
|
this.peerCount = meter.createGauge(Metrics.PEER_MANAGER_PEER_COUNT);
|
|
53
|
-
this.healthyPeerCount = meter.createGauge(Metrics.PEER_MANAGER_HEALTHY_PEER_COUNT);
|
|
54
52
|
this.lowScoreDisconnects = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_LOW_SCORE_DISCONNECTS, {
|
|
55
53
|
[Attributes.P2P_PEER_SCORE_STATE]: ['Banned', 'Disconnect'],
|
|
56
54
|
});
|
|
@@ -69,10 +67,6 @@ export class PeerManagerMetrics {
|
|
|
69
67
|
this.peerCount.record(count);
|
|
70
68
|
}
|
|
71
69
|
|
|
72
|
-
public recordHealthyPeerCount(count: number) {
|
|
73
|
-
this.healthyPeerCount.record(count);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
70
|
public recordLowScoreDisconnect(scoreState: 'Banned' | 'Disconnect') {
|
|
77
71
|
this.lowScoreDisconnects.add(1, { [Attributes.P2P_PEER_SCORE_STATE]: scoreState });
|
|
78
72
|
}
|
|
@@ -85,7 +79,6 @@ export class PeerManagerMetrics {
|
|
|
85
79
|
const connectedAt = this.peerConnectedAt.get(id.toString());
|
|
86
80
|
if (connectedAt) {
|
|
87
81
|
this.peerConnectionDuration.record(Date.now() - connectedAt);
|
|
88
|
-
this.peerConnectedAt.delete(id.toString());
|
|
89
82
|
}
|
|
90
83
|
}
|
|
91
84
|
}
|
|
@@ -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 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
|
|
|
@@ -515,8 +515,7 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
515
515
|
...this.peerScoring.getStats(),
|
|
516
516
|
});
|
|
517
517
|
|
|
518
|
-
this.metrics.recordPeerCount(
|
|
519
|
-
this.metrics.recordHealthyPeerCount(healthyConnections.length);
|
|
518
|
+
this.metrics.recordPeerCount(healthyConnections.length);
|
|
520
519
|
|
|
521
520
|
// Exit if no peers to connect
|
|
522
521
|
if (peersToConnect <= 0) {
|
|
@@ -776,8 +775,7 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
776
775
|
// Add to timed out peers
|
|
777
776
|
this.timedOutPeers.set(id, {
|
|
778
777
|
peerId: id,
|
|
779
|
-
timeoutUntilMs:
|
|
780
|
-
this.dateProvider.now() + (this.config.peerFailedBanTimeMs ?? DEFAULT_FAILED_PEER_BAN_TIME_MS),
|
|
778
|
+
timeoutUntilMs: this.dateProvider.now() + FAILED_PEER_BAN_TIME_MS,
|
|
781
779
|
});
|
|
782
780
|
}
|
|
783
781
|
}
|
|
@@ -939,8 +937,6 @@ export class PeerManager implements PeerManagerInterface {
|
|
|
939
937
|
`Received auth for validator ${sender.toString()} from peer ${peerIdString}, but this validator is already authenticated to peer ${peerForAddress.toString()}`,
|
|
940
938
|
{ ...logData, address: sender.toString() },
|
|
941
939
|
);
|
|
942
|
-
this.markAuthHandshakeFailed(peerId);
|
|
943
|
-
this.markPeerForDisconnect(peerId);
|
|
944
940
|
return;
|
|
945
941
|
}
|
|
946
942
|
|