@aztec/p2p 0.0.1-commit.e61ad554 → 0.0.1-commit.f146247c
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 +4 -3
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +4 -4
- package/dest/client/factory.d.ts +1 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +6 -5
- package/dest/client/p2p_client.d.ts +1 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +9 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +2 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +305 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +73 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +1 -0
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +8 -0
- package/dest/config.d.ts +8 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -0
- package/dest/mem_pools/instrumentation.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +2 -2
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +7 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.js +5 -5
- package/dest/msg_validators/tx_validator/archive_cache.d.ts +3 -3
- package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +5 -4
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
- package/dest/msg_validators/tx_validator/data_validator.d.ts +3 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +4 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +8 -3
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +21 -11
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +3 -2
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +2 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +3 -3
- package/dest/msg_validators/tx_validator/size_validator.d.ts +3 -1
- package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/size_validator.js +4 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +2 -2
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +3 -2
- package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +10 -6
- package/dest/services/discv5/discV5_service.js +1 -1
- package/dest/services/dummy_service.d.ts +13 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +39 -0
- package/dest/services/libp2p/instrumentation.d.ts +1 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -3
- package/dest/services/libp2p/libp2p_service.d.ts +9 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +37 -28
- package/dest/services/peer-manager/metrics.d.ts +2 -2
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +20 -5
- package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +8 -2
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +47 -0
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +566 -0
- package/dest/services/reqresp/batch-tx-requester/config.d.ts +17 -0
- package/dest/services/reqresp/batch-tx-requester/config.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/config.js +27 -0
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +50 -0
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/interface.js +1 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +37 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +151 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +54 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +139 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +20 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -0
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +21 -0
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +22 -3
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +63 -4
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +12 -0
- package/dest/services/reqresp/interface.d.ts +3 -1
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.d.ts +6 -5
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +17 -5
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +5 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +5 -0
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
- 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 -3
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +18 -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 +43 -13
- package/dest/services/reqresp/reqresp.d.ts +6 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +58 -22
- package/dest/services/service.d.ts +4 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +4 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +9 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +6 -4
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +16 -5
- package/dest/services/tx_collection/index.d.ts +2 -1
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +1 -0
- 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/instrumentation.js +9 -2
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +48 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -0
- package/dest/services/tx_collection/proposal_tx_collector.js +50 -0
- package/dest/services/tx_collection/tx_collection.d.ts +4 -4
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +5 -5
- package/dest/services/tx_provider_instrumentation.d.ts +1 -1
- package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
- package/dest/services/tx_provider_instrumentation.js +5 -5
- package/dest/test-helpers/index.d.ts +3 -1
- package/dest/test-helpers/index.d.ts.map +1 -1
- package/dest/test-helpers/index.js +2 -0
- package/dest/test-helpers/test_tx_provider.d.ts +40 -0
- package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
- package/dest/test-helpers/test_tx_provider.js +41 -0
- package/dest/test-helpers/testbench-utils.d.ts +158 -0
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
- package/dest/test-helpers/testbench-utils.js +297 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts +28 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +212 -131
- package/dest/testbench/worker_client_manager.d.ts +51 -6
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +226 -44
- package/package.json +14 -14
- package/src/bootstrap/bootstrap.ts +7 -4
- package/src/client/factory.ts +6 -10
- package/src/client/p2p_client.ts +9 -2
- package/src/client/test/tx_proposal_collector/README.md +227 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +336 -0
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
- package/src/config.ts +6 -1
- package/src/mem_pools/instrumentation.ts +2 -1
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +8 -2
- package/src/msg_validators/proposal_validator/proposal_validator.ts +5 -5
- package/src/msg_validators/tx_validator/archive_cache.ts +3 -3
- package/src/msg_validators/tx_validator/block_header_validator.ts +7 -8
- package/src/msg_validators/tx_validator/data_validator.ts +6 -2
- package/src/msg_validators/tx_validator/double_spend_validator.ts +4 -3
- package/src/msg_validators/tx_validator/factory.ts +64 -23
- package/src/msg_validators/tx_validator/gas_validator.ts +9 -3
- package/src/msg_validators/tx_validator/metadata_validator.ts +6 -3
- package/src/msg_validators/tx_validator/phases_validator.ts +5 -3
- package/src/msg_validators/tx_validator/size_validator.ts +6 -2
- package/src/msg_validators/tx_validator/timestamp_validator.ts +6 -3
- package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +8 -3
- package/src/services/data_store.ts +10 -7
- package/src/services/discv5/discV5_service.ts +1 -1
- package/src/services/dummy_service.ts +45 -0
- package/src/services/libp2p/instrumentation.ts +15 -2
- package/src/services/libp2p/libp2p_service.ts +60 -46
- package/src/services/peer-manager/metrics.ts +21 -4
- package/src/services/peer-manager/peer_scoring.ts +4 -1
- package/src/services/reqresp/batch-tx-requester/README.md +305 -0
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +706 -0
- package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
- package/src/services/reqresp/batch-tx-requester/interface.ts +57 -0
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +209 -0
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +205 -0
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +65 -4
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +16 -0
- package/src/services/reqresp/interface.ts +3 -0
- package/src/services/reqresp/metrics.ts +34 -9
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +7 -0
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +18 -4
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +51 -9
- package/src/services/reqresp/reqresp.ts +66 -19
- package/src/services/service.ts +4 -0
- package/src/services/tx_collection/config.ts +15 -1
- package/src/services/tx_collection/fast_tx_collection.ts +36 -13
- package/src/services/tx_collection/index.ts +5 -0
- package/src/services/tx_collection/instrumentation.ts +11 -2
- package/src/services/tx_collection/proposal_tx_collector.ts +114 -0
- package/src/services/tx_collection/tx_collection.ts +4 -4
- package/src/services/tx_provider_instrumentation.ts +11 -5
- package/src/test-helpers/index.ts +2 -0
- package/src/test-helpers/test_tx_provider.ts +64 -0
- package/src/test-helpers/testbench-utils.ts +374 -0
- package/src/testbench/p2p_client_testbench_worker.ts +321 -122
- package/src/testbench/worker_client_manager.ts +304 -47
|
@@ -6,7 +6,6 @@ import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/f
|
|
|
6
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
7
7
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
8
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
9
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
9
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
10
|
import type { EthAddress, L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
12
11
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
@@ -67,18 +66,15 @@ import {
|
|
|
67
66
|
CheckpointAttestationValidator,
|
|
68
67
|
CheckpointProposalValidator,
|
|
69
68
|
FishermanAttestationValidator,
|
|
70
|
-
SizeTxValidator,
|
|
71
69
|
} from '../../msg_validators/index.js';
|
|
72
70
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
73
71
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
74
|
-
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
75
72
|
import {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
} from '../../msg_validators/tx_validator/index.js';
|
|
73
|
+
type MessageValidator,
|
|
74
|
+
createTxMessageValidators,
|
|
75
|
+
createTxReqRespValidator,
|
|
76
|
+
} from '../../msg_validators/tx_validator/factory.js';
|
|
77
|
+
import { DoubleSpendTxValidator } from '../../msg_validators/tx_validator/index.js';
|
|
82
78
|
import { GossipSubEvent } from '../../types/index.js';
|
|
83
79
|
import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
|
|
84
80
|
import { getVersions } from '../../versioning.js';
|
|
@@ -89,10 +85,12 @@ import { gossipScoreThresholds } from '../gossipsub/scoring.js';
|
|
|
89
85
|
import type { PeerManagerInterface } from '../peer-manager/interface.js';
|
|
90
86
|
import { PeerManager } from '../peer-manager/peer_manager.js';
|
|
91
87
|
import { PeerScoring } from '../peer-manager/peer_scoring.js';
|
|
88
|
+
import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
|
|
92
89
|
import type { P2PReqRespConfig } from '../reqresp/config.js';
|
|
93
90
|
import {
|
|
94
91
|
DEFAULT_SUB_PROTOCOL_VALIDATORS,
|
|
95
92
|
type ReqRespInterface,
|
|
93
|
+
type ReqRespResponse,
|
|
96
94
|
ReqRespSubProtocol,
|
|
97
95
|
type ReqRespSubProtocolHandler,
|
|
98
96
|
type ReqRespSubProtocolHandlers,
|
|
@@ -286,14 +284,14 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
286
284
|
|
|
287
285
|
const datastore = new AztecDatastore(peerStore);
|
|
288
286
|
|
|
289
|
-
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry);
|
|
287
|
+
const otelMetricsAdapter = new OtelMetricsAdapter(telemetry, logger.getBindings());
|
|
290
288
|
|
|
291
289
|
const peerDiscoveryService = new DiscV5Service(
|
|
292
290
|
peerId,
|
|
293
291
|
config,
|
|
294
292
|
packageVersion,
|
|
295
293
|
telemetry,
|
|
296
|
-
createLogger(`${logger.module}:discv5_service
|
|
294
|
+
createLogger(`${logger.module}:discv5_service`, logger.getBindings()),
|
|
297
295
|
);
|
|
298
296
|
|
|
299
297
|
// Seed libp2p's bootstrap discovery with private and trusted peers
|
|
@@ -454,7 +452,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
454
452
|
connectionManager: components.connectionManager,
|
|
455
453
|
}),
|
|
456
454
|
},
|
|
457
|
-
logger: createLibp2pComponentLogger(logger.module),
|
|
455
|
+
logger: createLibp2pComponentLogger(logger.module, logger.getBindings()),
|
|
458
456
|
});
|
|
459
457
|
|
|
460
458
|
const peerScoring = new PeerScoring(config, telemetry);
|
|
@@ -642,6 +640,15 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
642
640
|
return this.reqresp.sendBatchRequest(protocol, requests, pinnedPeerId);
|
|
643
641
|
}
|
|
644
642
|
|
|
643
|
+
public sendRequestToPeer(
|
|
644
|
+
peerId: PeerId,
|
|
645
|
+
subProtocol: ReqRespSubProtocol,
|
|
646
|
+
payload: Buffer,
|
|
647
|
+
dialTimeout?: number,
|
|
648
|
+
): Promise<ReqRespResponse> {
|
|
649
|
+
return this.reqresp.sendRequestToPeer(peerId, subProtocol, payload, dialTimeout);
|
|
650
|
+
}
|
|
651
|
+
|
|
645
652
|
/**
|
|
646
653
|
* Get the ENR of the node
|
|
647
654
|
* @returns The ENR of the node
|
|
@@ -1207,7 +1214,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1207
1214
|
* @returns True if the requested block transactions are valid, false otherwise.
|
|
1208
1215
|
*/
|
|
1209
1216
|
@trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
|
|
1210
|
-
[Attributes.
|
|
1217
|
+
[Attributes.BLOCK_ARCHIVE]: request.archiveRoot.toString(),
|
|
1211
1218
|
}))
|
|
1212
1219
|
private async validateRequestedBlockTxs(
|
|
1213
1220
|
request: BlockTxsRequest,
|
|
@@ -1217,10 +1224,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1217
1224
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1218
1225
|
|
|
1219
1226
|
try {
|
|
1220
|
-
if (!response.
|
|
1227
|
+
if (!response.archiveRoot.equals(request.archiveRoot)) {
|
|
1221
1228
|
this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
|
|
1222
1229
|
throw new ValidationError(
|
|
1223
|
-
`Received block txs for unexpected
|
|
1230
|
+
`Received block txs for unexpected archive root: expected ${request.archiveRoot.toString()}, got ${response.archiveRoot.toString()}`,
|
|
1224
1231
|
);
|
|
1225
1232
|
}
|
|
1226
1233
|
|
|
@@ -1250,7 +1257,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1250
1257
|
}
|
|
1251
1258
|
|
|
1252
1259
|
// Given proposal (should have locally), ensure returned txs are valid subset and match request indices
|
|
1253
|
-
const proposal = await this.mempools.attestationPool.getBlockProposal(request.
|
|
1260
|
+
const proposal = await this.mempools.attestationPool.getBlockProposal(request.archiveRoot.toString());
|
|
1254
1261
|
if (proposal) {
|
|
1255
1262
|
// Build intersected indices
|
|
1256
1263
|
const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
|
|
@@ -1270,7 +1277,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1270
1277
|
} else {
|
|
1271
1278
|
// No local proposal, cannot check the membership/order of the returned txs
|
|
1272
1279
|
this.logger.warn(
|
|
1273
|
-
`Block proposal not found for
|
|
1280
|
+
`Block proposal not found for archive root ${request.archiveRoot.toString()}; cannot validate membership/order of returned txs`,
|
|
1274
1281
|
);
|
|
1275
1282
|
return false;
|
|
1276
1283
|
}
|
|
@@ -1309,7 +1316,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1309
1316
|
const requested = new Set(requestedTxHash.map(h => h.toString()));
|
|
1310
1317
|
const requestedTxValidator = this.createRequestedTxValidator();
|
|
1311
1318
|
|
|
1312
|
-
//TODO: (mralj) - this is somewhat naive implementation, if single tx is
|
|
1319
|
+
//TODO: (mralj) - this is somewhat naive implementation, if single tx is invalid we consider the whole response invalid.
|
|
1313
1320
|
// I think we should still extract the valid txs and return them, so that we can still use the response.
|
|
1314
1321
|
try {
|
|
1315
1322
|
await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
|
|
@@ -1372,28 +1379,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1372
1379
|
}
|
|
1373
1380
|
}
|
|
1374
1381
|
|
|
1375
|
-
private createRequestedTxValidator(): TxValidator {
|
|
1376
|
-
return new AggregateTxValidator(
|
|
1377
|
-
new DataTxValidator(),
|
|
1378
|
-
new SizeTxValidator(),
|
|
1379
|
-
new MetadataTxValidator({
|
|
1380
|
-
l1ChainId: new Fr(this.config.l1ChainId),
|
|
1381
|
-
rollupVersion: new Fr(this.config.rollupVersion),
|
|
1382
|
-
protocolContractsHash,
|
|
1383
|
-
vkTreeRoot: getVKTreeRoot(),
|
|
1384
|
-
}),
|
|
1385
|
-
new TxProofValidator(this.proofVerifier),
|
|
1386
|
-
);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
1382
|
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1390
1383
|
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1391
|
-
|
|
1392
|
-
if (!(await tx.validateTxHash())) {
|
|
1393
|
-
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1394
|
-
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
1384
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1398
1385
|
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1399
1386
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
@@ -1406,6 +1393,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1406
1393
|
}
|
|
1407
1394
|
}
|
|
1408
1395
|
|
|
1396
|
+
private createRequestedTxValidator(): TxValidator {
|
|
1397
|
+
return createTxReqRespValidator(this.proofVerifier, {
|
|
1398
|
+
l1ChainId: this.config.l1ChainId,
|
|
1399
|
+
rollupVersion: this.config.rollupVersion,
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1409
1403
|
@trackSpan('Libp2pService.validatePropagatedTx', tx => ({
|
|
1410
1404
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
1411
1405
|
}))
|
|
@@ -1448,6 +1442,22 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1448
1442
|
return gasFees;
|
|
1449
1443
|
}
|
|
1450
1444
|
|
|
1445
|
+
/**
|
|
1446
|
+
* Get the BatchTxRequesterLibP2PService dependencies for creating BatchTxRequester instances
|
|
1447
|
+
*/
|
|
1448
|
+
public getBatchTxRequesterService(): BatchTxRequesterLibP2PService {
|
|
1449
|
+
return {
|
|
1450
|
+
reqResp: this.reqresp,
|
|
1451
|
+
connectionSampler: this.reqresp.getConnectionSampler(),
|
|
1452
|
+
txValidatorConfig: {
|
|
1453
|
+
l1ChainId: this.config.l1ChainId,
|
|
1454
|
+
rollupVersion: this.config.rollupVersion,
|
|
1455
|
+
proofVerifier: this.proofVerifier,
|
|
1456
|
+
},
|
|
1457
|
+
peerScoring: this.peerManager,
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1451
1461
|
public async validate(txs: Tx[]): Promise<void> {
|
|
1452
1462
|
const currentBlockNumber = await this.archiver.getBlockNumber();
|
|
1453
1463
|
|
|
@@ -1498,6 +1508,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1498
1508
|
this.proofVerifier,
|
|
1499
1509
|
!this.config.disableTransactions,
|
|
1500
1510
|
allowedInSetup,
|
|
1511
|
+
this.logger.getBindings(),
|
|
1501
1512
|
);
|
|
1502
1513
|
}
|
|
1503
1514
|
|
|
@@ -1551,15 +1562,18 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1551
1562
|
return PeerErrorSeverity.HighToleranceError;
|
|
1552
1563
|
}
|
|
1553
1564
|
|
|
1554
|
-
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1565
|
+
const snapshotValidator = new DoubleSpendTxValidator(
|
|
1566
|
+
{
|
|
1567
|
+
nullifiersExist: async (nullifiers: Buffer[]) => {
|
|
1568
|
+
const merkleTree = this.worldStateSynchronizer.getSnapshot(
|
|
1569
|
+
BlockNumber(blockNumber - this.config.doubleSpendSeverePeerPenaltyWindow),
|
|
1570
|
+
);
|
|
1571
|
+
const indices = await merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
|
|
1572
|
+
return indices.map(index => index !== undefined);
|
|
1573
|
+
},
|
|
1561
1574
|
},
|
|
1562
|
-
|
|
1575
|
+
this.logger.getBindings(),
|
|
1576
|
+
);
|
|
1563
1577
|
|
|
1564
1578
|
const validSnapshot = await snapshotValidator.validateTx(tx);
|
|
1565
1579
|
if (validSnapshot.result !== 'valid') {
|
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
type TelemetryClient,
|
|
7
7
|
type Tracer,
|
|
8
8
|
type UpDownCounter,
|
|
9
|
+
createUpDownCounterWithDefault,
|
|
9
10
|
getTelemetryClient,
|
|
10
11
|
} from '@aztec/telemetry-client';
|
|
11
12
|
|
|
12
13
|
import type { PeerId } from '@libp2p/interface';
|
|
13
14
|
|
|
14
|
-
import {
|
|
15
|
+
import { GoodByeReason, prettyGoodbyeReason } from '../reqresp/protocols/index.js';
|
|
15
16
|
|
|
16
17
|
export class PeerManagerMetrics {
|
|
17
18
|
private sentGoodbyes: UpDownCounter;
|
|
@@ -31,10 +32,26 @@ export class PeerManagerMetrics {
|
|
|
31
32
|
this.tracer = telemetryClient.getTracer(name);
|
|
32
33
|
|
|
33
34
|
const meter = telemetryClient.getMeter(name);
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
const goodbyeReasonAttrs = {
|
|
36
|
+
[Attributes.P2P_GOODBYE_REASON]: [
|
|
37
|
+
prettyGoodbyeReason(GoodByeReason.SHUTDOWN),
|
|
38
|
+
prettyGoodbyeReason(GoodByeReason.MAX_PEERS),
|
|
39
|
+
prettyGoodbyeReason(GoodByeReason.LOW_SCORE),
|
|
40
|
+
prettyGoodbyeReason(GoodByeReason.BANNED),
|
|
41
|
+
prettyGoodbyeReason(GoodByeReason.WRONG_NETWORK),
|
|
42
|
+
prettyGoodbyeReason(GoodByeReason.UNKNOWN),
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
this.sentGoodbyes = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_GOODBYES_SENT, goodbyeReasonAttrs);
|
|
46
|
+
this.receivedGoodbyes = createUpDownCounterWithDefault(
|
|
47
|
+
meter,
|
|
48
|
+
Metrics.PEER_MANAGER_GOODBYES_RECEIVED,
|
|
49
|
+
goodbyeReasonAttrs,
|
|
50
|
+
);
|
|
36
51
|
this.peerCount = meter.createGauge(Metrics.PEER_MANAGER_PEER_COUNT);
|
|
37
|
-
this.lowScoreDisconnects = meter
|
|
52
|
+
this.lowScoreDisconnects = createUpDownCounterWithDefault(meter, Metrics.PEER_MANAGER_LOW_SCORE_DISCONNECTS, {
|
|
53
|
+
[Attributes.P2P_PEER_SCORE_STATE]: ['Banned', 'Disconnect'],
|
|
54
|
+
});
|
|
38
55
|
this.peerConnectionDuration = meter.createHistogram(Metrics.PEER_MANAGER_PEER_CONNECTION_DURATION);
|
|
39
56
|
}
|
|
40
57
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Metrics,
|
|
7
7
|
type TelemetryClient,
|
|
8
8
|
type UpDownCounter,
|
|
9
|
+
createUpDownCounterWithDefault,
|
|
9
10
|
getTelemetryClient,
|
|
10
11
|
} from '@aztec/telemetry-client';
|
|
11
12
|
|
|
@@ -52,7 +53,9 @@ export class PeerScoring {
|
|
|
52
53
|
|
|
53
54
|
const meter = telemetry.getMeter('PeerScoring');
|
|
54
55
|
|
|
55
|
-
this.peerStateCounter = meter
|
|
56
|
+
this.peerStateCounter = createUpDownCounterWithDefault(meter, Metrics.P2P_PEER_STATE_COUNT, {
|
|
57
|
+
[Attributes.P2P_PEER_SCORE_STATE]: ['Healthy', 'Disconnect', 'Banned'],
|
|
58
|
+
});
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
public penalizePeer(peerId: PeerId, penalty: PeerErrorSeverity) {
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# BatchTxRequester
|
|
2
|
+
|
|
3
|
+
The `BatchTxRequester` is a specialized P2P service that aggressively fetches missing transactions from peers when a node receives a block proposal but lacks some of the referenced transactions. This is critical for validators who need all transactions to attest to a proposal.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
When a validator receives a block proposal, they must verify all transactions in the block. If some transactions are missing from the local mempool (e.g., due to gossip delays), the `BatchTxRequester` kicks in to fetch them via direct peer-to-peer requests before the attestation deadline.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Block Proposal Received │
|
|
12
|
+
│ (contains hashes of N transactions) │
|
|
13
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────────────────────┐
|
|
17
|
+
│ Check local mempool for txs │
|
|
18
|
+
└─────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
┌─────────────────┴─────────────────┐
|
|
21
|
+
│ │
|
|
22
|
+
▼ ▼
|
|
23
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
24
|
+
│ All txs found │ │ Missing M txs │
|
|
25
|
+
│ → Attest now │ │ │
|
|
26
|
+
└─────────────────┘ └─────────────────┘
|
|
27
|
+
│
|
|
28
|
+
▼
|
|
29
|
+
┌───────────────────────────────┐
|
|
30
|
+
│ BatchTxRequester.run() │
|
|
31
|
+
│ Fetch missing txs until │
|
|
32
|
+
│ deadline or all collected │
|
|
33
|
+
└───────────────────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
### Peer Classification
|
|
39
|
+
|
|
40
|
+
The requester classifies peers into three categories to optimize fetching:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
┌─────────────────────────────┐
|
|
44
|
+
│ All Known Peers │
|
|
45
|
+
└─────────────────────────────┘
|
|
46
|
+
│
|
|
47
|
+
┌────────────────────────────┼────────────────────────────┐
|
|
48
|
+
│ │ │
|
|
49
|
+
▼ ▼ ▼
|
|
50
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
51
|
+
│ Pinned Peer │ │ Dumb Peers │ │ Smart Peers │
|
|
52
|
+
│ │ │ │ │ │
|
|
53
|
+
│ The peer who │ │ Peers we query │ │ Peers that have │
|
|
54
|
+
│ sent us the │ │ blindly - we │ │ told us which │
|
|
55
|
+
│ block proposal. │ │ don't know what │ │ txs they have │
|
|
56
|
+
│ Should have ALL │ │ txs they have. │ │ via BitVector │
|
|
57
|
+
│ transactions. │ │ │ │ responses. │
|
|
58
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
59
|
+
│ │ │
|
|
60
|
+
│ │ │
|
|
61
|
+
▼ ▼ ▼
|
|
62
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
63
|
+
│ Queried in │ │ Queried with │ │ Queried with │
|
|
64
|
+
│ dedicated loop, │ │ full tx hashes │ │ BitVector only │
|
|
65
|
+
│ prioritizes │ │ (peer may not │ │ (peer has the │
|
|
66
|
+
│ least-requested │ │ have proposal) │ │ block proposal) │
|
|
67
|
+
│ transactions │ │ │ │ │
|
|
68
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Blind Phase → Smart Phase Transition
|
|
72
|
+
|
|
73
|
+
Peers transition from "dumb" to "smart" when they respond with a valid `BlockTxsResponse` containing:
|
|
74
|
+
1. A matching `archiveRoot`
|
|
75
|
+
2. A non-empty `txIndices` BitVector indicating which transactions they have
|
|
76
|
+
3. At least one transaction we're still missing
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
┌──────────────────────────────────────────────────────────────────────────────┐
|
|
80
|
+
│ BLIND PHASE │
|
|
81
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
82
|
+
│ │ Initial State: All peers are "dumb" (except pinned peer) │ │
|
|
83
|
+
│ │ │ │
|
|
84
|
+
│ │ Request: [archiveRoot, txHashes (full list), txIndices (BitVector)] │ │
|
|
85
|
+
│ │ └─ Include full hashes because peer may not have proposal │ │
|
|
86
|
+
│ │ │ │
|
|
87
|
+
│ │ Response: [archiveRoot, txs[], txIndices (what peer has)] │ │
|
|
88
|
+
│ │ └─ Tells us exactly which txs this peer can provide │ │
|
|
89
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
90
|
+
└──────────────────────────────────────────────────────────────────────────────┘
|
|
91
|
+
│
|
|
92
|
+
│ Peer responds with valid txIndices
|
|
93
|
+
│ AND has txs we're missing
|
|
94
|
+
▼
|
|
95
|
+
┌──────────────────────────────────────────────────────────────────────────────┐
|
|
96
|
+
│ SMART PHASE │
|
|
97
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
98
|
+
│ │ Peer promoted to "smart" - we know exactly what they have │ │
|
|
99
|
+
│ │ │ │
|
|
100
|
+
│ │ Request: [archiveRoot, txIndices (BitVector only)] │ │
|
|
101
|
+
│ │ └─ No need for full hashes, peer has the proposal │ │
|
|
102
|
+
│ │ │ │
|
|
103
|
+
│ │ Response: [archiveRoot, txs[], txIndices (updated availability)] │ │
|
|
104
|
+
│ │ └─ May have received more txs since last response │ │
|
|
105
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
106
|
+
└──────────────────────────────────────────────────────────────────────────────┘
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Concurrent Worker Architecture
|
|
110
|
+
|
|
111
|
+
The `BatchTxRequester` runs three types of workers concurrently:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
┌─────────────────────────────────────┐
|
|
115
|
+
│ BatchTxRequester.run() │
|
|
116
|
+
│ │
|
|
117
|
+
│ ┌─────────────────────────────┐ │
|
|
118
|
+
│ │ txQueue (FifoMemoryQueue)│◄───┼──── Yields Tx objects
|
|
119
|
+
│ └─────────────────────────────┘ │ to caller
|
|
120
|
+
└─────────────────────────────────────┘
|
|
121
|
+
▲
|
|
122
|
+
│ put(tx)
|
|
123
|
+
┌──────────────────────────────┼────────────────────────────┐
|
|
124
|
+
│ │ │
|
|
125
|
+
│ │ │
|
|
126
|
+
┌──────────┴──────────┐ ┌───────────┴─────────┐ ┌──────────┴──────────┐
|
|
127
|
+
│ pinnedPeerRequester │ │ dumbRequester │ │ smartRequester │
|
|
128
|
+
│ │ │ │ │ │
|
|
129
|
+
│ Single dedicated │ │ N parallel workers │ │ M parallel workers │
|
|
130
|
+
│ loop for pinned │ │ (default: 10) │ │ (default: 10) │
|
|
131
|
+
│ peer │ │ │ │ │
|
|
132
|
+
│ │ │ Round-robin through │ │ Wait on semaphore │
|
|
133
|
+
│ Prioritizes txs │ │ available dumb │ │ until peers become │
|
|
134
|
+
│ that have been │ │ peers │ │ smart │
|
|
135
|
+
│ requested least │ │ │ │ │
|
|
136
|
+
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
|
|
137
|
+
│ │ │
|
|
138
|
+
└──────────────────────────────┼──────────────────────────────┘
|
|
139
|
+
│
|
|
140
|
+
▼
|
|
141
|
+
┌───────────────────────┐
|
|
142
|
+
│ requestTxBatch() │
|
|
143
|
+
│ │
|
|
144
|
+
│ sendRequestToPeer() │
|
|
145
|
+
│ via libp2p ReqResp │
|
|
146
|
+
└───────────────────────┘
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Wire Protocol
|
|
150
|
+
|
|
151
|
+
### BlockTxsRequest
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
class BlockTxsRequest {
|
|
155
|
+
archiveRoot: Fr; // Archive root after the proposed block is applied
|
|
156
|
+
txHashes: TxHashArray; // Full tx hashes (for dumb peers without proposal)
|
|
157
|
+
txIndices: BitVector; // Which txs from proposal we're requesting (1 = want)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### BlockTxsResponse
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
class BlockTxsResponse {
|
|
165
|
+
archiveRoot: Fr; // Echo back the proposal archive root
|
|
166
|
+
txs: TxArray; // Actual transaction data
|
|
167
|
+
txIndices: BitVector; // Which txs the peer has available (1 = have)
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The `BitVector` is a compact representation where each bit corresponds to a transaction index in the block proposal. This allows efficient capability advertisement without repeating full hashes.
|
|
172
|
+
|
|
173
|
+
## Key Files
|
|
174
|
+
|
|
175
|
+
| File | Description |
|
|
176
|
+
|------|-------------|
|
|
177
|
+
| `batch_tx_requester.ts` | Main orchestrator with worker loops |
|
|
178
|
+
| `missing_txs.ts` | Tracks metadata for each missing tx (request count, in-flight status, which peers have it) |
|
|
179
|
+
| `peer_collection.ts` | Manages peer classification (dumb/smart/bad) and rate limiting |
|
|
180
|
+
| `interface.ts` | Type definitions for dependencies |
|
|
181
|
+
| `../protocols/block_txs/` | Wire protocol definitions (`BlockTxsRequest`, `BlockTxsResponse`, `BitVector`) |
|
|
182
|
+
|
|
183
|
+
## Stopping Conditions
|
|
184
|
+
|
|
185
|
+
The `BatchTxRequester` stops when any of these conditions are met:
|
|
186
|
+
|
|
187
|
+
1. **All transactions fetched** - Success!
|
|
188
|
+
2. **Deadline exceeded** - Timeout configured by caller
|
|
189
|
+
3. **Abort signal** - External cancellation
|
|
190
|
+
4. **No transactions to fetch** - Nothing was missing
|
|
191
|
+
|
|
192
|
+
## Configuration
|
|
193
|
+
|
|
194
|
+
| Parameter | Default | Description |
|
|
195
|
+
|-----------|---------|-------------|
|
|
196
|
+
| `batchTxRequesterSmartParallelWorkerCount` | 10 | Max concurrent requests to smart peers |
|
|
197
|
+
| `batchTxRequesterDumbParallelWorkerCount` | 10 | Max concurrent requests to dumb peers |
|
|
198
|
+
| `batchTxRequesterTxBatchSize` | 8 | Max transactions per request |
|
|
199
|
+
| `batchTxRequesterBadPeerThreshold` | 2 | Penalties before marking peer as bad (see > threshold logic) |
|
|
200
|
+
| `RATE_LIMIT_EXCEEDED_PEER_CACHE_TTL` | 1000ms | Cooldown after rate limit hit |
|
|
201
|
+
|
|
202
|
+
## Error Handling
|
|
203
|
+
|
|
204
|
+
### Peer States
|
|
205
|
+
|
|
206
|
+
- **Bad Peer**: After `batchTxRequesterBadPeerThreshold` penalties, peer is excluded from queries
|
|
207
|
+
- **Bad Peer Penalties**: A penalty is applied on `FAILURE`/`UNKNOWN` responses or when transaction validation fails
|
|
208
|
+
- **Rate Limited**: On `RATE_LIMIT_EXCEEDED` response, peer is temporarily excluded
|
|
209
|
+
- **Redemption**: A peer is removed from the bad set only after a successful response with all transactions valid (this clears the penalty counter)
|
|
210
|
+
- **Peer Scoring**: Each penalty is forwarded to the injected `peerScoring` service with a severity
|
|
211
|
+
|
|
212
|
+
### Failure Recovery
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
Request to peer fails
|
|
216
|
+
│
|
|
217
|
+
├── RATE_LIMIT_EXCEEDED → Mark peer rate-limited, sleep, retry later
|
|
218
|
+
│
|
|
219
|
+
├── FAILURE/UNKNOWN → Penalise peer (severity), increment penalty counter
|
|
220
|
+
│ │
|
|
221
|
+
│ ├── Counter < threshold → Continue querying
|
|
222
|
+
│ │
|
|
223
|
+
│ └── Counter ≥ threshold → Exclude peer
|
|
224
|
+
│
|
|
225
|
+
└── SUCCESS → Process response, if all transactions are valid clear penalties
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Usage Example
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const requester = new BatchTxRequester(
|
|
232
|
+
missingTxHashes, // TxHash[] - what we need
|
|
233
|
+
blockProposal, // BlockProposal - the proposal we're attesting to
|
|
234
|
+
pinnedPeer, // PeerId | undefined - who sent us the proposal
|
|
235
|
+
timeoutMs, // number - how long to try
|
|
236
|
+
p2pService, // BatchTxRequesterLibP2PService
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// Async generator yields transactions as they arrive
|
|
240
|
+
for await (const tx of requester.run()) {
|
|
241
|
+
// Process each transaction as it's fetched and validated
|
|
242
|
+
mempool.addTx(tx);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Or collect all at once
|
|
246
|
+
const txs = await BatchTxRequester.collectAllTxs(requester.run());
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Integration with Broader Codebase
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
253
|
+
│ P2PClient │
|
|
254
|
+
│ │
|
|
255
|
+
│ Receives block proposals via gossipsub │
|
|
256
|
+
│ Triggers transaction collection when needed │
|
|
257
|
+
└───────────────────────────────────┬─────────────────────────────────────────┘
|
|
258
|
+
│
|
|
259
|
+
▼
|
|
260
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
261
|
+
│ TxCollection │
|
|
262
|
+
│ │
|
|
263
|
+
│ Coordinates Fast and Slow collection strategies │
|
|
264
|
+
│ Manages lifecycle of collection requests │
|
|
265
|
+
└───────────────────┬─────────────────────────────────┬───────────────────────┘
|
|
266
|
+
│ │
|
|
267
|
+
▼ ▼
|
|
268
|
+
┌───────────────────────────────────┐ ┌─────────────────────────────────────┐
|
|
269
|
+
│ FastTxCollection │ │ SlowTxCollection │
|
|
270
|
+
│ │ │ │
|
|
271
|
+
│ Time-critical: attestations │ │ Background: unproven blocks │
|
|
272
|
+
│ │ │ │
|
|
273
|
+
│ 1. Try RPC nodes first (fast) │ │ Periodic polling of RPC nodes │
|
|
274
|
+
│ 2. Fall back to BatchTxRequester │ │ and peers for missing txs │
|
|
275
|
+
│ │ │ │
|
|
276
|
+
└───────────────────┬───────────────┘ └─────────────────────────────────────┘
|
|
277
|
+
│
|
|
278
|
+
│ For 'proposal' requests
|
|
279
|
+
▼
|
|
280
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
281
|
+
│ BatchTxRequester │
|
|
282
|
+
│ │
|
|
283
|
+
│ Aggressive parallel fetching from multiple peers │
|
|
284
|
+
│ Uses BLOCK_TXS sub-protocol for efficient batching │
|
|
285
|
+
└───────────────────┬─────────────────────────────────────────────────────────┘
|
|
286
|
+
│
|
|
287
|
+
▼
|
|
288
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
289
|
+
│ ReqResp (libp2p) │
|
|
290
|
+
│ │
|
|
291
|
+
│ Low-level stream management │
|
|
292
|
+
│ sendRequestToPeer() → opens stream → sends request → awaits response │
|
|
293
|
+
└───────────────────┬─────────────────────────────────────────────────────────┘
|
|
294
|
+
│
|
|
295
|
+
▼
|
|
296
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
297
|
+
│ reqRespBlockTxsHandler (on peer) │
|
|
298
|
+
│ │
|
|
299
|
+
│ 1. Parse BlockTxsRequest │
|
|
300
|
+
│ 2. Look up block proposal in AttestationPool │
|
|
301
|
+
│ 3. Check TxPool for available transactions │
|
|
302
|
+
│ 4. Build BitVector of available tx indices │
|
|
303
|
+
│ 5. Return BlockTxsResponse with txs + availability info │
|
|
304
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
305
|
+
```
|