@aztec/p2p 3.0.0-canary.a9708bd → 3.0.0-devnet.2-patch.1
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/bootstrap/bootstrap.d.ts +1 -1
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +14 -4
- package/dest/client/factory.d.ts +2 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +8 -3
- package/dest/client/index.d.ts +1 -1
- package/dest/client/interface.d.ts +8 -6
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +11 -34
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +68 -46
- package/dest/config.d.ts +65 -56
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +21 -5
- package/dest/enr/generate-enr.d.ts +2 -2
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +1 -1
- package/dest/enr/index.d.ts +1 -1
- package/dest/errors/attestation-pool.error.d.ts +7 -0
- package/dest/errors/attestation-pool.error.d.ts.map +1 -0
- package/dest/errors/attestation-pool.error.js +12 -0
- package/dest/errors/reqresp.error.d.ts +1 -1
- package/dest/errors/reqresp.error.d.ts.map +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +43 -6
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- 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 +72 -46
- package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +15 -6
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +73 -18
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +13 -6
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +69 -11
- package/dest/mem_pools/attestation_pool/mocks.d.ts +226 -5
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +9 -7
- package/dest/mem_pools/index.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts +3 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +11 -2
- package/dest/mem_pools/interface.d.ts +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +17 -40
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +103 -44
- package/dest/mem_pools/tx_pool/index.d.ts +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +19 -6
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +88 -9
- package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +21 -6
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +132 -7
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +32 -5
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +67 -0
- package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
- package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/index.js +1 -0
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +56 -9
- package/dest/msg_validators/block_proposal_validator/index.d.ts +1 -1
- package/dest/msg_validators/index.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
- package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- 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/double_spend_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +11 -5
- 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/index.d.ts +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -6
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +6 -24
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
- package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +13 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.d.ts +3 -3
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +2 -2
- package/dest/services/dummy_service.d.ts +2 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/encoding.d.ts +25 -4
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +74 -6
- package/dest/services/gossipsub/scoring.d.ts +1 -1
- package/dest/services/index.d.ts +1 -1
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +9 -2
- package/dest/services/libp2p/libp2p_service.d.ts +29 -69
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +375 -133
- package/dest/services/peer-manager/interface.d.ts +1 -1
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +11 -0
- package/dest/services/peer-manager/peer_manager.d.ts +1 -32
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +27 -12
- 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 +40 -2
- package/dest/services/reqresp/config.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/index.d.ts +1 -1
- package/dest/services/reqresp/interface.d.ts +2 -11
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +1 -18
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.d.ts +2 -2
- package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/auth.js +2 -2
- package/dest/services/reqresp/protocols/block.d.ts +1 -1
- package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block.js +3 -2
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
- 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 +1 -1
- package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +6 -5
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +4 -3
- package/dest/services/reqresp/protocols/tx.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts +1 -41
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +14 -10
- package/dest/services/reqresp/status.d.ts +2 -2
- package/dest/services/reqresp/status.d.ts.map +1 -1
- package/dest/services/service.d.ts +2 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +6 -1
- package/dest/services/tx_collection/index.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -7
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +2 -1
- package/dest/services/tx_collection/tx_collection.d.ts +12 -11
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +3 -2
- package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +34 -4
- package/dest/services/tx_collection/tx_source.d.ts +1 -1
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +2 -2
- package/dest/services/tx_provider.d.ts +5 -4
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +8 -4
- package/dest/services/tx_provider_instrumentation.d.ts +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/index.d.ts +1 -1
- package/dest/test-helpers/make-enrs.d.ts +1 -1
- package/dest/test-helpers/make-enrs.js +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +4 -4
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
- package/dest/test-helpers/mock-tx-helpers.js +19 -0
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -2
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -3
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +16 -9
- package/dest/testbench/parse_log_file.d.ts +1 -1
- package/dest/testbench/testbench.d.ts +1 -1
- package/dest/testbench/testbench.js +2 -2
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/types/index.d.ts +1 -1
- package/dest/util.d.ts +2 -1
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +11 -2
- package/dest/versioning.d.ts +2 -2
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +2 -2
- package/package.json +21 -21
- package/src/bootstrap/bootstrap.ts +15 -4
- package/src/client/factory.ts +17 -3
- package/src/client/interface.ts +8 -5
- package/src/client/p2p_client.ts +88 -74
- package/src/config.ts +33 -6
- package/src/enr/generate-enr.ts +1 -1
- package/src/errors/attestation-pool.error.ts +13 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +46 -5
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +89 -48
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +107 -24
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +98 -19
- package/src/mem_pools/attestation_pool/mocks.ts +11 -8
- package/src/mem_pools/instrumentation.ts +13 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +116 -48
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +98 -12
- package/src/mem_pools/tx_pool/tx_pool.ts +20 -5
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +115 -7
- package/src/msg_validators/attestation_validator/attestation_validator.ts +41 -6
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
- package/src/msg_validators/attestation_validator/index.ts +1 -0
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +63 -18
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
- package/src/msg_validators/tx_validator/double_spend_validator.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +13 -6
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +8 -42
- package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
- package/src/msg_validators/tx_validator/test_utils.ts +1 -1
- package/src/msg_validators/tx_validator/timestamp_validator.ts +47 -0
- package/src/services/discv5/discV5_service.ts +2 -2
- package/src/services/dummy_service.ts +1 -1
- package/src/services/encoding.ts +81 -6
- package/src/services/libp2p/instrumentation.ts +10 -1
- package/src/services/libp2p/libp2p_service.ts +427 -157
- package/src/services/peer-manager/metrics.ts +10 -0
- package/src/services/peer-manager/peer_manager.ts +22 -14
- package/src/services/peer-manager/peer_scoring.ts +46 -3
- package/src/services/reqresp/interface.ts +1 -22
- package/src/services/reqresp/protocols/auth.ts +2 -2
- package/src/services/reqresp/protocols/block.ts +3 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
- package/src/services/reqresp/protocols/status.ts +9 -8
- package/src/services/reqresp/reqresp.ts +15 -11
- package/src/services/service.ts +1 -1
- package/src/services/tx_collection/fast_tx_collection.ts +8 -5
- package/src/services/tx_collection/slow_tx_collection.ts +7 -6
- package/src/services/tx_collection/tx_collection.ts +12 -10
- package/src/services/tx_collection/tx_collection_sink.ts +34 -3
- package/src/services/tx_collection/tx_source.ts +2 -2
- package/src/services/tx_provider.ts +9 -7
- package/src/test-helpers/make-enrs.ts +1 -1
- package/src/test-helpers/mock-tx-helpers.ts +24 -0
- package/src/test-helpers/reqresp-nodes.ts +3 -2
- package/src/testbench/p2p_client_testbench_worker.ts +12 -5
- package/src/testbench/testbench.ts +2 -2
- package/src/util.ts +12 -2
- package/src/versioning.ts +3 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
2
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
5
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
5
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
7
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
8
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
9
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
|
+
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
|
+
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
12
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
11
13
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
12
14
|
import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
@@ -23,12 +25,11 @@ import {
|
|
|
23
25
|
metricsTopicStrToLabels,
|
|
24
26
|
} from '@aztec/stdlib/p2p';
|
|
25
27
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
26
|
-
import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
|
|
28
|
+
import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
27
29
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
28
30
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
29
31
|
import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
30
32
|
|
|
31
|
-
import { ENR } from '@chainsafe/enr';
|
|
32
33
|
import {
|
|
33
34
|
type GossipSub,
|
|
34
35
|
type GossipSubComponents,
|
|
@@ -43,18 +44,29 @@ import { bootstrap } from '@libp2p/bootstrap';
|
|
|
43
44
|
import { identify } from '@libp2p/identify';
|
|
44
45
|
import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResult } from '@libp2p/interface';
|
|
45
46
|
import type { ConnectionManager } from '@libp2p/interface-internal';
|
|
46
|
-
import '@libp2p/kad-dht';
|
|
47
47
|
import { mplex } from '@libp2p/mplex';
|
|
48
48
|
import { tcp } from '@libp2p/tcp';
|
|
49
|
+
import { ENR } from '@nethermindeth/enr';
|
|
49
50
|
import { createLibp2p } from 'libp2p';
|
|
50
51
|
|
|
51
52
|
import type { P2PConfig } from '../../config.js';
|
|
53
|
+
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
52
54
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
53
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
AttestationValidator,
|
|
57
|
+
BlockProposalValidator,
|
|
58
|
+
FishermanAttestationValidator,
|
|
59
|
+
} from '../../msg_validators/index.js';
|
|
54
60
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
55
61
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
56
62
|
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
57
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
AggregateTxValidator,
|
|
65
|
+
DataTxValidator,
|
|
66
|
+
DoubleSpendTxValidator,
|
|
67
|
+
MetadataTxValidator,
|
|
68
|
+
TxProofValidator,
|
|
69
|
+
} from '../../msg_validators/tx_validator/index.js';
|
|
58
70
|
import { GossipSubEvent } from '../../types/index.js';
|
|
59
71
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
60
72
|
import { getVersions } from '../../versioning.js';
|
|
@@ -80,6 +92,8 @@ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs
|
|
|
80
92
|
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
|
|
81
93
|
import {
|
|
82
94
|
AuthRequest,
|
|
95
|
+
BlockTxsRequest,
|
|
96
|
+
BlockTxsResponse,
|
|
83
97
|
StatusMessage,
|
|
84
98
|
pingHandler,
|
|
85
99
|
reqRespBlockHandler,
|
|
@@ -98,11 +112,15 @@ interface ValidationResult {
|
|
|
98
112
|
|
|
99
113
|
type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
|
|
100
114
|
|
|
115
|
+
// REFACTOR: Unify with the type above
|
|
116
|
+
type ReceivedMessageValidationResult<T> =
|
|
117
|
+
| { obj: T; result: Exclude<TopicValidatorResult, TopicValidatorResult.Reject> }
|
|
118
|
+
| { obj?: undefined; result: TopicValidatorResult.Reject };
|
|
119
|
+
|
|
101
120
|
/**
|
|
102
121
|
* Lib P2P implementation of the P2PService interface.
|
|
103
122
|
*/
|
|
104
123
|
export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends WithTracer implements P2PService {
|
|
105
|
-
private jobQueue: SerialQueue = new SerialQueue();
|
|
106
124
|
private discoveryRunningPromise?: RunningPromise;
|
|
107
125
|
private msgIdSeenValidators: Record<TopicType, MessageSeenValidator> = {} as Record<TopicType, MessageSeenValidator>;
|
|
108
126
|
|
|
@@ -113,7 +131,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
113
131
|
private protocolVersion = '';
|
|
114
132
|
private topicStrings: Record<TopicType, string> = {} as Record<TopicType, string>;
|
|
115
133
|
|
|
116
|
-
private feesCache: { blockNumber:
|
|
134
|
+
private feesCache: { blockNumber: BlockNumber; gasFees: GasFees } | undefined;
|
|
117
135
|
|
|
118
136
|
/**
|
|
119
137
|
* Callback for when a block is received from a peer.
|
|
@@ -126,6 +144,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
126
144
|
|
|
127
145
|
private instrumentation: P2PInstrumentation;
|
|
128
146
|
|
|
147
|
+
protected logger: Logger;
|
|
148
|
+
|
|
129
149
|
constructor(
|
|
130
150
|
private clientType: T,
|
|
131
151
|
private config: P2PConfig,
|
|
@@ -139,10 +159,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
139
159
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
140
160
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
141
161
|
telemetry: TelemetryClient,
|
|
142
|
-
|
|
162
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
143
163
|
) {
|
|
144
164
|
super(telemetry, 'LibP2PService');
|
|
145
165
|
|
|
166
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
167
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
168
|
+
|
|
146
169
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
147
170
|
|
|
148
171
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
@@ -160,15 +183,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
160
183
|
this.protocolVersion,
|
|
161
184
|
);
|
|
162
185
|
|
|
163
|
-
|
|
164
|
-
this.
|
|
186
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
187
|
+
this.attestationValidator = config.fishermanMode
|
|
188
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool!, telemetry)
|
|
189
|
+
: new AttestationValidator(epochCache);
|
|
190
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
165
191
|
|
|
166
192
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
167
193
|
|
|
168
194
|
this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation[] | undefined> => {
|
|
169
195
|
this.logger.debug(
|
|
170
|
-
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber
|
|
171
|
-
{ p2pMessageIdentifier: await block.
|
|
196
|
+
`Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
|
|
197
|
+
{ p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
|
|
172
198
|
);
|
|
173
199
|
return undefined;
|
|
174
200
|
};
|
|
@@ -273,7 +299,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
273
299
|
// The connection attempts to the node on TCP layer are not necessarily valid Aztec peers so we want to have a bit of leeway here
|
|
274
300
|
// If we hit the limit, the connection will be temporarily accepted and immediately dropped.
|
|
275
301
|
// Docs: https://nodejs.org/api/net.html#servermaxconnections
|
|
276
|
-
maxConnections:
|
|
302
|
+
maxConnections: maxPeerCount * 2,
|
|
277
303
|
// socket option: the maximum length of the queue of pending connections
|
|
278
304
|
// https://nodejs.org/dist/latest-v22.x/docs/api/net.html#serverlisten
|
|
279
305
|
// it's not safe if we increase this number
|
|
@@ -284,7 +310,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
284
310
|
// In case closeAbove is reached, the server stops listening altogether
|
|
285
311
|
// It's important that there is enough difference between closeAbove and listenAbove,
|
|
286
312
|
// otherwise the server.listener will flap between being closed and open potentially degrading perf even more
|
|
287
|
-
closeAbove: maxPeerCount *
|
|
313
|
+
closeAbove: maxPeerCount * 3,
|
|
288
314
|
listenBelow: Math.floor(maxPeerCount * 0.9),
|
|
289
315
|
},
|
|
290
316
|
}),
|
|
@@ -294,8 +320,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
294
320
|
streamMuxers: [yamux(), mplex()],
|
|
295
321
|
connectionEncryption: [noise()],
|
|
296
322
|
connectionManager: {
|
|
297
|
-
minConnections: 0,
|
|
298
|
-
maxConnections
|
|
323
|
+
minConnections: 0, // Disable libp2p peer dialing, we do it manually
|
|
324
|
+
// We set maxConnections above maxPeerCount because if we hit limit of maxPeerCount
|
|
325
|
+
// libp2p will start aggressively rejecting all new connections, preventing network discovery and crawling.
|
|
326
|
+
maxConnections: maxPeerCount * 2,
|
|
299
327
|
maxParallelDials: 100,
|
|
300
328
|
dialTimeout: 30_000,
|
|
301
329
|
maxPeerAddrsToDial: 5,
|
|
@@ -379,7 +407,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
379
407
|
logger: createLibp2pComponentLogger(logger.module),
|
|
380
408
|
});
|
|
381
409
|
|
|
382
|
-
const peerScoring = new PeerScoring(config);
|
|
410
|
+
const peerScoring = new PeerScoring(config, telemetry);
|
|
383
411
|
const reqresp = new ReqResp(config, node, peerScoring, createLogger(`${logger.module}:reqresp`));
|
|
384
412
|
|
|
385
413
|
const peerManager = new PeerManager(
|
|
@@ -434,9 +462,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
434
462
|
}
|
|
435
463
|
const announceTcpMultiaddr = convertToMultiaddr(p2pIp, p2pPort, 'tcp');
|
|
436
464
|
|
|
437
|
-
// Start job queue, peer discovery service and libp2p node
|
|
438
|
-
this.jobQueue.start();
|
|
439
|
-
|
|
440
465
|
await this.peerManager.initializePeers();
|
|
441
466
|
if (!this.config.p2pDiscoveryDisabled) {
|
|
442
467
|
await this.peerDiscoveryService.start();
|
|
@@ -453,10 +478,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
453
478
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
454
479
|
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
455
480
|
const statusHandler = reqRespStatusHandler(this.protocolVersion, this.worldStateSynchronizer, this.logger);
|
|
456
|
-
// In case P2P client doesnt'have attestation pool,
|
|
457
|
-
// const blockTxsHandler = this.mempools.attestationPool
|
|
458
|
-
// ? reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool)
|
|
459
|
-
// : def;
|
|
460
481
|
|
|
461
482
|
const requestResponseHandlers: Partial<ReqRespSubProtocolHandlers> = {
|
|
462
483
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
@@ -466,7 +487,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
466
487
|
};
|
|
467
488
|
|
|
468
489
|
// Only handle block transactions request if attestation pool is available to the client
|
|
469
|
-
if (this.mempools.attestationPool) {
|
|
490
|
+
if (this.mempools.attestationPool && !this.config.disableTransactions) {
|
|
470
491
|
const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
|
|
471
492
|
requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
|
|
472
493
|
}
|
|
@@ -478,9 +499,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
478
499
|
// add GossipSub listener
|
|
479
500
|
this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.gossipSubEventHandler);
|
|
480
501
|
|
|
481
|
-
// Start running promise for peer discovery
|
|
502
|
+
// Start running promise for peer discovery and metrics collection
|
|
482
503
|
this.discoveryRunningPromise = new RunningPromise(
|
|
483
|
-
() =>
|
|
504
|
+
async () => {
|
|
505
|
+
await this.peerManager.heartbeat();
|
|
506
|
+
},
|
|
484
507
|
this.logger,
|
|
485
508
|
this.config.peerCheckIntervalMS,
|
|
486
509
|
);
|
|
@@ -489,8 +512,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
489
512
|
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
|
|
490
513
|
const reqrespSubProtocolValidators = {
|
|
491
514
|
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
492
|
-
|
|
493
|
-
[ReqRespSubProtocol.
|
|
515
|
+
[ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
|
|
516
|
+
[ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
|
|
517
|
+
[ReqRespSubProtocol.BLOCK]: this.validateRequestedBlock.bind(this),
|
|
494
518
|
};
|
|
495
519
|
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
|
|
496
520
|
this.logger.info(`Started P2P service`, {
|
|
@@ -512,9 +536,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
512
536
|
// Stop peer manager
|
|
513
537
|
this.logger.debug('Stopping peer manager...');
|
|
514
538
|
await this.peerManager.stop();
|
|
515
|
-
|
|
516
|
-
this.logger.debug('Stopping job queue...');
|
|
517
|
-
await this.jobQueue.end();
|
|
518
539
|
this.logger.debug('Stopping running promise...');
|
|
519
540
|
await this.discoveryRunningPromise?.stop();
|
|
520
541
|
this.logger.debug('Stopping peer discovery service...');
|
|
@@ -602,16 +623,16 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
602
623
|
if (!this.node.services.pubsub) {
|
|
603
624
|
throw new Error('Pubsub service not available.');
|
|
604
625
|
}
|
|
605
|
-
const p2pMessage =
|
|
606
|
-
this.logger.debug(`Publishing message`, {
|
|
607
|
-
topic,
|
|
608
|
-
messageId: p2pMessage.id,
|
|
609
|
-
});
|
|
626
|
+
const p2pMessage = P2PMessage.fromGossipable(message, this.config.debugP2PInstrumentMessages);
|
|
610
627
|
const result = await this.node.services.pubsub.publish(topic, p2pMessage.toMessageData());
|
|
611
|
-
|
|
612
628
|
return result.recipients.length;
|
|
613
629
|
}
|
|
614
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Checks if this message has already been seen, based on its msgId computed from hashing the message data.
|
|
633
|
+
* Note that we do not rely on the seenCache from gossipsub since we want to keep a longer history of seen
|
|
634
|
+
* messages to avoid tx echoes across the network.
|
|
635
|
+
*/
|
|
615
636
|
protected preValidateReceivedMessage(
|
|
616
637
|
msg: Message,
|
|
617
638
|
msgId: string,
|
|
@@ -647,82 +668,122 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
647
668
|
return { result: true, topicType };
|
|
648
669
|
}
|
|
649
670
|
|
|
671
|
+
/**
|
|
672
|
+
* Safely deserializes a P2PMessage from raw message data.
|
|
673
|
+
* @param msgId - The message ID.
|
|
674
|
+
* @param source - The peer ID of the message source.
|
|
675
|
+
* @param data - The raw message data.
|
|
676
|
+
* @returns The deserialized P2PMessage or undefined if deserialization fails.
|
|
677
|
+
*/
|
|
678
|
+
private safelyDeserializeP2PMessage(msgId: string, source: PeerId, data: Uint8Array): P2PMessage | undefined {
|
|
679
|
+
try {
|
|
680
|
+
return P2PMessage.fromMessageData(Buffer.from(data), this.config.debugP2PInstrumentMessages);
|
|
681
|
+
} catch (err) {
|
|
682
|
+
this.logger.error(`Error deserializing P2PMessage`, err, {
|
|
683
|
+
msgId,
|
|
684
|
+
source: source.toString(),
|
|
685
|
+
});
|
|
686
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), TopicValidatorResult.Reject);
|
|
687
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
688
|
+
return undefined;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
650
692
|
/**
|
|
651
693
|
* Handles a new gossip message that was received by the client.
|
|
652
694
|
* @param topic - The message's topic.
|
|
653
695
|
* @param data - The message data
|
|
654
696
|
*/
|
|
655
697
|
protected async handleNewGossipMessage(msg: Message, msgId: string, source: PeerId) {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
messageLatency,
|
|
663
|
-
});
|
|
698
|
+
const msgReceivedTime = Date.now();
|
|
699
|
+
let topicType: TopicType | undefined;
|
|
700
|
+
const p2pMessage = this.safelyDeserializeP2PMessage(msgId, source, msg.data);
|
|
701
|
+
if (!p2pMessage) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
664
704
|
|
|
665
705
|
const preValidationResult = this.preValidateReceivedMessage(msg, msgId, source);
|
|
666
706
|
|
|
667
707
|
if (!preValidationResult.result) {
|
|
668
708
|
return;
|
|
669
|
-
} else if (preValidationResult.topicType !== undefined) {
|
|
670
|
-
// guard against clock skew & DST
|
|
671
|
-
if (messageLatency > 0) {
|
|
672
|
-
this.instrumentation.recordMessageLatency(preValidationResult.topicType, messageLatency);
|
|
673
|
-
}
|
|
674
709
|
}
|
|
675
710
|
|
|
676
711
|
if (msg.topic === this.topicStrings[TopicType.tx]) {
|
|
712
|
+
topicType = TopicType.tx;
|
|
677
713
|
await this.handleGossipedTx(p2pMessage.payload, msgId, source);
|
|
678
714
|
}
|
|
679
|
-
if (msg.topic === this.topicStrings[TopicType.block_attestation]
|
|
680
|
-
|
|
715
|
+
if (msg.topic === this.topicStrings[TopicType.block_attestation]) {
|
|
716
|
+
topicType = TopicType.block_attestation;
|
|
717
|
+
if (this.clientType === P2PClientType.Full) {
|
|
718
|
+
await this.processAttestationFromPeer(p2pMessage.payload, msgId, source);
|
|
719
|
+
}
|
|
681
720
|
}
|
|
682
721
|
if (msg.topic === this.topicStrings[TopicType.block_proposal]) {
|
|
722
|
+
topicType = TopicType.block_proposal;
|
|
683
723
|
await this.processBlockFromPeer(p2pMessage.payload, msgId, source);
|
|
684
724
|
}
|
|
685
725
|
|
|
726
|
+
if (p2pMessage.timestamp !== undefined && topicType !== undefined) {
|
|
727
|
+
const latency = msgReceivedTime - p2pMessage.timestamp.getTime();
|
|
728
|
+
this.instrumentation.recordMessageLatency(topicType, latency);
|
|
729
|
+
}
|
|
730
|
+
|
|
686
731
|
return;
|
|
687
732
|
}
|
|
688
733
|
|
|
689
734
|
protected async validateReceivedMessage<T>(
|
|
690
|
-
validationFunc: () => Promise<
|
|
735
|
+
validationFunc: () => Promise<ReceivedMessageValidationResult<T>>,
|
|
691
736
|
msgId: string,
|
|
692
737
|
source: PeerId,
|
|
693
738
|
topicType: TopicType,
|
|
694
|
-
): Promise<
|
|
695
|
-
let resultAndObj:
|
|
739
|
+
): Promise<ReceivedMessageValidationResult<T>> {
|
|
740
|
+
let resultAndObj: ReceivedMessageValidationResult<T> = { result: TopicValidatorResult.Reject };
|
|
696
741
|
const timer = new Timer();
|
|
697
742
|
try {
|
|
698
743
|
resultAndObj = await validationFunc();
|
|
699
744
|
} catch (err) {
|
|
700
|
-
this.
|
|
745
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.LowToleranceError);
|
|
746
|
+
this.logger.error(`Error deserializing and validating gossipsub message`, err, {
|
|
747
|
+
msgId,
|
|
748
|
+
source: source.toString(),
|
|
749
|
+
topicType,
|
|
750
|
+
});
|
|
701
751
|
}
|
|
702
752
|
|
|
703
|
-
if (resultAndObj.result) {
|
|
753
|
+
if (resultAndObj.result === TopicValidatorResult.Accept) {
|
|
704
754
|
this.instrumentation.recordMessageValidation(topicType, timer);
|
|
705
755
|
}
|
|
706
756
|
|
|
707
|
-
this.node.services.pubsub.reportMessageValidationResult(
|
|
708
|
-
msgId,
|
|
709
|
-
source.toString(),
|
|
710
|
-
resultAndObj.result && resultAndObj.obj ? TopicValidatorResult.Accept : TopicValidatorResult.Reject,
|
|
711
|
-
);
|
|
757
|
+
this.node.services.pubsub.reportMessageValidationResult(msgId, source.toString(), resultAndObj.result);
|
|
712
758
|
return resultAndObj;
|
|
713
759
|
}
|
|
714
760
|
|
|
715
761
|
protected async handleGossipedTx(payloadData: Buffer, msgId: string, source: PeerId) {
|
|
716
|
-
const validationFunc = async () => {
|
|
762
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<Tx>> = async () => {
|
|
717
763
|
const tx = Tx.fromBuffer(payloadData);
|
|
718
|
-
const
|
|
719
|
-
|
|
764
|
+
const isValid = await this.validatePropagatedTx(tx, source);
|
|
765
|
+
const exists = isValid && (await this.mempools.txPool.hasTx(tx.getTxHash()));
|
|
766
|
+
|
|
767
|
+
this.logger.trace(`Validate propagated tx`, {
|
|
768
|
+
isValid,
|
|
769
|
+
exists,
|
|
770
|
+
[Attributes.P2P_ID]: source.toString(),
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
if (!isValid) {
|
|
774
|
+
return { result: TopicValidatorResult.Reject };
|
|
775
|
+
} else if (exists) {
|
|
776
|
+
return { result: TopicValidatorResult.Ignore, obj: tx };
|
|
777
|
+
} else {
|
|
778
|
+
return { result: TopicValidatorResult.Accept, obj: tx };
|
|
779
|
+
}
|
|
720
780
|
};
|
|
721
781
|
|
|
722
782
|
const { result, obj: tx } = await this.validateReceivedMessage<Tx>(validationFunc, msgId, source, TopicType.tx);
|
|
723
|
-
if (
|
|
783
|
+
if (result !== TopicValidatorResult.Accept || !tx) {
|
|
724
784
|
return;
|
|
725
785
|
}
|
|
786
|
+
|
|
726
787
|
const txHash = tx.getTxHash();
|
|
727
788
|
const txHashString = txHash.toString();
|
|
728
789
|
this.logger.verbose(`Received tx ${txHashString} from external peer ${source.toString()} via gossip`, {
|
|
@@ -731,10 +792,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
731
792
|
});
|
|
732
793
|
|
|
733
794
|
if (this.config.dropTransactions && randomInt(1000) < this.config.dropTransactionsProbability * 1000) {
|
|
734
|
-
this.logger.
|
|
795
|
+
this.logger.warn(`Intentionally dropping tx ${txHashString} (probability rule)`);
|
|
735
796
|
return;
|
|
736
797
|
}
|
|
737
798
|
|
|
799
|
+
this.instrumentation.incrementTxReceived(1);
|
|
738
800
|
await this.mempools.txPool.addTxs([tx]);
|
|
739
801
|
}
|
|
740
802
|
|
|
@@ -745,14 +807,42 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
745
807
|
* @param attestation - The attestation to process.
|
|
746
808
|
*/
|
|
747
809
|
private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
748
|
-
const validationFunc = async () => {
|
|
810
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
|
|
749
811
|
const attestation = BlockAttestation.fromBuffer(payloadData);
|
|
750
|
-
const
|
|
751
|
-
this.
|
|
812
|
+
const pool = this.mempools.attestationPool!;
|
|
813
|
+
const isValid = await this.validateAttestation(source, attestation);
|
|
814
|
+
const exists = isValid && (await pool.hasAttestation(attestation));
|
|
815
|
+
|
|
816
|
+
let canAdd = true;
|
|
817
|
+
if (isValid && !exists) {
|
|
818
|
+
const slot = attestation.payload.header.slotNumber;
|
|
819
|
+
const { committee } = await this.epochCache.getCommittee(slot);
|
|
820
|
+
const committeeSize = committee?.length ?? 0;
|
|
821
|
+
canAdd = await pool.canAddAttestation(attestation, committeeSize);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
this.logger.trace(`Validate propagated block attestation`, {
|
|
825
|
+
isValid,
|
|
826
|
+
exists,
|
|
827
|
+
canAdd,
|
|
752
828
|
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toString(),
|
|
753
829
|
[Attributes.P2P_ID]: source.toString(),
|
|
754
830
|
});
|
|
755
|
-
|
|
831
|
+
|
|
832
|
+
if (!isValid) {
|
|
833
|
+
return { result: TopicValidatorResult.Reject };
|
|
834
|
+
} else if (exists) {
|
|
835
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
836
|
+
} else if (!canAdd) {
|
|
837
|
+
this.logger.warn(`Dropping block attestation due to per-(slot, proposalId) attestation cap`, {
|
|
838
|
+
slot: attestation.payload.header.slotNumber.toString(),
|
|
839
|
+
archive: attestation.archive.toString(),
|
|
840
|
+
source: source.toString(),
|
|
841
|
+
});
|
|
842
|
+
return { result: TopicValidatorResult.Ignore, obj: attestation };
|
|
843
|
+
} else {
|
|
844
|
+
return { result: TopicValidatorResult.Accept, obj: attestation };
|
|
845
|
+
}
|
|
756
846
|
};
|
|
757
847
|
|
|
758
848
|
const { result, obj: attestation } = await this.validateReceivedMessage<BlockAttestation>(
|
|
@@ -761,31 +851,58 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
761
851
|
source,
|
|
762
852
|
TopicType.block_attestation,
|
|
763
853
|
);
|
|
764
|
-
|
|
854
|
+
|
|
855
|
+
if (result !== TopicValidatorResult.Accept || !attestation) {
|
|
765
856
|
return;
|
|
766
857
|
}
|
|
858
|
+
|
|
767
859
|
this.logger.debug(
|
|
768
|
-
`Received attestation for
|
|
860
|
+
`Received attestation for slot ${attestation.slotNumber} from external peer ${source.toString()}`,
|
|
769
861
|
{
|
|
770
|
-
p2pMessageIdentifier: await attestation.
|
|
771
|
-
slot: attestation.slotNumber
|
|
862
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
863
|
+
slot: attestation.slotNumber,
|
|
772
864
|
archive: attestation.archive.toString(),
|
|
773
|
-
block: attestation.blockNumber,
|
|
774
865
|
source: source.toString(),
|
|
775
866
|
},
|
|
776
867
|
);
|
|
868
|
+
|
|
777
869
|
await this.mempools.attestationPool!.addAttestations([attestation]);
|
|
778
870
|
}
|
|
779
871
|
|
|
780
872
|
private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
|
|
781
|
-
const validationFunc = async () => {
|
|
873
|
+
const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockProposal>> = async () => {
|
|
782
874
|
const block = BlockProposal.fromBuffer(payloadData);
|
|
783
|
-
const
|
|
784
|
-
this.
|
|
875
|
+
const isValid = await this.validateBlockProposal(source, block);
|
|
876
|
+
const pool = this.mempools.attestationPool;
|
|
877
|
+
|
|
878
|
+
// Note that we dont have an attestation pool if we're a prover node, but we still
|
|
879
|
+
// subscribe to block proposal topics in order to prevent their txs from being cleared.
|
|
880
|
+
const exists = isValid && (await pool?.hasBlockProposal(block));
|
|
881
|
+
const canAdd = isValid && (await pool?.canAddProposal(block));
|
|
882
|
+
|
|
883
|
+
this.logger.trace(`Validate propagated block proposal`, {
|
|
884
|
+
isValid,
|
|
885
|
+
exists,
|
|
886
|
+
canAdd,
|
|
785
887
|
[Attributes.SLOT_NUMBER]: block.payload.header.slotNumber.toString(),
|
|
786
888
|
[Attributes.P2P_ID]: source.toString(),
|
|
787
889
|
});
|
|
788
|
-
|
|
890
|
+
|
|
891
|
+
if (!isValid) {
|
|
892
|
+
return { result: TopicValidatorResult.Reject };
|
|
893
|
+
} else if (exists) {
|
|
894
|
+
return { result: TopicValidatorResult.Ignore, obj: block };
|
|
895
|
+
} else if (!canAdd) {
|
|
896
|
+
this.peerManager.penalizePeer(source, PeerErrorSeverity.MidToleranceError);
|
|
897
|
+
this.logger.warn(`Penalizing peer for block proposal exceeding per-slot cap`, {
|
|
898
|
+
slot: block.slotNumber.toString(),
|
|
899
|
+
archive: block.archive.toString(),
|
|
900
|
+
source: source.toString(),
|
|
901
|
+
});
|
|
902
|
+
return { result: TopicValidatorResult.Reject };
|
|
903
|
+
} else {
|
|
904
|
+
return { result: TopicValidatorResult.Accept, obj: block };
|
|
905
|
+
}
|
|
789
906
|
};
|
|
790
907
|
|
|
791
908
|
const { result, obj: block } = await this.validateReceivedMessage<BlockProposal>(
|
|
@@ -794,6 +911,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
794
911
|
source,
|
|
795
912
|
TopicType.block_proposal,
|
|
796
913
|
);
|
|
914
|
+
|
|
797
915
|
if (!result || !block) {
|
|
798
916
|
return;
|
|
799
917
|
}
|
|
@@ -803,48 +921,51 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
803
921
|
|
|
804
922
|
// REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
805
923
|
@trackSpan('Libp2pService.processValidBlockProposal', async block => ({
|
|
806
|
-
[Attributes.
|
|
807
|
-
[Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
|
|
924
|
+
[Attributes.SLOT_NUMBER]: block.slotNumber,
|
|
808
925
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
809
|
-
[Attributes.P2P_ID]: await block.
|
|
926
|
+
[Attributes.P2P_ID]: await block.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
810
927
|
}))
|
|
811
928
|
private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
|
|
812
|
-
const slot = block.slotNumber
|
|
813
|
-
const previousSlot = slot -
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
archive: block.archive.toString(),
|
|
821
|
-
block: block.blockNumber,
|
|
822
|
-
source: sender.toString(),
|
|
823
|
-
},
|
|
824
|
-
);
|
|
929
|
+
const slot = block.slotNumber;
|
|
930
|
+
const previousSlot = SlotNumber(slot - 1);
|
|
931
|
+
this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
|
|
932
|
+
p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier(),
|
|
933
|
+
slot: block.slotNumber,
|
|
934
|
+
archive: block.archive.toString(),
|
|
935
|
+
source: sender.toString(),
|
|
936
|
+
});
|
|
825
937
|
const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
|
|
826
938
|
if (attestationsForPreviousSlot !== undefined) {
|
|
827
939
|
this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
|
|
828
940
|
}
|
|
829
941
|
|
|
830
|
-
//
|
|
942
|
+
// Attempt to add proposal, then mark the txs in this proposal as non-evictable
|
|
943
|
+
try {
|
|
944
|
+
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
945
|
+
} catch (err: unknown) {
|
|
946
|
+
// Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
|
|
947
|
+
if (err instanceof ProposalSlotCapExceededError) {
|
|
948
|
+
this.logger.warn(`Dropping block proposal due to per-slot proposal cap`, {
|
|
949
|
+
slot: String(slot),
|
|
950
|
+
archive: block.archive.toString(),
|
|
951
|
+
error: (err as Error).message,
|
|
952
|
+
});
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
throw err;
|
|
956
|
+
}
|
|
831
957
|
await this.mempools.txPool.markTxsAsNonEvictable(block.txHashes);
|
|
832
|
-
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
833
958
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
834
959
|
|
|
835
960
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
836
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
961
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
837
962
|
if (attestations?.length) {
|
|
838
963
|
for (const attestation of attestations) {
|
|
839
|
-
this.logger.verbose(
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
archive: attestation.archive.toString(),
|
|
845
|
-
block: attestation.blockNumber,
|
|
846
|
-
},
|
|
847
|
-
);
|
|
964
|
+
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber}`, {
|
|
965
|
+
p2pMessageIdentifier: await attestation.p2pMessageLoggingIdentifier(),
|
|
966
|
+
slot: attestation.slotNumber,
|
|
967
|
+
archive: attestation.archive.toString(),
|
|
968
|
+
});
|
|
848
969
|
await this.broadcastAttestation(attestation);
|
|
849
970
|
}
|
|
850
971
|
}
|
|
@@ -855,10 +976,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
855
976
|
* @param attestation - The attestation to broadcast.
|
|
856
977
|
*/
|
|
857
978
|
@trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
|
|
858
|
-
[Attributes.
|
|
859
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
979
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
860
980
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
861
|
-
[Attributes.P2P_ID]: await attestation.
|
|
981
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
862
982
|
}))
|
|
863
983
|
private async broadcastAttestation(attestation: BlockAttestation) {
|
|
864
984
|
await this.propagate(attestation);
|
|
@@ -869,15 +989,100 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
869
989
|
* @param message - The message to propagate.
|
|
870
990
|
*/
|
|
871
991
|
public async propagate<T extends Gossipable>(message: T) {
|
|
872
|
-
const p2pMessageIdentifier = await message.
|
|
992
|
+
const p2pMessageIdentifier = await message.p2pMessageLoggingIdentifier();
|
|
873
993
|
this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
|
|
874
|
-
void this.
|
|
875
|
-
.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
994
|
+
void this.sendToPeers(message).catch(error => {
|
|
995
|
+
this.logger.error(`Error propagating message ${p2pMessageIdentifier}`, { error });
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Validate the requested block transactions. Allow partial returns.
|
|
1001
|
+
* @param request - The block transactions request.
|
|
1002
|
+
* @param response - The block transactions response.
|
|
1003
|
+
* @param peerId - The ID of the peer that made the request.
|
|
1004
|
+
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1005
|
+
*/
|
|
1006
|
+
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1007
|
+
[Attributes.BLOCK_HASH]: request.blockHash.toString(),
|
|
1008
|
+
}))
|
|
1009
|
+
private async validateRequestedBlockTxs(
|
|
1010
|
+
request: BlockTxsRequest,
|
|
1011
|
+
response: BlockTxsResponse,
|
|
1012
|
+
peerId: PeerId,
|
|
1013
|
+
): Promise<boolean> {
|
|
1014
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1015
|
+
|
|
1016
|
+
try {
|
|
1017
|
+
if (!response.blockHash.equals(request.blockHash)) {
|
|
1018
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1019
|
+
throw new ValidationError(
|
|
1020
|
+
`Received block txs for unexpected block: expected ${request.blockHash.toString()}, got ${response.blockHash.toString()}`,
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (response.txIndices.getLength() !== request.txIndices.getLength()) {
|
|
1025
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1026
|
+
throw new ValidationError(
|
|
1027
|
+
`Received block txs with mismatched bitvector length: expected ${request.txIndices.getLength()}, got ${response.txIndices.getLength()}`,
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Check no duplicates and not exceeding returnable count
|
|
1032
|
+
const requestedIndices = new Set(request.txIndices.getTrueIndices());
|
|
1033
|
+
const availableIndices = new Set(response.txIndices.getTrueIndices());
|
|
1034
|
+
const maxReturnable = [...requestedIndices].filter(i => availableIndices.has(i)).length;
|
|
1035
|
+
|
|
1036
|
+
const returnedHashes = await Promise.all(response.txs.map(tx => tx.getTxHash().toString()));
|
|
1037
|
+
const uniqueReturned = new Set(returnedHashes.map(h => h.toString()));
|
|
1038
|
+
if (uniqueReturned.size !== returnedHashes.length) {
|
|
1039
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1040
|
+
throw new ValidationError(`Received duplicate txs in block txs response`);
|
|
1041
|
+
}
|
|
1042
|
+
if (response.txs.length > maxReturnable) {
|
|
1043
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1044
|
+
throw new ValidationError(
|
|
1045
|
+
`Received more txs (${response.txs.length}) than requested-and-available (${maxReturnable})`,
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1050
|
+
const proposal = await this.mempools.attestationPool?.getBlockProposal(request.blockHash.toString());
|
|
1051
|
+
if (proposal) {
|
|
1052
|
+
// Build intersected indices
|
|
1053
|
+
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
1054
|
+
|
|
1055
|
+
// Enforce subset membership and preserve increasing order by index.
|
|
1056
|
+
const hashToIndexInProposal = new Map<string, number>(
|
|
1057
|
+
proposal.txHashes.map((h, i) => [h.toString(), i] as [string, number]),
|
|
1058
|
+
);
|
|
1059
|
+
const allowedIndexSet = new Set(intersectIdx);
|
|
1060
|
+
const indices = returnedHashes.map(h => hashToIndexInProposal.get(h));
|
|
1061
|
+
const allAllowed = indices.every(idx => idx !== undefined && allowedIndexSet.has(idx));
|
|
1062
|
+
const strictlyIncreasing = indices.every((idx, i) => (i === 0 ? idx !== undefined : idx! > indices[i - 1]!));
|
|
1063
|
+
if (!allAllowed || !strictlyIncreasing) {
|
|
1064
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1065
|
+
throw new ValidationError('Returned txs do not match expected subset/order for requested indices');
|
|
1066
|
+
}
|
|
1067
|
+
} else {
|
|
1068
|
+
// No local proposal, cannot check the membership/order of the returned txs
|
|
1069
|
+
this.logger.warn(
|
|
1070
|
+
`Block proposal not found for block hash ${request.blockHash.toString()}; cannot validate membership/order of returned txs`,
|
|
1071
|
+
);
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
|
|
1076
|
+
return true;
|
|
1077
|
+
} catch (e: any) {
|
|
1078
|
+
if (e instanceof ValidationError) {
|
|
1079
|
+
this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
|
|
1080
|
+
} else {
|
|
1081
|
+
this.logger.error(`Error during validation of requested block txs`, e);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
return false;
|
|
1085
|
+
}
|
|
881
1086
|
}
|
|
882
1087
|
|
|
883
1088
|
/**
|
|
@@ -890,47 +1095,113 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
890
1095
|
* ReqRespSubProtocol.TX subprotocol validation.
|
|
891
1096
|
*
|
|
892
1097
|
* @param requestedTxHash - The collection of the txs that was requested.
|
|
893
|
-
* @param responseTx - The
|
|
1098
|
+
* @param responseTx - The collection of txs that was received as a response to the request.
|
|
894
1099
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
895
1100
|
* @returns True if the whole collection of txs is valid, false otherwise.
|
|
896
1101
|
*/
|
|
897
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
898
|
-
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
899
1102
|
@trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
|
|
900
1103
|
[Attributes.TX_HASH]: requestedTxHash.toString(),
|
|
901
1104
|
}))
|
|
902
|
-
private async
|
|
1105
|
+
private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
|
|
903
1106
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1107
|
+
const requestedTxValidator = this.createRequestedTxValidator();
|
|
904
1108
|
|
|
905
|
-
|
|
906
|
-
|
|
1109
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
|
|
1110
|
+
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
907
1111
|
try {
|
|
908
|
-
await Promise.all(
|
|
909
|
-
responseTx.map(async tx => {
|
|
910
|
-
if (!requested.has(tx.getTxHash().toString())) {
|
|
911
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
912
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
const { result } = await proofValidator.validateTx(tx);
|
|
916
|
-
if (result === 'invalid') {
|
|
917
|
-
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
918
|
-
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
919
|
-
}
|
|
920
|
-
}),
|
|
921
|
-
);
|
|
1112
|
+
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
922
1113
|
return true;
|
|
923
1114
|
} catch (e: any) {
|
|
924
1115
|
if (e instanceof ValidationError) {
|
|
925
|
-
this.logger.
|
|
1116
|
+
this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
|
|
926
1117
|
} else {
|
|
927
|
-
this.logger.
|
|
1118
|
+
this.logger.error(`Error during validation of requested txs`, e);
|
|
928
1119
|
}
|
|
929
1120
|
|
|
930
1121
|
return false;
|
|
931
1122
|
}
|
|
932
1123
|
}
|
|
933
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* Validates a BLOCK response.
|
|
1127
|
+
*
|
|
1128
|
+
* If a local copy exists, enforces hash equality. If missing, rejects (no penalty) since the hash cannot be verified.
|
|
1129
|
+
* Penalizes on block number mismatch or hash mismatch.
|
|
1130
|
+
*
|
|
1131
|
+
* @param requestedBlockNumber - The requested block number.
|
|
1132
|
+
* @param responseBlock - The block returned by the peer.
|
|
1133
|
+
* @param peerId - The peer that returned the block.
|
|
1134
|
+
* @returns True if the response is valid, false otherwise.
|
|
1135
|
+
*/
|
|
1136
|
+
@trackSpan('Libp2pService.validateRequestedBlock', (requestedBlockNumber, _responseBlock) => ({
|
|
1137
|
+
[Attributes.BLOCK_NUMBER]: requestedBlockNumber.toString(),
|
|
1138
|
+
}))
|
|
1139
|
+
private async validateRequestedBlock(
|
|
1140
|
+
requestedBlockNumber: Fr,
|
|
1141
|
+
responseBlock: L2Block,
|
|
1142
|
+
peerId: PeerId,
|
|
1143
|
+
): Promise<boolean> {
|
|
1144
|
+
try {
|
|
1145
|
+
const reqNum = Number(requestedBlockNumber.toString());
|
|
1146
|
+
if (responseBlock.number !== reqNum) {
|
|
1147
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
const local = await this.archiver.getBlock(BlockNumber(reqNum));
|
|
1152
|
+
if (!local) {
|
|
1153
|
+
// We are missing the local block; we cannot verify the hash yet. Reject without penalizing.
|
|
1154
|
+
// TODO: Consider extending this validator to accept an expected hash or
|
|
1155
|
+
// performing quorum-based checks when using P2P syncing prior to L1 sync.
|
|
1156
|
+
this.logger.warn(`Local block ${reqNum} not found; rejecting BLOCK response without hash verification`);
|
|
1157
|
+
return false;
|
|
1158
|
+
}
|
|
1159
|
+
const [localHash, respHash] = await Promise.all([local.hash(), responseBlock.hash()]);
|
|
1160
|
+
if (!localHash.equals(respHash)) {
|
|
1161
|
+
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1162
|
+
return false;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return true;
|
|
1166
|
+
} catch (e) {
|
|
1167
|
+
this.logger.warn(`Error validating requested block`, e);
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
private createRequestedTxValidator(): TxValidator {
|
|
1173
|
+
return new AggregateTxValidator(
|
|
1174
|
+
new DataTxValidator(),
|
|
1175
|
+
new MetadataTxValidator({
|
|
1176
|
+
l1ChainId: new Fr(this.config.l1ChainId),
|
|
1177
|
+
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1178
|
+
protocolContractsHash,
|
|
1179
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
1180
|
+
}),
|
|
1181
|
+
new TxProofValidator(this.proofVerifier),
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1186
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1187
|
+
|
|
1188
|
+
if (!(await tx.validateTxHash())) {
|
|
1189
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1190
|
+
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1194
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1195
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
const { result } = await txValidator.validateTx(tx);
|
|
1199
|
+
if (result === 'invalid') {
|
|
1200
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1201
|
+
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
934
1205
|
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
935
1206
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
936
1207
|
}))
|
|
@@ -952,7 +1223,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
952
1223
|
|
|
953
1224
|
// Double spend validator has a special case handler
|
|
954
1225
|
if (name === 'doubleSpendValidator') {
|
|
955
|
-
const txBlockNumber = currentBlockNumber + 1; // tx is expected to be in the next block
|
|
1226
|
+
const txBlockNumber = BlockNumber(currentBlockNumber + 1); // tx is expected to be in the next block
|
|
956
1227
|
severity = await this.handleDoubleSpendFailure(tx, txBlockNumber);
|
|
957
1228
|
}
|
|
958
1229
|
|
|
@@ -962,7 +1233,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
962
1233
|
return true;
|
|
963
1234
|
}
|
|
964
1235
|
|
|
965
|
-
private async getGasFees(blockNumber:
|
|
1236
|
+
private async getGasFees(blockNumber: BlockNumber): Promise<GasFees> {
|
|
966
1237
|
if (blockNumber === this.feesCache?.blockNumber) {
|
|
967
1238
|
return this.feesCache.gasFees;
|
|
968
1239
|
}
|
|
@@ -1003,13 +1274,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1003
1274
|
* @returns The message validators.
|
|
1004
1275
|
*/
|
|
1005
1276
|
private async createMessageValidators(
|
|
1006
|
-
currentBlockNumber:
|
|
1277
|
+
currentBlockNumber: BlockNumber,
|
|
1007
1278
|
nextSlotTimestamp: UInt64,
|
|
1008
1279
|
): Promise<Record<string, MessageValidator>[]> {
|
|
1009
1280
|
const gasFees = await this.getGasFees(currentBlockNumber);
|
|
1010
1281
|
const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
1011
1282
|
|
|
1012
|
-
const blockNumberInWhichTheTxIsConsideredToBeIncluded = currentBlockNumber + 1;
|
|
1283
|
+
const blockNumberInWhichTheTxIsConsideredToBeIncluded = BlockNumber(currentBlockNumber + 1);
|
|
1013
1284
|
|
|
1014
1285
|
return createTxMessageValidators(
|
|
1015
1286
|
nextSlotTimestamp,
|
|
@@ -1018,7 +1289,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1018
1289
|
gasFees,
|
|
1019
1290
|
this.config.l1ChainId,
|
|
1020
1291
|
this.config.rollupVersion,
|
|
1021
|
-
|
|
1292
|
+
protocolContractsHash,
|
|
1022
1293
|
this.archiver,
|
|
1023
1294
|
this.proofVerifier,
|
|
1024
1295
|
!this.config.disableTransactions,
|
|
@@ -1071,7 +1342,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1071
1342
|
* @param peerId - The peer ID of the peer that sent the tx.
|
|
1072
1343
|
* @returns Severity
|
|
1073
1344
|
*/
|
|
1074
|
-
private async handleDoubleSpendFailure(tx: Tx, blockNumber:
|
|
1345
|
+
private async handleDoubleSpendFailure(tx: Tx, blockNumber: BlockNumber): Promise<PeerErrorSeverity> {
|
|
1075
1346
|
if (blockNumber <= this.config.doubleSpendSeverePeerPenaltyWindow) {
|
|
1076
1347
|
return PeerErrorSeverity.HighToleranceError;
|
|
1077
1348
|
}
|
|
@@ -1079,7 +1350,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1079
1350
|
const snapshotValidator = new DoubleSpendTxValidator({
|
|
1080
1351
|
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1081
1352
|
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1082
|
-
blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow,
|
|
1353
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1083
1354
|
);
|
|
1084
1355
|
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1085
1356
|
return indices.map(index => index !== undefined);
|
|
@@ -1101,10 +1372,9 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1101
1372
|
* @returns True if the attestation is valid, false otherwise.
|
|
1102
1373
|
*/
|
|
1103
1374
|
@trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
|
|
1104
|
-
[Attributes.
|
|
1105
|
-
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
|
|
1375
|
+
[Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber,
|
|
1106
1376
|
[Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
|
|
1107
|
-
[Attributes.P2P_ID]: await attestation.
|
|
1377
|
+
[Attributes.P2P_ID]: await attestation.p2pMessageLoggingIdentifier().then(i => i.toString()),
|
|
1108
1378
|
}))
|
|
1109
1379
|
public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
|
|
1110
1380
|
const severity = await this.attestationValidator.validate(attestation);
|
|
@@ -1147,7 +1417,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1147
1417
|
private async sendToPeers<T extends Gossipable>(message: T) {
|
|
1148
1418
|
const parent = message.constructor as typeof Gossipable;
|
|
1149
1419
|
|
|
1150
|
-
const identifier = await message.
|
|
1420
|
+
const identifier = await message.p2pMessageLoggingIdentifier().then(i => i.toString());
|
|
1151
1421
|
this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
|
|
1152
1422
|
|
|
1153
1423
|
const recipientsNum = await this.publishToTopic(this.topicStrings[parent.p2pTopic], message);
|