@aztec/p2p 0.0.1-commit.e3c1de76 → 0.0.1-commit.e558bd1c
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 +3 -3
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +5 -3
- package/dest/client/interface.d.ts +9 -2
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +7 -4
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +22 -7
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +1 -1
- package/dest/config.d.ts +9 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +94 -87
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +411 -3
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +351 -85
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -2
- package/dest/mem_pools/index.d.ts +2 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/index.js +1 -1
- package/dest/mem_pools/interface.d.ts +3 -3
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts +2 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +43 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +103 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +47 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +119 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +90 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +19 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +89 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +10 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +11 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +131 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +63 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +17 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +91 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +70 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +20 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +63 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +19 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts +5 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/index.js +4 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +197 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.js +6 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +71 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +95 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts +26 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.js +70 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +99 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +332 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +55 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +156 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +69 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +748 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +3 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/services/dummy_service.d.ts +6 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +3 -0
- package/dest/services/index.d.ts +2 -1
- package/dest/services/index.d.ts.map +1 -1
- package/dest/services/index.js +1 -0
- package/dest/services/libp2p/libp2p_service.d.ts +74 -33
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +299 -228
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -4
- 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 +8 -8
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +6 -4
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +16 -11
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +15 -10
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +12 -11
- package/dest/services/service.d.ts +18 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +3 -3
- package/dest/services/tx_collection/config.js +3 -3
- package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -5
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +10 -14
- package/dest/services/tx_collection/index.d.ts +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +12 -12
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +4 -5
- package/dest/services/tx_file_store/config.d.ts +18 -0
- package/dest/services/tx_file_store/config.d.ts.map +1 -0
- package/dest/services/tx_file_store/config.js +26 -0
- package/dest/services/tx_file_store/index.d.ts +4 -0
- package/dest/services/tx_file_store/index.d.ts.map +1 -0
- package/dest/services/tx_file_store/index.js +3 -0
- package/dest/services/tx_file_store/instrumentation.d.ts +15 -0
- package/dest/services/tx_file_store/instrumentation.d.ts.map +1 -0
- package/dest/services/tx_file_store/instrumentation.js +29 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts +47 -0
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -0
- package/dest/services/tx_file_store/tx_file_store.js +149 -0
- package/dest/test-helpers/testbench-utils.d.ts +10 -16
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +32 -30
- package/dest/testbench/p2p_client_testbench_worker.js +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +7 -4
- package/src/client/interface.ts +13 -1
- package/src/client/p2p_client.ts +30 -8
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +1 -1
- package/src/config.ts +8 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +444 -90
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +436 -100
- package/src/mem_pools/attestation_pool/index.ts +9 -2
- package/src/mem_pools/index.ts +1 -1
- package/src/mem_pools/interface.ts +2 -2
- package/src/mem_pools/tx_pool_v2/README.md +209 -0
- package/src/mem_pools/tx_pool_v2/archive/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +120 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +147 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +118 -0
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +111 -0
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +23 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +164 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +74 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +101 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +86 -0
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +72 -0
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +31 -0
- package/src/mem_pools/tx_pool_v2/index.ts +11 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +227 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +161 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_bench_metrics.ts +77 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +417 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +212 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +882 -0
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +2 -2
- package/src/services/dummy_service.ts +6 -0
- package/src/services/index.ts +1 -0
- package/src/services/libp2p/libp2p_service.ts +304 -230
- package/src/services/reqresp/batch-tx-requester/README.md +7 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +11 -11
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +22 -13
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +21 -15
- package/src/services/service.ts +20 -0
- package/src/services/tx_collection/config.ts +6 -6
- package/src/services/tx_collection/fast_tx_collection.ts +14 -24
- package/src/services/tx_collection/index.ts +1 -1
- package/src/services/tx_collection/proposal_tx_collector.ts +12 -14
- package/src/services/tx_file_store/config.ts +43 -0
- package/src/services/tx_file_store/index.ts +3 -0
- package/src/services/tx_file_store/instrumentation.ts +36 -0
- package/src/services/tx_file_store/tx_file_store.ts +173 -0
- package/src/test-helpers/testbench-utils.ts +18 -39
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -218
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -180
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
|
@@ -370,7 +370,7 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _initProto;
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _initProto;
|
|
374
374
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
375
375
|
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
376
376
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
@@ -395,12 +395,9 @@ import { mplex } from '@libp2p/mplex';
|
|
|
395
395
|
import { tcp } from '@libp2p/tcp';
|
|
396
396
|
import { ENR } from '@nethermindeth/enr';
|
|
397
397
|
import { createLibp2p } from 'libp2p';
|
|
398
|
-
import {
|
|
399
|
-
import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, FishermanAttestationValidator } from '../../msg_validators/index.js';
|
|
398
|
+
import { BlockProposalValidator, CheckpointAttestationValidator, CheckpointProposalValidator, DoubleSpendTxValidator, FishermanAttestationValidator, getDefaultAllowedSetupFunctions } from '../../msg_validators/index.js';
|
|
400
399
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
401
|
-
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
402
400
|
import { createTxMessageValidators, createTxReqRespValidator } from '../../msg_validators/tx_validator/factory.js';
|
|
403
|
-
import { DoubleSpendTxValidator } from '../../msg_validators/tx_validator/index.js';
|
|
404
401
|
import { GossipSubEvent } from '../../types/index.js';
|
|
405
402
|
import { convertToMultiaddr } from '../../util.js';
|
|
406
403
|
import { getVersions } from '../../versioning.js';
|
|
@@ -410,36 +407,37 @@ import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encod
|
|
|
410
407
|
import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
411
408
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
412
409
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
413
|
-
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError } from '../reqresp/
|
|
414
|
-
import { reqRespBlockTxsHandler } from '../reqresp/
|
|
415
|
-
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
416
|
-
import { pingHandler, reqRespBlockHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/protocols/index.js';
|
|
410
|
+
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, ValidationError } from '../reqresp/index.js';
|
|
411
|
+
import { pingHandler, reqGoodbyeHandler, reqRespBlockHandler, reqRespBlockTxsHandler, reqRespStatusHandler, reqRespTxHandler } from '../reqresp/index.js';
|
|
417
412
|
import { ReqResp } from '../reqresp/reqresp.js';
|
|
418
413
|
import { P2PInstrumentation } from './instrumentation.js';
|
|
419
|
-
_dec = trackSpan('Libp2pService.
|
|
414
|
+
_dec = trackSpan('Libp2pService.validateAndStoreCheckpointAttestation', (_peerId, attestation)=>({
|
|
415
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString()
|
|
416
|
+
})), _dec1 = trackSpan('Libp2pService.validateAndStoreBlockProposal', (_peerId, block)=>({
|
|
417
|
+
[Attributes.BLOCK_NUMBER]: block.blockNumber.toString(),
|
|
418
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber.toString()
|
|
419
|
+
})), _dec2 = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
420
420
|
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
421
421
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
422
422
|
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
423
|
-
})),
|
|
423
|
+
})), _dec3 = trackSpan('Libp2pService.validateAndStoreCheckpointProposal', (_peerId, checkpoint)=>({
|
|
424
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString()
|
|
425
|
+
})), _dec4 = trackSpan('Libp2pService.processValidCheckpointProposal', async (checkpoint)=>({
|
|
424
426
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber,
|
|
425
427
|
[Attributes.BLOCK_ARCHIVE]: checkpoint.archive.toString(),
|
|
426
428
|
[Attributes.P2P_ID]: await checkpoint.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
427
|
-
})),
|
|
429
|
+
})), _dec5 = trackSpan('Libp2pService.validateRequestedBlockTxs', (request)=>({
|
|
428
430
|
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString()
|
|
429
|
-
})),
|
|
431
|
+
})), _dec6 = trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx)=>({
|
|
430
432
|
[Attributes.TX_HASH]: requestedTxHash.toString()
|
|
431
|
-
})),
|
|
433
|
+
})), _dec7 = trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock)=>({
|
|
432
434
|
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString()
|
|
433
|
-
})),
|
|
435
|
+
})), _dec8 = trackSpan('Libp2pService.validatePropagatedTx', (tx)=>({
|
|
434
436
|
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
435
|
-
})),
|
|
437
|
+
})), _dec9 = trackSpan('Libp2pService.validateCheckpointAttestation', async (_, attestation)=>({
|
|
436
438
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
437
439
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
438
440
|
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then((i)=>i.toString())
|
|
439
|
-
})), _dec7 = trackSpan('Libp2pService.validateBlockProposal', (_peerId, block)=>({
|
|
440
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toString()
|
|
441
|
-
})), _dec8 = trackSpan('Libp2pService.validateCheckpointProposal', (_peerId, checkpoint)=>({
|
|
442
|
-
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString()
|
|
443
441
|
}));
|
|
444
442
|
/**
|
|
445
443
|
* Lib P2P implementation of the P2PService interface.
|
|
@@ -460,47 +458,52 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
460
458
|
[
|
|
461
459
|
_dec,
|
|
462
460
|
2,
|
|
463
|
-
"
|
|
461
|
+
"validateAndStoreCheckpointAttestation"
|
|
464
462
|
],
|
|
465
463
|
[
|
|
466
464
|
_dec1,
|
|
467
465
|
2,
|
|
468
|
-
"
|
|
466
|
+
"validateAndStoreBlockProposal"
|
|
469
467
|
],
|
|
470
468
|
[
|
|
471
469
|
_dec2,
|
|
472
470
|
2,
|
|
473
|
-
"
|
|
471
|
+
"processValidBlockProposal"
|
|
474
472
|
],
|
|
475
473
|
[
|
|
476
474
|
_dec3,
|
|
477
475
|
2,
|
|
478
|
-
"
|
|
476
|
+
"validateAndStoreCheckpointProposal"
|
|
479
477
|
],
|
|
480
478
|
[
|
|
481
479
|
_dec4,
|
|
482
480
|
2,
|
|
483
|
-
"
|
|
481
|
+
"processValidCheckpointProposal"
|
|
484
482
|
],
|
|
485
483
|
[
|
|
486
484
|
_dec5,
|
|
487
485
|
2,
|
|
488
|
-
"
|
|
486
|
+
"validateRequestedBlockTxs"
|
|
489
487
|
],
|
|
490
488
|
[
|
|
491
489
|
_dec6,
|
|
492
490
|
2,
|
|
493
|
-
"
|
|
491
|
+
"validateRequestedTxs"
|
|
494
492
|
],
|
|
495
493
|
[
|
|
496
494
|
_dec7,
|
|
497
495
|
2,
|
|
498
|
-
"
|
|
496
|
+
"validateRequestedBlock"
|
|
499
497
|
],
|
|
500
498
|
[
|
|
501
499
|
_dec8,
|
|
502
500
|
2,
|
|
503
|
-
"
|
|
501
|
+
"validatePropagatedTx"
|
|
502
|
+
],
|
|
503
|
+
[
|
|
504
|
+
_dec9,
|
|
505
|
+
2,
|
|
506
|
+
"validateCheckpointAttestation"
|
|
504
507
|
]
|
|
505
508
|
], []));
|
|
506
509
|
}
|
|
@@ -513,6 +516,7 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
513
516
|
protocolVersion;
|
|
514
517
|
topicStrings;
|
|
515
518
|
feesCache;
|
|
519
|
+
/** Callback invoked when a duplicate proposal is detected (triggers slashing). */ duplicateProposalCallback;
|
|
516
520
|
/**
|
|
517
521
|
* Callback for when a block is received from a peer.
|
|
518
522
|
* @param block - The block received from the peer.
|
|
@@ -776,7 +780,7 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
776
780
|
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this)
|
|
777
781
|
};
|
|
778
782
|
if (!this.config.disableTransactions) {
|
|
779
|
-
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
783
|
+
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.archiver, this.mempools.txPool);
|
|
780
784
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
781
785
|
}
|
|
782
786
|
if (!this.config.disableTransactions) {
|
|
@@ -876,6 +880,12 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
876
880
|
this.checkpointReceivedCallback = callback;
|
|
877
881
|
}
|
|
878
882
|
/**
|
|
883
|
+
* Registers a callback to be invoked when a duplicate proposal is detected.
|
|
884
|
+
* This callback is triggered on the first duplicate (when count goes from 1 to 2).
|
|
885
|
+
*/ registerDuplicateProposalCallback(callback) {
|
|
886
|
+
this.duplicateProposalCallback = callback;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
879
889
|
* Subscribes to a topic.
|
|
880
890
|
* @param topic - The topic to subscribe to.
|
|
881
891
|
*/ subscribeToTopic(topic) {
|
|
@@ -1102,114 +1112,159 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
1102
1112
|
* Process a checkpoint attestation from a peer.
|
|
1103
1113
|
* Validates the attestation and adds it to the pool.
|
|
1104
1114
|
*/ async processCheckpointAttestationFromPeer(payloadData, msgId, source) {
|
|
1105
|
-
const
|
|
1106
|
-
const attestation = CheckpointAttestation.fromBuffer(payloadData);
|
|
1107
|
-
const pool = this.mempools.attestationPool;
|
|
1108
|
-
const validationResult = await this.validateCheckpointAttestation(source, attestation);
|
|
1109
|
-
const isValid = validationResult.result === 'accept';
|
|
1110
|
-
const exists = isValid && await pool.hasCheckpointAttestation(attestation);
|
|
1111
|
-
let canAdd = true;
|
|
1112
|
-
if (isValid && !exists) {
|
|
1113
|
-
const slot = attestation.payload.header.slotNumber;
|
|
1114
|
-
const { committee } = await this.epochCache.getCommittee(slot);
|
|
1115
|
-
const committeeSize = committee?.length ?? 0;
|
|
1116
|
-
canAdd = await pool.canAddCheckpointAttestation(attestation, committeeSize);
|
|
1117
|
-
}
|
|
1118
|
-
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1119
|
-
isValid,
|
|
1120
|
-
exists,
|
|
1121
|
-
canAdd,
|
|
1122
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
1123
|
-
[Attributes.P2P_ID]: source.toString()
|
|
1124
|
-
});
|
|
1125
|
-
if (validationResult.result === 'reject') {
|
|
1126
|
-
return {
|
|
1127
|
-
result: TopicValidatorResult.Reject
|
|
1128
|
-
};
|
|
1129
|
-
} else if (validationResult.result === 'ignore' || exists) {
|
|
1130
|
-
return {
|
|
1131
|
-
result: TopicValidatorResult.Ignore,
|
|
1132
|
-
obj: attestation
|
|
1133
|
-
};
|
|
1134
|
-
} else if (!canAdd) {
|
|
1135
|
-
this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
|
|
1136
|
-
slot: attestation.payload.header.slotNumber.toString(),
|
|
1137
|
-
archive: attestation.archive.toString(),
|
|
1138
|
-
source: source.toString()
|
|
1139
|
-
});
|
|
1140
|
-
return {
|
|
1141
|
-
result: TopicValidatorResult.Ignore,
|
|
1142
|
-
obj: attestation
|
|
1143
|
-
};
|
|
1144
|
-
} else {
|
|
1145
|
-
return {
|
|
1146
|
-
result: TopicValidatorResult.Accept,
|
|
1147
|
-
obj: attestation
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
};
|
|
1151
|
-
const { result, obj: attestation } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.checkpoint_attestation);
|
|
1115
|
+
const { result, obj: attestation } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointAttestation(source, CheckpointAttestation.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_attestation);
|
|
1152
1116
|
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
1153
1117
|
return;
|
|
1154
1118
|
}
|
|
1155
|
-
this.logger.
|
|
1119
|
+
this.logger.verbose(`Received valid checkpoint attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`, {
|
|
1156
1120
|
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
1157
1121
|
slot: attestation.slotNumber,
|
|
1158
1122
|
archive: attestation.archive.toString(),
|
|
1159
1123
|
source: source.toString()
|
|
1160
1124
|
});
|
|
1161
|
-
await this.mempools.attestationPool.addCheckpointAttestations([
|
|
1162
|
-
attestation
|
|
1163
|
-
]);
|
|
1164
1125
|
}
|
|
1165
|
-
async
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1126
|
+
/** Validates a checkpoint attestation and adds it to the pool. Penalizes the peer if validation fails. */ async validateAndStoreCheckpointAttestation(peerId, attestation) {
|
|
1127
|
+
const validationResult = await this.checkpointAttestationValidator.validate(attestation);
|
|
1128
|
+
if (validationResult.result === 'reject') {
|
|
1129
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1130
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1131
|
+
return {
|
|
1132
|
+
result: TopicValidatorResult.Reject
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
if (validationResult.result === 'ignore') {
|
|
1136
|
+
return {
|
|
1137
|
+
result: TopicValidatorResult.Ignore,
|
|
1138
|
+
obj: attestation
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
// Get committee size for the attestation's slot
|
|
1142
|
+
const slot = attestation.payload.header.slotNumber;
|
|
1143
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
1144
|
+
const committeeSize = committee?.length ?? 0;
|
|
1145
|
+
// Try to add the attestation: this handles existence check, cap check, and adding in one call
|
|
1146
|
+
const { added, alreadyExists } = await this.mempools.attestationPool.tryAddCheckpointAttestation(attestation, committeeSize);
|
|
1147
|
+
this.logger.trace(`Validate propagated checkpoint attestation`, {
|
|
1148
|
+
added,
|
|
1149
|
+
alreadyExists,
|
|
1150
|
+
[Attributes.SLOT_NUMBER]: slot.toString(),
|
|
1151
|
+
[Attributes.P2P_ID]: peerId.toString()
|
|
1152
|
+
});
|
|
1153
|
+
// Duplicate attestation received, no need to re-broadcast
|
|
1154
|
+
if (alreadyExists) {
|
|
1155
|
+
return {
|
|
1156
|
+
result: TopicValidatorResult.Ignore,
|
|
1157
|
+
obj: attestation
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
// Could not add (cap reached), no need to re-broadcast
|
|
1161
|
+
if (!added) {
|
|
1162
|
+
this.logger.warn(`Dropping checkpoint attestation due to per-(slot, proposalId) attestation cap`, {
|
|
1163
|
+
slot: slot.toString(),
|
|
1164
|
+
archive: attestation.archive.toString(),
|
|
1165
|
+
source: peerId.toString()
|
|
1179
1166
|
});
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
} else if (!canAdd) {
|
|
1190
|
-
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
1191
|
-
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
1192
|
-
slot: block.slotNumber.toString(),
|
|
1193
|
-
archive: block.archive.toString(),
|
|
1194
|
-
source: source.toString()
|
|
1195
|
-
});
|
|
1196
|
-
return {
|
|
1197
|
-
result: TopicValidatorResult.Reject
|
|
1198
|
-
};
|
|
1199
|
-
} else {
|
|
1200
|
-
return {
|
|
1201
|
-
result: TopicValidatorResult.Accept,
|
|
1202
|
-
obj: block
|
|
1203
|
-
};
|
|
1204
|
-
}
|
|
1167
|
+
return {
|
|
1168
|
+
result: TopicValidatorResult.Ignore,
|
|
1169
|
+
obj: attestation
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
// Attestation was added successfully
|
|
1173
|
+
return {
|
|
1174
|
+
result: TopicValidatorResult.Accept,
|
|
1175
|
+
obj: attestation
|
|
1205
1176
|
};
|
|
1206
|
-
|
|
1207
|
-
|
|
1177
|
+
}
|
|
1178
|
+
async processBlockFromPeer(payloadData, msgId, source) {
|
|
1179
|
+
const { result, obj: block, metadata: { isEquivocated } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreBlockProposal(source, BlockProposal.fromBuffer(payloadData)), msgId, source, TopicType.block_proposal);
|
|
1180
|
+
// If not accepted or equivocated, return
|
|
1181
|
+
if (result !== TopicValidatorResult.Accept || !block || isEquivocated) {
|
|
1208
1182
|
return;
|
|
1209
1183
|
}
|
|
1210
1184
|
await this.processValidBlockProposal(block, source);
|
|
1211
1185
|
}
|
|
1212
|
-
|
|
1186
|
+
/** Validates a block proposal. Triggers a penalization to the peer that sent it if invalid. Adds to the mempool if valid. */ async validateAndStoreBlockProposal(peerId, block) {
|
|
1187
|
+
const validationResult = await this.blockProposalValidator.validate(block);
|
|
1188
|
+
if (validationResult.result === 'reject') {
|
|
1189
|
+
this.logger.warn(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1190
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1191
|
+
return {
|
|
1192
|
+
result: TopicValidatorResult.Reject
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
if (validationResult.result === 'ignore') {
|
|
1196
|
+
return {
|
|
1197
|
+
result: TopicValidatorResult.Ignore,
|
|
1198
|
+
obj: block
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
// Try to add the proposal: this handles existence check, cap check, and adding in one call
|
|
1202
|
+
const { added, alreadyExists, totalForPosition } = await this.mempools.attestationPool.tryAddBlockProposal(block);
|
|
1203
|
+
const isEquivocated = totalForPosition !== undefined && totalForPosition > 1;
|
|
1204
|
+
// Duplicate proposal received, no need to re-broadcast
|
|
1205
|
+
if (alreadyExists) {
|
|
1206
|
+
this.logger.debug(`Ignoring duplicate block proposal received`, {
|
|
1207
|
+
...block.toBlockInfo(),
|
|
1208
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1209
|
+
proposer: block.getSender()?.toString(),
|
|
1210
|
+
source: peerId.toString()
|
|
1211
|
+
});
|
|
1212
|
+
return {
|
|
1213
|
+
result: TopicValidatorResult.Ignore,
|
|
1214
|
+
obj: block,
|
|
1215
|
+
metadata: {
|
|
1216
|
+
isEquivocated
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
// Too many blocks received for this slot and index, penalize peer and do not re-broadcast
|
|
1221
|
+
if (!added) {
|
|
1222
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1223
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-position cap`, {
|
|
1224
|
+
...block.toBlockInfo(),
|
|
1225
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
1226
|
+
totalForPosition,
|
|
1227
|
+
proposer: block.getSender()?.toString(),
|
|
1228
|
+
source: peerId.toString()
|
|
1229
|
+
});
|
|
1230
|
+
return {
|
|
1231
|
+
result: TopicValidatorResult.Reject,
|
|
1232
|
+
metadata: {
|
|
1233
|
+
isEquivocated
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1238
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1239
|
+
if (isEquivocated) {
|
|
1240
|
+
const proposer = block.getSender();
|
|
1241
|
+
this.logger.warn(`Detected duplicate block proposal (equivocation) at slot ${block.slotNumber}`, {
|
|
1242
|
+
...block.toBlockInfo(),
|
|
1243
|
+
source: peerId.toString(),
|
|
1244
|
+
proposer: proposer?.toString()
|
|
1245
|
+
});
|
|
1246
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1247
|
+
if (proposer && totalForPosition === 2) {
|
|
1248
|
+
this.duplicateProposalCallback?.({
|
|
1249
|
+
slot: block.slotNumber,
|
|
1250
|
+
proposer,
|
|
1251
|
+
type: 'block'
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
return {
|
|
1255
|
+
result: TopicValidatorResult.Accept,
|
|
1256
|
+
obj: block,
|
|
1257
|
+
metadata: {
|
|
1258
|
+
isEquivocated
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
// Otherwise, we're good to go!
|
|
1263
|
+
return {
|
|
1264
|
+
result: TopicValidatorResult.Accept,
|
|
1265
|
+
obj: block
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1213
1268
|
// REFACTOR(palla): This method should be moved to the p2p_client or to a separate component,
|
|
1214
1269
|
// should not be here as it does not deal with p2p networking.
|
|
1215
1270
|
async processValidBlockProposal(block, sender) {
|
|
@@ -1219,21 +1274,6 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
1219
1274
|
source: sender.toString(),
|
|
1220
1275
|
...block.toBlockInfo()
|
|
1221
1276
|
});
|
|
1222
|
-
// Attempt to add proposal
|
|
1223
|
-
try {
|
|
1224
|
-
await this.mempools.attestationPool.addBlockProposal(block);
|
|
1225
|
-
} catch (err) {
|
|
1226
|
-
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
1227
|
-
if (err instanceof ProposalSlotCapExceededError) {
|
|
1228
|
-
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
1229
|
-
slot: String(slot),
|
|
1230
|
-
archive: block.archive.toString(),
|
|
1231
|
-
error: err.message
|
|
1232
|
-
});
|
|
1233
|
-
return;
|
|
1234
|
-
}
|
|
1235
|
-
throw err;
|
|
1236
|
-
}
|
|
1237
1277
|
// Mark the txs in this proposal as non-evictable
|
|
1238
1278
|
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
1239
1279
|
// Call the block received callback to validate the proposal.
|
|
@@ -1247,57 +1287,135 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
1247
1287
|
* Handle a gossiped checkpoint proposal.
|
|
1248
1288
|
* Validates and processes the checkpoint proposal, then triggers the callback for attestation.
|
|
1249
1289
|
*/ async handleGossipedCheckpointProposal(payloadData, msgId, source) {
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1290
|
+
const { result, obj: checkpoint, metadata: { isEquivocated, processBlock } = {} } = await this.validateReceivedMessage(()=>this.validateAndStoreCheckpointProposal(source, CheckpointProposal.fromBuffer(payloadData)), msgId, source, TopicType.checkpoint_proposal);
|
|
1291
|
+
// If the checkpoint contained a valid last block, we process it even if the checkpoint itself is to be rejected
|
|
1292
|
+
// TODO(palla/mbps): Is this ok? Should we be considering a block from a checkpoint that was equivocated?
|
|
1293
|
+
if (processBlock && checkpoint?.getBlockProposal()) {
|
|
1294
|
+
await this.processValidBlockProposal(checkpoint.getBlockProposal(), source);
|
|
1295
|
+
}
|
|
1296
|
+
if (result !== TopicValidatorResult.Accept || !checkpoint || isEquivocated) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
await this.processValidCheckpointProposal(checkpoint.toCore(), source);
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Validates a checkpoint proposal. Penalizes peer if validation fails. Adds the checkpoint and
|
|
1303
|
+
* its last block (if present) to the mempool if valid. Triggers equivocation detection on both.
|
|
1304
|
+
*/ async validateAndStoreCheckpointProposal(peerId, checkpoint) {
|
|
1305
|
+
const validationResult = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1306
|
+
if (validationResult.result === 'reject') {
|
|
1307
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1308
|
+
this.peerManager.penalizePeer(peerId, validationResult.severity);
|
|
1309
|
+
return {
|
|
1310
|
+
result: TopicValidatorResult.Reject
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
if (validationResult.result === 'ignore') {
|
|
1314
|
+
return {
|
|
1315
|
+
result: TopicValidatorResult.Ignore,
|
|
1316
|
+
obj: checkpoint
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
// Extract and try to add the block proposal first if present
|
|
1320
|
+
const blockProposal = checkpoint.getBlockProposal();
|
|
1321
|
+
let processBlock = false;
|
|
1322
|
+
if (blockProposal) {
|
|
1323
|
+
this.logger.debug(`Validating block proposal from propagated checkpoint`, {
|
|
1262
1324
|
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1263
|
-
[Attributes.P2P_ID]:
|
|
1325
|
+
[Attributes.P2P_ID]: peerId.toString()
|
|
1264
1326
|
});
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
result
|
|
1272
|
-
obj: checkpoint
|
|
1273
|
-
};
|
|
1274
|
-
} else if (!canAdd) {
|
|
1275
|
-
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
1276
|
-
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1277
|
-
slot: checkpoint.slotNumber.toString(),
|
|
1278
|
-
archive: checkpoint.archive.toString(),
|
|
1279
|
-
source: source.toString()
|
|
1327
|
+
const { result, obj, metadata: { isEquivocated } = {} } = await this.validateAndStoreBlockProposal(peerId, blockProposal);
|
|
1328
|
+
if (result === TopicValidatorResult.Reject || !obj || isEquivocated) {
|
|
1329
|
+
this.logger.debug(`Rejecting checkpoint due to invalid last block proposal`, {
|
|
1330
|
+
[Attributes.SLOT_NUMBER]: checkpoint.slotNumber.toString(),
|
|
1331
|
+
[Attributes.P2P_ID]: peerId.toString(),
|
|
1332
|
+
isEquivocated,
|
|
1333
|
+
result
|
|
1280
1334
|
});
|
|
1281
1335
|
return {
|
|
1282
1336
|
result: TopicValidatorResult.Reject
|
|
1283
1337
|
};
|
|
1284
|
-
} else {
|
|
1285
|
-
|
|
1286
|
-
result: TopicValidatorResult.Accept,
|
|
1287
|
-
obj: checkpoint
|
|
1288
|
-
};
|
|
1338
|
+
} else if (result === TopicValidatorResult.Accept && obj && !isEquivocated) {
|
|
1339
|
+
processBlock = true;
|
|
1289
1340
|
}
|
|
1290
|
-
};
|
|
1291
|
-
const { result, obj: checkpoint } = await this.validateReceivedMessage(validationFunc, msgId, source, TopicType.checkpoint_proposal);
|
|
1292
|
-
if (result !== TopicValidatorResult.Accept || !checkpoint) {
|
|
1293
|
-
return;
|
|
1294
1341
|
}
|
|
1295
|
-
|
|
1342
|
+
// Try to add the checkpoint proposal core: this handles existence check, cap check, and adding in one call
|
|
1343
|
+
const checkpointCore = checkpoint.toCore();
|
|
1344
|
+
const tryAddResult = await this.mempools.attestationPool.tryAddCheckpointProposal(checkpointCore);
|
|
1345
|
+
const { added, alreadyExists, totalForPosition } = tryAddResult;
|
|
1346
|
+
const isEquivocated = totalForPosition !== undefined && totalForPosition > 1;
|
|
1347
|
+
// Duplicate proposal received, do not re-broadcast
|
|
1348
|
+
if (alreadyExists) {
|
|
1349
|
+
this.logger.debug(`Ignoring duplicate checkpoint proposal received`, {
|
|
1350
|
+
...checkpoint.toCheckpointInfo(),
|
|
1351
|
+
source: peerId.toString()
|
|
1352
|
+
});
|
|
1353
|
+
return {
|
|
1354
|
+
result: TopicValidatorResult.Ignore,
|
|
1355
|
+
obj: checkpoint,
|
|
1356
|
+
metadata: {
|
|
1357
|
+
isEquivocated,
|
|
1358
|
+
processBlock
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
// Too many checkpoint proposals received for this slot, penalize peer and do not re-broadcast
|
|
1363
|
+
// Note: We still return the checkpoint obj so the lastBlock can be processed if valid
|
|
1364
|
+
if (!added) {
|
|
1365
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
|
|
1366
|
+
this.logger.warn(`Penalizing peer for checkpoint proposal exceeding per-slot cap`, {
|
|
1367
|
+
...checkpoint.toCheckpointInfo(),
|
|
1368
|
+
totalForPosition,
|
|
1369
|
+
source: peerId.toString()
|
|
1370
|
+
});
|
|
1371
|
+
return {
|
|
1372
|
+
result: TopicValidatorResult.Reject,
|
|
1373
|
+
obj: checkpoint,
|
|
1374
|
+
metadata: {
|
|
1375
|
+
isEquivocated,
|
|
1376
|
+
processBlock
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
// If this was a duplicate proposal, do not process it, but do invoke the duplicate callback,
|
|
1381
|
+
// and do re-broadcast it so other nodes in the network know to slash the proposer
|
|
1382
|
+
if (isEquivocated) {
|
|
1383
|
+
const proposer = checkpoint.getSender();
|
|
1384
|
+
this.logger.warn(`Detected duplicate checkpoint proposal (equivocation) at slot ${checkpoint.slotNumber}`, {
|
|
1385
|
+
...checkpoint.toCheckpointInfo(),
|
|
1386
|
+
source: peerId.toString(),
|
|
1387
|
+
proposer: proposer?.toString()
|
|
1388
|
+
});
|
|
1389
|
+
// Invoke the duplicate callback on the first duplicate spotted only
|
|
1390
|
+
if (proposer && totalForPosition === 2) {
|
|
1391
|
+
this.duplicateProposalCallback?.({
|
|
1392
|
+
slot: checkpoint.slotNumber,
|
|
1393
|
+
proposer,
|
|
1394
|
+
type: 'checkpoint'
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
result: TopicValidatorResult.Accept,
|
|
1399
|
+
obj: checkpoint,
|
|
1400
|
+
metadata: {
|
|
1401
|
+
isEquivocated,
|
|
1402
|
+
processBlock
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
// Otherwise, we're good to go!
|
|
1407
|
+
return {
|
|
1408
|
+
result: TopicValidatorResult.Accept,
|
|
1409
|
+
obj: checkpoint,
|
|
1410
|
+
metadata: {
|
|
1411
|
+
processBlock,
|
|
1412
|
+
isEquivocated
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1296
1415
|
}
|
|
1297
1416
|
/**
|
|
1298
1417
|
* Process a validated checkpoint proposal.
|
|
1299
|
-
*
|
|
1300
|
-
* The block callback is invoked before the checkpoint callback.
|
|
1418
|
+
* Note: The proposal was already added to the pool by tryAddCheckpointProposal in handleGossipedCheckpointProposal.
|
|
1301
1419
|
*/ async processValidCheckpointProposal(checkpoint, sender) {
|
|
1302
1420
|
const slot = checkpoint.slotNumber;
|
|
1303
1421
|
this.logger.verbose(`Received checkpoint proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
@@ -1306,33 +1424,12 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
1306
1424
|
archive: checkpoint.archive.toString(),
|
|
1307
1425
|
source: sender.toString()
|
|
1308
1426
|
});
|
|
1309
|
-
// Extract block proposal before adding to pool (pool stores them separately)
|
|
1310
|
-
const blockProposal = checkpoint.getBlockProposal();
|
|
1311
|
-
// Add proposal to the pool (this extracts and stores block proposal separately)
|
|
1312
|
-
await this.mempools.attestationPool.addCheckpointProposal(checkpoint);
|
|
1313
|
-
// Mark txs as non-evictable if present (from the last block)
|
|
1314
|
-
if (checkpoint.txHashes.length > 0) {
|
|
1315
|
-
await this.mempools.txPool.markTxsAsNonEvictable(checkpoint.txHashes);
|
|
1316
|
-
}
|
|
1317
|
-
// If there was a last block proposal, invoke the block callback first for validation.
|
|
1318
|
-
// Note: The block proposal is already stored in the pool by addCheckpointProposal.
|
|
1319
|
-
if (blockProposal) {
|
|
1320
|
-
const isValid = await this.blockReceivedCallback(blockProposal, sender);
|
|
1321
|
-
if (!isValid) {
|
|
1322
|
-
this.logger.warn(`Block proposal from checkpoint failed validation`, {
|
|
1323
|
-
slot: slot.toString(),
|
|
1324
|
-
archive: checkpoint.archive.toString(),
|
|
1325
|
-
blockNumber: blockProposal.blockNumber.toString()
|
|
1326
|
-
});
|
|
1327
|
-
return;
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
1427
|
// Call the checkpoint received callback with the core version (without lastBlock)
|
|
1331
1428
|
// to validate and potentially generate attestations
|
|
1332
|
-
const attestations = await this.checkpointReceivedCallback(checkpoint
|
|
1429
|
+
const attestations = await this.checkpointReceivedCallback(checkpoint, sender);
|
|
1333
1430
|
if (attestations && attestations.length > 0) {
|
|
1334
1431
|
// If the callback returned attestations, add them to the pool and propagate them
|
|
1335
|
-
await this.mempools.attestationPool.
|
|
1432
|
+
await this.mempools.attestationPool.addOwnCheckpointAttestations(attestations);
|
|
1336
1433
|
for (const attestation of attestations){
|
|
1337
1434
|
await this.propagate(attestation);
|
|
1338
1435
|
}
|
|
@@ -1659,33 +1756,7 @@ _dec = trackSpan('Libp2pService.processValidBlockProposal', async (block)=>({
|
|
|
1659
1756
|
*/ async validateCheckpointAttestation(peerId, attestation) {
|
|
1660
1757
|
const result = await this.checkpointAttestationValidator.validate(attestation);
|
|
1661
1758
|
if (result.result === 'reject') {
|
|
1662
|
-
this.logger.
|
|
1663
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1664
|
-
}
|
|
1665
|
-
return result;
|
|
1666
|
-
}
|
|
1667
|
-
/**
|
|
1668
|
-
* Validate a block proposal.
|
|
1669
|
-
*
|
|
1670
|
-
* @param block - The block proposal to validate.
|
|
1671
|
-
* @returns True if the block proposal is valid, false otherwise.
|
|
1672
|
-
*/ async validateBlockProposal(peerId, block) {
|
|
1673
|
-
const result = await this.blockProposalValidator.validate(block);
|
|
1674
|
-
if (result.result === 'reject') {
|
|
1675
|
-
this.logger.debug(`Penalizing peer ${peerId} for block proposal validation failure`);
|
|
1676
|
-
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1677
|
-
}
|
|
1678
|
-
return result;
|
|
1679
|
-
}
|
|
1680
|
-
/**
|
|
1681
|
-
* Validate a checkpoint proposal.
|
|
1682
|
-
*
|
|
1683
|
-
* @param checkpoint - The checkpoint proposal to validate.
|
|
1684
|
-
* @returns True if the checkpoint proposal is valid, false otherwise.
|
|
1685
|
-
*/ async validateCheckpointProposal(peerId, checkpoint) {
|
|
1686
|
-
const result = await this.checkpointProposalValidator.validate(checkpoint);
|
|
1687
|
-
if (result.result === 'reject') {
|
|
1688
|
-
this.logger.debug(`Penalizing peer ${peerId} for checkpoint proposal validation failure`);
|
|
1759
|
+
this.logger.warn(`Penalizing peer ${peerId} for checkpoint attestation validation failure`);
|
|
1689
1760
|
this.peerManager.penalizePeer(peerId, result.severity);
|
|
1690
1761
|
}
|
|
1691
1762
|
return result;
|