@aztec/p2p 3.0.0-devnet.2 → 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/client/factory.d.ts +1 -1
- package/dest/client/index.d.ts +1 -1
- package/dest/client/interface.d.ts +4 -2
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +8 -26
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +31 -24
- package/dest/config.d.ts +60 -54
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -2
- package/dest/enr/generate-enr.d.ts +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 +67 -34
- 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 +57 -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 +51 -7
- 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 +2 -2
- 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 +5 -38
- 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 +9 -3
- package/dest/mem_pools/tx_pool/index.d.ts +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +5 -3
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +7 -0
- package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +10 -3
- 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 +5 -4
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +12 -12
- 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 +1 -1
- 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 +22 -10
- 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/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/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 +1 -1
- 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 +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- 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 +3 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- 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 +1 -1
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/dummy_service.d.ts +1 -1
- 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 +25 -74
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +308 -84
- 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 +4 -2
- 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 -2
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +1 -1
- 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 +2 -2
- 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 +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/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 +11 -11
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- 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_source.d.ts +1 -1
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_provider.d.ts +5 -4
- package/dest/services/tx_provider.d.ts.map +1 -1
- 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-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 +2 -2
- package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
- package/dest/test-helpers/mock-tx-helpers.js +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +14 -8
- 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 +1 -1
- package/package.json +19 -18
- package/src/client/interface.ts +4 -1
- package/src/client/p2p_client.ts +51 -43
- package/src/config.ts +19 -2
- 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 +84 -34
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +87 -24
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +77 -15
- package/src/mem_pools/attestation_pool/mocks.ts +3 -3
- package/src/mem_pools/instrumentation.ts +13 -0
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +15 -9
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +13 -6
- package/src/mem_pools/tx_pool/tx_pool.ts +10 -2
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +5 -4
- package/src/msg_validators/attestation_validator/attestation_validator.ts +14 -16
- 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 +26 -10
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +3 -2
- package/src/msg_validators/tx_validator/metadata_validator.ts +1 -1
- 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 +2 -1
- package/src/services/encoding.ts +81 -6
- package/src/services/libp2p/instrumentation.ts +10 -1
- package/src/services/libp2p/libp2p_service.ts +334 -91
- package/src/services/peer-manager/metrics.ts +10 -0
- package/src/services/peer-manager/peer_manager.ts +4 -2
- package/src/services/peer-manager/peer_scoring.ts +46 -3
- package/src/services/reqresp/interface.ts +1 -1
- 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 +2 -2
- package/src/services/tx_collection/fast_tx_collection.ts +3 -2
- package/src/services/tx_collection/slow_tx_collection.ts +7 -6
- package/src/services/tx_collection/tx_collection.ts +10 -9
- package/src/services/tx_provider.ts +4 -3
- package/src/test-helpers/mock-tx-helpers.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +11 -5
- package/src/testbench/testbench.ts +2 -2
- package/src/util.ts +12 -2
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
|
|
3
4
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
4
5
|
|
|
5
6
|
import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
|
|
6
7
|
import type { AttestationPool } from './attestation_pool.js';
|
|
8
|
+
import { ATTESTATION_CAP_BUFFER, MAX_PROPOSALS_PER_SLOT } from './kv_attestation_pool.js';
|
|
7
9
|
|
|
8
10
|
export class InMemoryAttestationPool implements AttestationPool {
|
|
9
11
|
private metrics: PoolInstrumentation<BlockAttestation>;
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
14
|
+
private attestations: Map<
|
|
15
|
+
/*slot=*/ SlotNumber,
|
|
16
|
+
Map</*proposalId*/ string, Map</*address=*/ string, BlockAttestation>>
|
|
17
|
+
>;
|
|
12
18
|
private proposals: Map<string, BlockProposal>;
|
|
13
19
|
|
|
14
20
|
constructor(
|
|
@@ -30,7 +36,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
30
36
|
return Promise.resolve(this.attestations.size === 0);
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
public getAttestationsForSlot(slot:
|
|
39
|
+
public getAttestationsForSlot(slot: SlotNumber): Promise<BlockAttestation[]> {
|
|
34
40
|
return Promise.resolve(
|
|
35
41
|
Array.from(this.attestations.get(slot)?.values() ?? []).flatMap(proposalAttestationMap =>
|
|
36
42
|
Array.from(proposalAttestationMap.values()),
|
|
@@ -38,7 +44,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
38
44
|
);
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
public getAttestationsForSlotAndProposal(slot:
|
|
47
|
+
public getAttestationsForSlotAndProposal(slot: SlotNumber, proposalId: string): Promise<BlockAttestation[]> {
|
|
42
48
|
const slotAttestationMap = this.attestations.get(slot);
|
|
43
49
|
if (slotAttestationMap) {
|
|
44
50
|
const proposalAttestationMap = slotAttestationMap.get(proposalId);
|
|
@@ -59,7 +65,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
59
65
|
|
|
60
66
|
// Skip attestations with invalid signatures
|
|
61
67
|
if (!sender) {
|
|
62
|
-
this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber
|
|
68
|
+
this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber}`, {
|
|
63
69
|
signature: attestation.signature.toString(),
|
|
64
70
|
slotNumber,
|
|
65
71
|
proposalId,
|
|
@@ -67,11 +73,11 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
67
73
|
continue;
|
|
68
74
|
}
|
|
69
75
|
|
|
70
|
-
const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber
|
|
76
|
+
const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber);
|
|
71
77
|
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
|
|
72
78
|
proposalAttestationMap.set(sender.toString(), attestation);
|
|
73
79
|
|
|
74
|
-
this.log.verbose(`Added attestation for slot ${slotNumber
|
|
80
|
+
this.log.verbose(`Added attestation for slot ${slotNumber} from ${sender}`, {
|
|
75
81
|
signature: attestation.signature.toString(),
|
|
76
82
|
slotNumber,
|
|
77
83
|
address: sender,
|
|
@@ -82,7 +88,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
82
88
|
return Promise.resolve();
|
|
83
89
|
}
|
|
84
90
|
|
|
85
|
-
#getNumberOfAttestationsInSlot(slot:
|
|
91
|
+
#getNumberOfAttestationsInSlot(slot: SlotNumber): number {
|
|
86
92
|
let total = 0;
|
|
87
93
|
const slotAttestationMap = getSlotOrDefault(this.attestations, slot);
|
|
88
94
|
|
|
@@ -94,7 +100,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
94
100
|
return total;
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
public async deleteAttestationsOlderThan(oldestSlot:
|
|
103
|
+
public async deleteAttestationsOlderThan(oldestSlot: SlotNumber): Promise<void> {
|
|
98
104
|
const olderThan = [];
|
|
99
105
|
|
|
100
106
|
// Entries are iterated in insertion order, so we can break as soon as we find a slot that is older than the oldestSlot.
|
|
@@ -115,7 +121,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
115
121
|
return Promise.resolve();
|
|
116
122
|
}
|
|
117
123
|
|
|
118
|
-
public deleteAttestationsForSlot(slot:
|
|
124
|
+
public deleteAttestationsForSlot(slot: SlotNumber): Promise<void> {
|
|
119
125
|
// We count the number of attestations we are removing
|
|
120
126
|
const numberOfAttestations = this.#getNumberOfAttestationsInSlot(slot);
|
|
121
127
|
const proposalIdsToDelete = this.attestations.get(slot)?.keys();
|
|
@@ -133,7 +139,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
133
139
|
return Promise.resolve();
|
|
134
140
|
}
|
|
135
141
|
|
|
136
|
-
public deleteAttestationsForSlotAndProposal(slot:
|
|
142
|
+
public deleteAttestationsForSlotAndProposal(slot: SlotNumber, proposalId: string): Promise<void> {
|
|
137
143
|
const slotAttestationMap = getSlotOrDefault(this.attestations, slot);
|
|
138
144
|
if (slotAttestationMap) {
|
|
139
145
|
if (slotAttestationMap.has(proposalId)) {
|
|
@@ -152,7 +158,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
152
158
|
public deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
|
|
153
159
|
for (const attestation of attestations) {
|
|
154
160
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
155
|
-
const slotAttestationMap = this.attestations.get(slotNumber
|
|
161
|
+
const slotAttestationMap = this.attestations.get(slotNumber);
|
|
156
162
|
if (slotAttestationMap) {
|
|
157
163
|
const proposalId = attestation.archive.toString();
|
|
158
164
|
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
|
|
@@ -161,7 +167,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
161
167
|
|
|
162
168
|
// Skip attestations with invalid signatures
|
|
163
169
|
if (!sender) {
|
|
164
|
-
this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber
|
|
170
|
+
this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber}`);
|
|
165
171
|
continue;
|
|
166
172
|
}
|
|
167
173
|
|
|
@@ -173,10 +179,33 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
173
179
|
return Promise.resolve();
|
|
174
180
|
}
|
|
175
181
|
|
|
182
|
+
public hasAttestation(attestation: BlockAttestation): Promise<boolean> {
|
|
183
|
+
const slotNumber = attestation.payload.header.slotNumber;
|
|
184
|
+
const proposalId = attestation.archive.toString();
|
|
185
|
+
const sender = attestation.getSender();
|
|
186
|
+
|
|
187
|
+
// Attestations with invalid signatures are never in the pool
|
|
188
|
+
if (!sender) {
|
|
189
|
+
return Promise.resolve(false);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const slotAttestationMap = this.attestations.get(slotNumber);
|
|
193
|
+
if (!slotAttestationMap) {
|
|
194
|
+
return Promise.resolve(false);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const proposalAttestationMap = slotAttestationMap.get(proposalId);
|
|
198
|
+
if (!proposalAttestationMap) {
|
|
199
|
+
return Promise.resolve(false);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return Promise.resolve(proposalAttestationMap.has(sender.toString()));
|
|
203
|
+
}
|
|
204
|
+
|
|
176
205
|
public addBlockProposal(blockProposal: BlockProposal): Promise<void> {
|
|
177
206
|
// We initialize slot-proposal mapping if it does not exist
|
|
178
207
|
// This is important to ensure we can delete this proposal if there were not attestations for it
|
|
179
|
-
const slotProposalMapping = getSlotOrDefault(this.attestations, blockProposal.slotNumber
|
|
208
|
+
const slotProposalMapping = getSlotOrDefault(this.attestations, blockProposal.slotNumber);
|
|
180
209
|
slotProposalMapping.set(blockProposal.payload.archive.toString(), new Map<string, BlockAttestation>());
|
|
181
210
|
|
|
182
211
|
this.proposals.set(blockProposal.payload.archive.toString(), blockProposal);
|
|
@@ -186,6 +215,38 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
186
215
|
public getBlockProposal(id: string): Promise<BlockProposal | undefined> {
|
|
187
216
|
return Promise.resolve(this.proposals.get(id));
|
|
188
217
|
}
|
|
218
|
+
|
|
219
|
+
public hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
|
|
220
|
+
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.payload.archive.toString();
|
|
221
|
+
return Promise.resolve(this.proposals.has(id));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public hasReachedProposalCap(slot: SlotNumber): Promise<boolean> {
|
|
225
|
+
const slotAttestationMap = this.attestations.get(slot);
|
|
226
|
+
const proposalCount = slotAttestationMap?.size ?? 0;
|
|
227
|
+
return Promise.resolve(proposalCount >= MAX_PROPOSALS_PER_SLOT);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public hasReachedAttestationCap(slot: SlotNumber, proposalId: string, committeeSize: number): Promise<boolean> {
|
|
231
|
+
const limit = committeeSize + ATTESTATION_CAP_BUFFER;
|
|
232
|
+
const count = this.attestations.get(slot)?.get(proposalId)?.size ?? 0;
|
|
233
|
+
return Promise.resolve(limit <= 0 || count >= limit);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public async canAddProposal(block: BlockProposal): Promise<boolean> {
|
|
237
|
+
return this.proposals.has(block.archive.toString()) || !(await this.hasReachedProposalCap(block.slotNumber));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public async canAddAttestation(attestation: BlockAttestation, committeeSize: number): Promise<boolean> {
|
|
241
|
+
const sender = attestation.getSender();
|
|
242
|
+
const slot = attestation.payload.header.slotNumber;
|
|
243
|
+
const pid = attestation.archive.toString();
|
|
244
|
+
return (
|
|
245
|
+
!!sender &&
|
|
246
|
+
((this.attestations.get(slot)?.get(pid)?.has(sender.toString()) ?? false) ||
|
|
247
|
+
!(await this.hasReachedAttestationCap(slot, pid, committeeSize)))
|
|
248
|
+
);
|
|
249
|
+
}
|
|
189
250
|
}
|
|
190
251
|
|
|
191
252
|
/**
|
|
@@ -197,8 +258,9 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
197
258
|
* @returns The slot mapping
|
|
198
259
|
*/
|
|
199
260
|
function getSlotOrDefault(
|
|
200
|
-
|
|
201
|
-
|
|
261
|
+
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
262
|
+
map: Map<SlotNumber, Map<string, Map<string, BlockAttestation>>>,
|
|
263
|
+
slot: SlotNumber,
|
|
202
264
|
): Map<string, Map<string, BlockAttestation>> {
|
|
203
265
|
if (!map.has(slot)) {
|
|
204
266
|
map.set(slot, new Map<string, Map<string, BlockAttestation>>());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Secp256k1Signer } from '@aztec/foundation/crypto';
|
|
2
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import type { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import {
|
|
4
4
|
BlockAttestation,
|
|
5
5
|
ConsensusPayload,
|
|
@@ -33,7 +33,7 @@ export const mockAttestation = (
|
|
|
33
33
|
): BlockAttestation => {
|
|
34
34
|
// Use arbitrary numbers for all other than slot
|
|
35
35
|
const header = makeL2BlockHeader(1, 2, slot);
|
|
36
|
-
const payload = new ConsensusPayload(header.toCheckpointHeader(), archive
|
|
36
|
+
const payload = new ConsensusPayload(header.toCheckpointHeader(), archive);
|
|
37
37
|
|
|
38
38
|
const attestationHash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
|
|
39
39
|
const attestationSignature = signer.sign(attestationHash);
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type MetricsType,
|
|
11
11
|
type ObservableGauge,
|
|
12
12
|
type TelemetryClient,
|
|
13
|
+
type UpDownCounter,
|
|
13
14
|
} from '@aztec/telemetry-client';
|
|
14
15
|
|
|
15
16
|
export enum PoolName {
|
|
@@ -20,6 +21,7 @@ export enum PoolName {
|
|
|
20
21
|
type MetricsLabels = {
|
|
21
22
|
objectInMempool: MetricsType;
|
|
22
23
|
objectSize: MetricsType;
|
|
24
|
+
itemsAdded: MetricsType;
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -32,11 +34,13 @@ function getMetricsLabels(name: PoolName): MetricsLabels {
|
|
|
32
34
|
return {
|
|
33
35
|
objectInMempool: Metrics.MEMPOOL_TX_COUNT,
|
|
34
36
|
objectSize: Metrics.MEMPOOL_TX_SIZE,
|
|
37
|
+
itemsAdded: Metrics.MEMPOOL_TX_ADDED_COUNT,
|
|
35
38
|
};
|
|
36
39
|
} else if (name === PoolName.ATTESTATION_POOL) {
|
|
37
40
|
return {
|
|
38
41
|
objectInMempool: Metrics.MEMPOOL_ATTESTATIONS_COUNT,
|
|
39
42
|
objectSize: Metrics.MEMPOOL_ATTESTATIONS_SIZE,
|
|
43
|
+
itemsAdded: Metrics.MEMPOOL_ATTESTATIONS_ADDED_COUNT,
|
|
40
44
|
};
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -53,6 +57,7 @@ export type PoolStatsCallback = () => Promise<{
|
|
|
53
57
|
export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
54
58
|
/** The number of txs in the mempool */
|
|
55
59
|
private objectsInMempool: ObservableGauge;
|
|
60
|
+
private addObjectCounter: UpDownCounter;
|
|
56
61
|
/** Tracks tx size */
|
|
57
62
|
private objectSize: Histogram;
|
|
58
63
|
|
|
@@ -89,6 +94,10 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
89
94
|
dbStats,
|
|
90
95
|
);
|
|
91
96
|
|
|
97
|
+
this.addObjectCounter = this.meter.createUpDownCounter(metricsLabels.itemsAdded, {
|
|
98
|
+
description: 'The number of transactions added to the mempool',
|
|
99
|
+
});
|
|
100
|
+
|
|
92
101
|
this.meter.addBatchObservableCallback(this.observeStats, [this.objectsInMempool]);
|
|
93
102
|
}
|
|
94
103
|
|
|
@@ -96,6 +105,10 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
96
105
|
this.objectSize.record(poolObject.getSize());
|
|
97
106
|
}
|
|
98
107
|
|
|
108
|
+
public incrementAddedObjects(count: number) {
|
|
109
|
+
this.addObjectCounter.add(count);
|
|
110
|
+
}
|
|
111
|
+
|
|
99
112
|
private observeStats = async (observer: BatchObservableResult) => {
|
|
100
113
|
const { itemCount } = await this.poolStats();
|
|
101
114
|
if (typeof itemCount === 'number') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
3
|
import { toArray } from '@aztec/foundation/iterable';
|
|
3
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
@@ -6,7 +7,7 @@ import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap, AztecAsyncSi
|
|
|
6
7
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
7
8
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
8
9
|
import type { MerkleTreeReadOperations, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
|
-
import {
|
|
10
|
+
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
10
11
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
11
12
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
12
13
|
import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
@@ -37,7 +38,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
37
38
|
txPoolOverflowFactor: number = 1;
|
|
38
39
|
|
|
39
40
|
/** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
|
|
40
|
-
#minedTxHashToBlock: AztecAsyncMap<string,
|
|
41
|
+
#minedTxHashToBlock: AztecAsyncMap<string, BlockNumber>;
|
|
41
42
|
|
|
42
43
|
/** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */
|
|
43
44
|
#pendingTxPriorityToHash: AztecAsyncMultiMap<string, string>;
|
|
@@ -49,10 +50,10 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
49
50
|
#pendingTxHashToHeaderHash: AztecAsyncMap<string, string>;
|
|
50
51
|
|
|
51
52
|
/** Map from tx hash to the block number it was originally mined in (for soft-deleted txs). */
|
|
52
|
-
#deletedMinedTxHashes: AztecAsyncMap<string,
|
|
53
|
+
#deletedMinedTxHashes: AztecAsyncMap<string, BlockNumber>;
|
|
53
54
|
|
|
54
55
|
/** MultiMap from block number to deleted mined tx hashes for efficient cleanup. */
|
|
55
|
-
#blockToDeletedMinedTxHash: AztecAsyncMultiMap<
|
|
56
|
+
#blockToDeletedMinedTxHash: AztecAsyncMultiMap<BlockNumber, string>;
|
|
56
57
|
|
|
57
58
|
/** The cumulative tx size in bytes that the pending txs in the pool take up. */
|
|
58
59
|
#pendingTxSize: AztecAsyncSingleton<number>;
|
|
@@ -222,7 +223,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
222
223
|
return vals.map(TxHash.fromString);
|
|
223
224
|
}
|
|
224
225
|
|
|
225
|
-
public async getMinedTxHashes(): Promise<[TxHash,
|
|
226
|
+
public async getMinedTxHashes(): Promise<[TxHash, BlockNumber][]> {
|
|
226
227
|
const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
|
|
227
228
|
return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
|
|
228
229
|
}
|
|
@@ -273,6 +274,11 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
273
274
|
return await Promise.all(txHashes.map(txHash => this.#txs.hasAsync(txHash.toString())));
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
async hasTx(txHash: TxHash): Promise<boolean> {
|
|
278
|
+
const result = await this.hasTxs([txHash]);
|
|
279
|
+
return result[0];
|
|
280
|
+
}
|
|
281
|
+
|
|
276
282
|
/**
|
|
277
283
|
* Checks if an archived tx exists and returns it.
|
|
278
284
|
* @param txHash - The tx hash.
|
|
@@ -436,10 +442,10 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
436
442
|
* @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
|
|
437
443
|
* @returns The number of transactions permanently deleted.
|
|
438
444
|
*/
|
|
439
|
-
public async cleanupDeletedMinedTxs(blockNumber:
|
|
445
|
+
public async cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number> {
|
|
440
446
|
let deletedCount = 0;
|
|
441
447
|
const txHashesToDelete: string[] = [];
|
|
442
|
-
const blocksToDelete:
|
|
448
|
+
const blocksToDelete: BlockNumber[] = [];
|
|
443
449
|
|
|
444
450
|
await this.#store.transactionAsync(async () => {
|
|
445
451
|
// Iterate through all entries and check block numbers
|
|
@@ -546,7 +552,7 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
546
552
|
const archivedTx: Tx = new Tx(
|
|
547
553
|
tx.txHash,
|
|
548
554
|
tx.data,
|
|
549
|
-
|
|
555
|
+
ChonkProof.empty(),
|
|
550
556
|
tx.contractClassLogFields,
|
|
551
557
|
tx.publicFunctionCalldata,
|
|
552
558
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
3
4
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
@@ -18,10 +19,11 @@ export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter
|
|
|
18
19
|
* Our tx pool, stored as a Map in-memory, with K: tx hash and V: the transaction.
|
|
19
20
|
*/
|
|
20
21
|
private txs: Map<bigint, Tx>;
|
|
21
|
-
private minedTxs: Map<bigint,
|
|
22
|
+
private minedTxs: Map<bigint, BlockNumber>;
|
|
22
23
|
private pendingTxs: Set<bigint>;
|
|
23
|
-
private deletedMinedTxHashes: Map<bigint,
|
|
24
|
-
|
|
24
|
+
private deletedMinedTxHashes: Map<bigint, BlockNumber>;
|
|
25
|
+
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
26
|
+
private blockToDeletedMinedTxHash: Map<BlockNumber, Set<bigint>>;
|
|
25
27
|
|
|
26
28
|
private metrics: PoolInstrumentation<Tx>;
|
|
27
29
|
|
|
@@ -108,7 +110,7 @@ export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter
|
|
|
108
110
|
});
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
public getMinedTxHashes(): Promise<[TxHash,
|
|
113
|
+
public getMinedTxHashes(): Promise<[TxHash, BlockNumber][]> {
|
|
112
114
|
return Promise.resolve(
|
|
113
115
|
Array.from(this.minedTxs.entries()).map(([txHash, blockNumber]) => [TxHash.fromBigInt(txHash), blockNumber]),
|
|
114
116
|
);
|
|
@@ -151,6 +153,11 @@ export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter
|
|
|
151
153
|
return Promise.resolve(txHashes.map(txHash => this.txs.has(txHash.toBigInt())));
|
|
152
154
|
}
|
|
153
155
|
|
|
156
|
+
async hasTx(txHash: TxHash): Promise<boolean> {
|
|
157
|
+
const result = await this.hasTxs([txHash]);
|
|
158
|
+
return result[0];
|
|
159
|
+
}
|
|
160
|
+
|
|
154
161
|
public getArchivedTxByHash(): Promise<Tx | undefined> {
|
|
155
162
|
return Promise.resolve(undefined);
|
|
156
163
|
}
|
|
@@ -248,9 +255,9 @@ export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter
|
|
|
248
255
|
* @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
|
|
249
256
|
* @returns The number of transactions permanently deleted.
|
|
250
257
|
*/
|
|
251
|
-
public cleanupDeletedMinedTxs(blockNumber:
|
|
258
|
+
public cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number> {
|
|
252
259
|
let deletedCount = 0;
|
|
253
|
-
const blocksToDelete:
|
|
260
|
+
const blocksToDelete: BlockNumber[] = [];
|
|
254
261
|
|
|
255
262
|
// Find all blocks up to the specified block number
|
|
256
263
|
for (const [block, txHashes] of this.blockToDeletedMinedTxHash.entries()) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
2
3
|
import type { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
3
4
|
|
|
@@ -43,6 +44,13 @@ export interface TxPool extends TypedEventEmitter<TxPoolEvents> {
|
|
|
43
44
|
*/
|
|
44
45
|
hasTxs(txHashes: TxHash[]): Promise<boolean[]>;
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a transaction exists in the pool
|
|
49
|
+
* @param txHash - The hash of the transaction to check for
|
|
50
|
+
* @returns True if the transaction exists, false otherwise
|
|
51
|
+
*/
|
|
52
|
+
hasTx(txHash: TxHash): Promise<boolean>;
|
|
53
|
+
|
|
46
54
|
/**
|
|
47
55
|
* Checks if an archived transaction exists in the pool and returns it.
|
|
48
56
|
* @param txHash - The hash of the transaction, used as an ID.
|
|
@@ -95,7 +103,7 @@ export interface TxPool extends TypedEventEmitter<TxPoolEvents> {
|
|
|
95
103
|
* Gets the hashes of mined transactions currently in the tx pool.
|
|
96
104
|
* @returns An array of mined transaction hashes found in the tx pool.
|
|
97
105
|
*/
|
|
98
|
-
getMinedTxHashes(): Promise<[tx: TxHash, blockNumber:
|
|
106
|
+
getMinedTxHashes(): Promise<[tx: TxHash, blockNumber: BlockNumber][]>;
|
|
99
107
|
|
|
100
108
|
/**
|
|
101
109
|
* Returns whether the given tx hash is flagged as pending, mined, or deleted.
|
|
@@ -124,5 +132,5 @@ export interface TxPool extends TypedEventEmitter<TxPoolEvents> {
|
|
|
124
132
|
* @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
|
|
125
133
|
* @returns The number of transactions permanently deleted.
|
|
126
134
|
*/
|
|
127
|
-
cleanupDeletedMinedTxs(blockNumber:
|
|
135
|
+
cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number>;
|
|
128
136
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { unfreeze } from '@aztec/foundation/types';
|
|
2
3
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
3
4
|
import { mockTx } from '@aztec/stdlib/testing';
|
|
@@ -13,7 +14,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
13
14
|
let pool: TxPool;
|
|
14
15
|
|
|
15
16
|
const minedBlockHeader = BlockHeader.empty({
|
|
16
|
-
globalVariables: GlobalVariables.empty({ blockNumber: 1, timestamp: 0n }),
|
|
17
|
+
globalVariables: GlobalVariables.empty({ blockNumber: BlockNumber(1), timestamp: 0n }),
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
beforeEach(() => {
|
|
@@ -261,7 +262,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
261
262
|
await pool.deleteTxs([txs[0].getTxHash(), txs[1].getTxHash()]);
|
|
262
263
|
|
|
263
264
|
// Clean up deleted mined txs from block 1 and earlier
|
|
264
|
-
const deletedCount = await pool.cleanupDeletedMinedTxs(1);
|
|
265
|
+
const deletedCount = await pool.cleanupDeletedMinedTxs(BlockNumber(1));
|
|
265
266
|
|
|
266
267
|
// Verify old transactions are permanently deleted
|
|
267
268
|
expect(deletedCount).toBe(2);
|
|
@@ -276,7 +277,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
276
277
|
|
|
277
278
|
// Mark as mined in block 2
|
|
278
279
|
const laterBlockHeader = BlockHeader.empty({
|
|
279
|
-
globalVariables: GlobalVariables.empty({ blockNumber: 2, timestamp: 0n }),
|
|
280
|
+
globalVariables: GlobalVariables.empty({ blockNumber: BlockNumber(2), timestamp: 0n }),
|
|
280
281
|
});
|
|
281
282
|
await pool.markAsMined([txs[0].getTxHash()], laterBlockHeader);
|
|
282
283
|
|
|
@@ -284,7 +285,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
284
285
|
await pool.deleteTxs([txs[0].getTxHash()]);
|
|
285
286
|
|
|
286
287
|
// Try to clean up with block 1 (before the mined block)
|
|
287
|
-
const deletedCount = await pool.cleanupDeletedMinedTxs(1);
|
|
288
|
+
const deletedCount = await pool.cleanupDeletedMinedTxs(BlockNumber(1));
|
|
288
289
|
|
|
289
290
|
// Verify no transactions were cleaned up
|
|
290
291
|
expect(deletedCount).toBe(0);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { NoCommitteeError } from '@aztec/ethereum';
|
|
2
|
+
import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { type BlockAttestation, type P2PValidator, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
5
5
|
|
|
6
6
|
export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
protected epochCache: EpochCacheInterface;
|
|
8
|
+
protected logger: Logger;
|
|
9
9
|
|
|
10
10
|
constructor(epochCache: EpochCacheInterface) {
|
|
11
11
|
this.epochCache = epochCache;
|
|
@@ -13,47 +13,45 @@ export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
async validate(message: BlockAttestation): Promise<PeerErrorSeverity | undefined> {
|
|
16
|
-
const
|
|
16
|
+
const slotNumber = message.payload.header.slotNumber;
|
|
17
17
|
|
|
18
18
|
try {
|
|
19
19
|
const { currentProposer, nextProposer, currentSlot, nextSlot } =
|
|
20
20
|
await this.epochCache.getProposerAttesterAddressInCurrentOrNextSlot();
|
|
21
21
|
|
|
22
|
-
if (
|
|
23
|
-
this.logger.warn(
|
|
24
|
-
`Attestation slot ${slotNumberBigInt} is not current (${currentSlot}) or next (${nextSlot}) slot`,
|
|
25
|
-
);
|
|
22
|
+
if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
|
|
23
|
+
this.logger.warn(`Attestation slot ${slotNumber} is not current (${currentSlot}) or next (${nextSlot}) slot`);
|
|
26
24
|
return PeerErrorSeverity.HighToleranceError;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
// Verify the signature is valid
|
|
30
28
|
const attester = message.getSender();
|
|
31
29
|
if (attester === undefined) {
|
|
32
|
-
this.logger.warn(`Invalid signature in attestation for slot ${
|
|
30
|
+
this.logger.warn(`Invalid signature in attestation for slot ${slotNumber}`);
|
|
33
31
|
return PeerErrorSeverity.LowToleranceError;
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
// Verify the attester is in the committee for this slot
|
|
37
|
-
if (!(await this.epochCache.isInCommittee(
|
|
38
|
-
this.logger.warn(`Attester ${attester.toString()} is not in committee for slot ${
|
|
35
|
+
if (!(await this.epochCache.isInCommittee(slotNumber, attester))) {
|
|
36
|
+
this.logger.warn(`Attester ${attester.toString()} is not in committee for slot ${slotNumber}`);
|
|
39
37
|
return PeerErrorSeverity.HighToleranceError;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
// Verify the proposer signature matches the expected proposer for this slot
|
|
43
41
|
const proposer = message.getProposer();
|
|
44
|
-
const expectedProposer =
|
|
42
|
+
const expectedProposer = slotNumber === currentSlot ? currentProposer : nextProposer;
|
|
45
43
|
if (!expectedProposer) {
|
|
46
|
-
this.logger.warn(`No proposer defined for slot ${
|
|
44
|
+
this.logger.warn(`No proposer defined for slot ${slotNumber}`);
|
|
47
45
|
return PeerErrorSeverity.HighToleranceError;
|
|
48
46
|
}
|
|
49
47
|
if (!proposer) {
|
|
50
|
-
this.logger.warn(`Invalid proposer signature in attestation for slot ${
|
|
48
|
+
this.logger.warn(`Invalid proposer signature in attestation for slot ${slotNumber}`);
|
|
51
49
|
return PeerErrorSeverity.LowToleranceError;
|
|
52
50
|
}
|
|
53
51
|
if (!proposer.equals(expectedProposer)) {
|
|
54
52
|
this.logger.warn(
|
|
55
53
|
`Proposer signature mismatch in attestation. ` +
|
|
56
|
-
`Expected ${expectedProposer?.toString() ?? 'none'} but got ${proposer.toString()} for slot ${
|
|
54
|
+
`Expected ${expectedProposer?.toString() ?? 'none'} but got ${proposer.toString()} for slot ${slotNumber}`,
|
|
57
55
|
);
|
|
58
56
|
return PeerErrorSeverity.HighToleranceError;
|
|
59
57
|
}
|
|
@@ -62,7 +60,7 @@ export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
|
62
60
|
} catch (e) {
|
|
63
61
|
// People shouldn't be sending us attestations if the committee doesn't exist
|
|
64
62
|
if (e instanceof NoCommitteeError) {
|
|
65
|
-
this.logger.warn(`No committee exists for attestation for slot ${
|
|
63
|
+
this.logger.warn(`No committee exists for attestation for slot ${slotNumber}`);
|
|
66
64
|
return PeerErrorSeverity.LowToleranceError;
|
|
67
65
|
}
|
|
68
66
|
throw e;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
+
import { type BlockAttestation, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
|
+
import { Attributes, Metrics, type TelemetryClient, ValueType } from '@aztec/telemetry-client';
|
|
4
|
+
|
|
5
|
+
import type { AttestationPool } from '../../mem_pools/attestation_pool/attestation_pool.js';
|
|
6
|
+
import { AttestationValidator } from './attestation_validator.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* FishermanAttestationValidator extends the base AttestationValidator to add
|
|
10
|
+
* additional validation for fisherman nodes: verifying that attestations sign
|
|
11
|
+
* the same payload as the original proposal.
|
|
12
|
+
* Invalid attestations are rejected (not propagated), but peer penalization is
|
|
13
|
+
* handled by LibP2PService based on the fishermanMode config to ensure a better
|
|
14
|
+
* view of the network.
|
|
15
|
+
*/
|
|
16
|
+
export class FishermanAttestationValidator extends AttestationValidator {
|
|
17
|
+
private invalidAttestationCounter;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
epochCache: EpochCacheInterface,
|
|
21
|
+
private attestationPool: AttestationPool,
|
|
22
|
+
telemetryClient: TelemetryClient,
|
|
23
|
+
) {
|
|
24
|
+
super(epochCache);
|
|
25
|
+
this.logger = this.logger.createChild('[FISHERMAN]');
|
|
26
|
+
|
|
27
|
+
const meter = telemetryClient.getMeter('FishermanAttestationValidator');
|
|
28
|
+
this.invalidAttestationCounter = meter.createUpDownCounter(Metrics.VALIDATOR_INVALID_ATTESTATION_RECEIVED_COUNT, {
|
|
29
|
+
description: 'The number of invalid attestations received',
|
|
30
|
+
valueType: ValueType.INT,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override async validate(message: BlockAttestation): Promise<PeerErrorSeverity | undefined> {
|
|
35
|
+
// First run the standard validation
|
|
36
|
+
const baseValidationResult = await super.validate(message);
|
|
37
|
+
if (baseValidationResult !== undefined) {
|
|
38
|
+
// Track base validation failures (invalid signature, wrong committee, etc.)
|
|
39
|
+
this.invalidAttestationCounter.add(1, {
|
|
40
|
+
[Attributes.ERROR_TYPE]: 'base_validation_failed',
|
|
41
|
+
});
|
|
42
|
+
return baseValidationResult;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// fisherman validation: verify attestation payload matches proposal payload
|
|
46
|
+
const slotNumberBigInt = message.payload.header.slotNumber;
|
|
47
|
+
const attester = message.getSender();
|
|
48
|
+
const proposer = message.getProposer();
|
|
49
|
+
|
|
50
|
+
if (!attester || !proposer) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const proposalId = message.archive.toString();
|
|
55
|
+
const proposal = await this.attestationPool.getBlockProposal(proposalId);
|
|
56
|
+
|
|
57
|
+
if (proposal) {
|
|
58
|
+
// Compare the attestation payload with the proposal payload
|
|
59
|
+
if (!message.payload.equals(proposal.payload)) {
|
|
60
|
+
this.logger.error(
|
|
61
|
+
`Attestation payload mismatch for slot ${slotNumberBigInt}! ` +
|
|
62
|
+
`Attester ${attester.toString()} signed different data than the proposal.`,
|
|
63
|
+
{
|
|
64
|
+
slot: slotNumberBigInt.toString(),
|
|
65
|
+
attester: attester.toString(),
|
|
66
|
+
proposer: proposer.toString(),
|
|
67
|
+
proposalArchive: proposal.archive.toString(),
|
|
68
|
+
attestationArchive: message.archive.toString(),
|
|
69
|
+
proposalHeader: proposal.payload.header.hash().toString(),
|
|
70
|
+
attestationHeader: message.payload.header.hash().toString(),
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Track invalid attestation metric
|
|
75
|
+
this.invalidAttestationCounter.add(1, {
|
|
76
|
+
[Attributes.ERROR_TYPE]: 'payload_mismatch',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Return error to reject the message, but LibP2PService won't penalize in fisherman mode
|
|
80
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
// We might receive attestations before proposals in some cases
|
|
84
|
+
this.logger.debug(
|
|
85
|
+
`Received attestation for slot ${slotNumberBigInt} but proposal not found yet. ` + `Proposal ID: ${proposalId}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|