@aztec/p2p 0.0.1-commit.f2ce05ee → 0.0.1-commit.f8ca9b2f3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/factory.d.ts +3 -3
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +38 -7
- package/dest/client/interface.d.ts +26 -15
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +31 -35
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +97 -138
- package/dest/config.d.ts +10 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +9 -0
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +18 -11
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +62 -37
- 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 +53 -53
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -1
- package/dest/mem_pools/index.d.ts +2 -1
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/interface.d.ts +3 -3
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +87 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +180 -0
- package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +25 -3
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +36 -4
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +77 -74
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +3 -3
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
- 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/services/dummy_service.d.ts +6 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +3 -0
- package/dest/services/encoding.d.ts +2 -2
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +2 -2
- package/dest/services/libp2p/libp2p_service.d.ts +11 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +71 -35
- package/dest/services/reqresp/interface.d.ts +10 -1
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +15 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +3 -3
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +7 -1
- 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 +15 -0
- package/dest/services/reqresp/protocols/tx.d.ts +7 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +20 -0
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +11 -4
- package/dest/services/service.d.ts +18 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +7 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +16 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +3 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +17 -3
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +44 -0
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_collection.js +118 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +27 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +57 -0
- 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/slow_tx_collection.d.ts +3 -1
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +48 -19
- package/dest/services/tx_collection/tx_collection.d.ts +17 -7
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +58 -2
- package/dest/services/tx_collection/tx_collection_sink.d.ts +15 -6
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +13 -7
- package/dest/services/tx_file_store/config.d.ts +1 -3
- package/dest/services/tx_file_store/config.d.ts.map +1 -1
- package/dest/services/tx_file_store/config.js +0 -4
- package/dest/services/tx_file_store/tx_file_store.d.ts +3 -3
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_provider.d.ts +3 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +5 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +3 -3
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.d.ts +27 -1
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +97 -2
- package/dest/test-helpers/testbench-utils.d.ts +30 -24
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +87 -35
- package/dest/testbench/p2p_client_testbench_worker.js +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +65 -8
- package/src/client/interface.ts +26 -13
- package/src/client/p2p_client.ts +123 -158
- package/src/config.ts +16 -0
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +87 -44
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +57 -53
- package/src/mem_pools/attestation_pool/index.ts +3 -3
- package/src/mem_pools/index.ts +3 -0
- package/src/mem_pools/interface.ts +2 -2
- package/src/mem_pools/tx_pool_v2/README.md +59 -9
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +234 -0
- package/src/mem_pools/tx_pool_v2/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +2 -2
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +51 -5
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +90 -77
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +2 -2
- package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
- package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
- package/src/msg_validators/tx_validator/timestamp_validator.ts +19 -14
- package/src/services/dummy_service.ts +6 -0
- package/src/services/encoding.ts +2 -2
- package/src/services/libp2p/libp2p_service.ts +70 -37
- package/src/services/reqresp/interface.ts +26 -1
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +2 -2
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +17 -0
- package/src/services/reqresp/protocols/tx.ts +22 -0
- package/src/services/reqresp/reqresp.ts +13 -3
- package/src/services/service.ts +20 -0
- package/src/services/tx_collection/config.ts +26 -0
- package/src/services/tx_collection/fast_tx_collection.ts +14 -2
- package/src/services/tx_collection/file_store_tx_collection.ts +152 -0
- package/src/services/tx_collection/file_store_tx_source.ts +70 -0
- package/src/services/tx_collection/index.ts +1 -0
- package/src/services/tx_collection/slow_tx_collection.ts +55 -26
- package/src/services/tx_collection/tx_collection.ts +78 -12
- package/src/services/tx_collection/tx_collection_sink.ts +17 -7
- package/src/services/tx_file_store/config.ts +0 -6
- package/src/services/tx_file_store/tx_file_store.ts +4 -4
- package/src/services/tx_provider.ts +8 -7
- package/src/test-helpers/make-test-p2p-clients.ts +3 -3
- package/src/test-helpers/mock-pubsub.ts +133 -3
- package/src/test-helpers/testbench-utils.ts +100 -40
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
|
@@ -19,13 +19,17 @@ export type TryAddResult = {
|
|
|
19
19
|
added: boolean;
|
|
20
20
|
/** Whether the exact item already existed */
|
|
21
21
|
alreadyExists: boolean;
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/** Count of items for the position. Meaning varies by method:
|
|
23
|
+
* - tryAddBlockProposal: proposals at (slot, indexWithinCheckpoint)
|
|
24
|
+
* - tryAddCheckpointProposal: proposals at slot
|
|
25
|
+
* - tryAddCheckpointAttestation: attestations by this signer for this slot */
|
|
26
|
+
count: number;
|
|
24
27
|
};
|
|
25
28
|
|
|
26
|
-
export const
|
|
27
|
-
export const
|
|
28
|
-
|
|
29
|
+
export const MAX_CHECKPOINT_PROPOSALS_PER_SLOT = 5;
|
|
30
|
+
export const MAX_BLOCK_PROPOSALS_PER_POSITION = 3;
|
|
31
|
+
/** Maximum attestations a single signer can make per slot before being rejected. */
|
|
32
|
+
export const MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER = 3;
|
|
29
33
|
|
|
30
34
|
/** Public API interface for attestation pools. Used for typing mocks and test implementations. */
|
|
31
35
|
export type AttestationPoolApi = Pick<
|
|
@@ -69,6 +73,10 @@ export class AttestationPool {
|
|
|
69
73
|
// Key: (slot << 10) | indexWithinCheckpoint, Value: archive string
|
|
70
74
|
private blockProposalsForSlotAndIndex: AztecAsyncMultiMap<number, string>;
|
|
71
75
|
|
|
76
|
+
// Checkpoint attestations indexed by (slot, signer) for tracking attestations per (slot, signer) for duplicate detection
|
|
77
|
+
// Key: `${Fr(slot).toString()}-${signerAddress}` string (padded for lexicographic ordering), Value: `proposalId` strings
|
|
78
|
+
private checkpointAttestationsPerSlotAndSigner: AztecAsyncMultiMap<string, string>;
|
|
79
|
+
|
|
72
80
|
constructor(
|
|
73
81
|
private store: AztecAsyncKVStore,
|
|
74
82
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
@@ -80,6 +88,7 @@ export class AttestationPool {
|
|
|
80
88
|
|
|
81
89
|
// Initialize checkpoint attestations storage
|
|
82
90
|
this.checkpointAttestations = store.openMap('checkpoint_attestations');
|
|
91
|
+
this.checkpointAttestationsPerSlotAndSigner = store.openMultiMap('checkpoint_attestations_per_slot_and_signer');
|
|
83
92
|
|
|
84
93
|
// Initialize checkpoint proposal storage
|
|
85
94
|
this.checkpointProposals = store.openMap('checkpoint_proposals');
|
|
@@ -133,6 +142,12 @@ export class AttestationPool {
|
|
|
133
142
|
return { start: `${proposalKey}-`, end: `${proposalKey}-Z` };
|
|
134
143
|
}
|
|
135
144
|
|
|
145
|
+
/** Creates a key for the per-signer-per-slot attestation index. Uses padded slot for lexicographic ordering. */
|
|
146
|
+
private getSlotSignerKey(slot: SlotNumber, signerAddress: string): string {
|
|
147
|
+
const slotStr = new Fr(slot).toString();
|
|
148
|
+
return `${slotStr}-${signerAddress}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
136
151
|
/** Number of bits reserved for indexWithinCheckpoint in position keys. */
|
|
137
152
|
private static readonly INDEX_BITS = 10;
|
|
138
153
|
/** Maximum indexWithinCheckpoint value (2^10 - 1 = 1023). */
|
|
@@ -166,21 +181,21 @@ export class AttestationPool {
|
|
|
166
181
|
// Check if already exists
|
|
167
182
|
const alreadyExists = await this.blockProposals.hasAsync(proposalId);
|
|
168
183
|
if (alreadyExists) {
|
|
169
|
-
const
|
|
184
|
+
const count = await this.getBlockProposalCountForPosition(
|
|
170
185
|
blockProposal.slotNumber,
|
|
171
186
|
blockProposal.indexWithinCheckpoint,
|
|
172
187
|
);
|
|
173
|
-
return { added: false, alreadyExists: true,
|
|
188
|
+
return { added: false, alreadyExists: true, count };
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
// Get current count for position and check cap, do not add if exceeded
|
|
177
|
-
const
|
|
192
|
+
const count = await this.getBlockProposalCountForPosition(
|
|
178
193
|
blockProposal.slotNumber,
|
|
179
194
|
blockProposal.indexWithinCheckpoint,
|
|
180
195
|
);
|
|
181
196
|
|
|
182
|
-
if (
|
|
183
|
-
return { added: false, alreadyExists: false,
|
|
197
|
+
if (count >= MAX_BLOCK_PROPOSALS_PER_POSITION) {
|
|
198
|
+
return { added: false, alreadyExists: false, count };
|
|
184
199
|
}
|
|
185
200
|
|
|
186
201
|
// Add the proposal
|
|
@@ -195,7 +210,7 @@ export class AttestationPool {
|
|
|
195
210
|
},
|
|
196
211
|
);
|
|
197
212
|
|
|
198
|
-
return { added: true, alreadyExists: false,
|
|
213
|
+
return { added: true, alreadyExists: false, count: count + 1 };
|
|
199
214
|
});
|
|
200
215
|
}
|
|
201
216
|
|
|
@@ -261,14 +276,14 @@ export class AttestationPool {
|
|
|
261
276
|
// Check if already exists
|
|
262
277
|
const alreadyExists = await this.checkpointProposals.hasAsync(proposalId);
|
|
263
278
|
if (alreadyExists) {
|
|
264
|
-
const
|
|
265
|
-
return { added: false, alreadyExists: true,
|
|
279
|
+
const count = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
|
|
280
|
+
return { added: false, alreadyExists: true, count };
|
|
266
281
|
}
|
|
267
282
|
|
|
268
283
|
// Get current count for slot and check cap
|
|
269
|
-
const
|
|
270
|
-
if (
|
|
271
|
-
return { added: false, alreadyExists: false,
|
|
284
|
+
const count = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
|
|
285
|
+
if (count >= MAX_CHECKPOINT_PROPOSALS_PER_SLOT) {
|
|
286
|
+
return { added: false, alreadyExists: false, count };
|
|
272
287
|
}
|
|
273
288
|
|
|
274
289
|
// Add the proposal if cap not exceeded
|
|
@@ -279,7 +294,7 @@ export class AttestationPool {
|
|
|
279
294
|
slotNumber: proposal.slotNumber,
|
|
280
295
|
});
|
|
281
296
|
|
|
282
|
-
return { added: true, alreadyExists: false,
|
|
297
|
+
return { added: true, alreadyExists: false, count: count + 1 };
|
|
283
298
|
});
|
|
284
299
|
}
|
|
285
300
|
|
|
@@ -409,6 +424,14 @@ export class AttestationPool {
|
|
|
409
424
|
numberOfAttestations++;
|
|
410
425
|
}
|
|
411
426
|
|
|
427
|
+
// Clean up per-signer-per-slot index. Keys are formatted as `${Fr(slot).toString()}-${signerAddress}`.
|
|
428
|
+
// Since Fr pads to fixed-width hex, Fr(oldestSlot) is lexicographically greater than any key with
|
|
429
|
+
// a smaller slot (even with the signer suffix), so using it as the exclusive end bound is correct.
|
|
430
|
+
const slotSignerEndKey = new Fr(oldestSlot).toString();
|
|
431
|
+
for await (const key of this.checkpointAttestationsPerSlotAndSigner.keysAsync({ end: slotSignerEndKey })) {
|
|
432
|
+
await this.checkpointAttestationsPerSlotAndSigner.delete(key);
|
|
433
|
+
}
|
|
434
|
+
|
|
412
435
|
// Delete checkpoint proposals for slots < oldestSlot, using checkpointProposalsForSlot as index
|
|
413
436
|
for await (const slot of this.checkpointProposalsForSlot.keysAsync({ end: oldestSlot })) {
|
|
414
437
|
const proposalIds = await toArray(this.checkpointProposalsForSlot.getValuesAsync(slot));
|
|
@@ -445,61 +468,81 @@ export class AttestationPool {
|
|
|
445
468
|
*
|
|
446
469
|
* This method performs validation and addition in a single call:
|
|
447
470
|
* - Checks if the attestation already exists (returns alreadyExists: true if so)
|
|
448
|
-
* - Checks if
|
|
471
|
+
* - Checks if this signer has reached the per-signer attestation cap for this slot
|
|
449
472
|
* - Adds the attestation if validation passes
|
|
450
473
|
*
|
|
451
474
|
* @param attestation - The checkpoint attestation to add
|
|
452
|
-
* @
|
|
453
|
-
*
|
|
475
|
+
* @returns Result indicating whether the attestation was added, existence info, and count of
|
|
476
|
+
* attestations by this signer for this slot (for equivocation detection)
|
|
454
477
|
*/
|
|
455
|
-
public async tryAddCheckpointAttestation(
|
|
456
|
-
attestation: CheckpointAttestation,
|
|
457
|
-
committeeSize: number,
|
|
458
|
-
): Promise<TryAddResult> {
|
|
478
|
+
public async tryAddCheckpointAttestation(attestation: CheckpointAttestation): Promise<TryAddResult> {
|
|
459
479
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
460
480
|
const proposalId = attestation.archive.toString();
|
|
461
481
|
const sender = attestation.getSender();
|
|
462
482
|
|
|
463
483
|
if (!sender) {
|
|
464
|
-
return { added: false, alreadyExists: false,
|
|
484
|
+
return { added: false, alreadyExists: false, count: 0 };
|
|
465
485
|
}
|
|
466
486
|
|
|
487
|
+
const signerAddress = sender.toString();
|
|
488
|
+
|
|
467
489
|
return await this.store.transactionAsync(async () => {
|
|
468
|
-
const key = this.getAttestationKey(slotNumber, proposalId,
|
|
490
|
+
const key = this.getAttestationKey(slotNumber, proposalId, signerAddress);
|
|
469
491
|
const alreadyExists = await this.checkpointAttestations.hasAsync(key);
|
|
470
492
|
|
|
493
|
+
// Get count of attestations by this signer for this slot (for duplicate detection)
|
|
494
|
+
const signerAttestationCount = await this.getSignerAttestationCountForSlot(slotNumber, signerAddress);
|
|
495
|
+
|
|
471
496
|
if (alreadyExists) {
|
|
472
|
-
|
|
473
|
-
|
|
497
|
+
return {
|
|
498
|
+
added: false,
|
|
499
|
+
alreadyExists: true,
|
|
500
|
+
count: signerAttestationCount,
|
|
501
|
+
};
|
|
474
502
|
}
|
|
475
503
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
504
|
+
// Check if this signer has exceeded the per-signer cap for this slot
|
|
505
|
+
if (signerAttestationCount >= MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER) {
|
|
506
|
+
this.log.debug(`Rejecting attestation: signer ${signerAddress} exceeded per-slot cap for slot ${slotNumber}`, {
|
|
507
|
+
slotNumber,
|
|
508
|
+
signerAddress,
|
|
509
|
+
proposalId,
|
|
510
|
+
signerAttestationCount,
|
|
511
|
+
});
|
|
512
|
+
return {
|
|
513
|
+
added: false,
|
|
514
|
+
alreadyExists: false,
|
|
515
|
+
count: signerAttestationCount,
|
|
516
|
+
};
|
|
481
517
|
}
|
|
482
518
|
|
|
519
|
+
// Add the attestation
|
|
483
520
|
await this.checkpointAttestations.set(key, attestation.toBuffer());
|
|
484
521
|
|
|
485
|
-
this
|
|
522
|
+
// Track this attestation in the per-signer-per-slot index for duplicate detection
|
|
523
|
+
const slotSignerKey = this.getSlotSignerKey(slotNumber, signerAddress);
|
|
524
|
+
await this.checkpointAttestationsPerSlotAndSigner.set(slotSignerKey, proposalId);
|
|
525
|
+
|
|
526
|
+
this.log.debug(`Added checkpoint attestation for slot ${slotNumber} from ${signerAddress}`, {
|
|
486
527
|
signature: attestation.signature.toString(),
|
|
487
528
|
slotNumber,
|
|
488
|
-
address:
|
|
529
|
+
address: signerAddress,
|
|
489
530
|
proposalId,
|
|
490
531
|
});
|
|
491
|
-
|
|
532
|
+
|
|
533
|
+
// Return the new count
|
|
534
|
+
return {
|
|
535
|
+
added: true,
|
|
536
|
+
alreadyExists: false,
|
|
537
|
+
count: signerAttestationCount + 1,
|
|
538
|
+
};
|
|
492
539
|
});
|
|
493
540
|
}
|
|
494
541
|
|
|
495
|
-
/** Gets the count of attestations for a given
|
|
496
|
-
private async
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
for await (const _ of this.checkpointAttestations.keysAsync(range)) {
|
|
500
|
-
count++;
|
|
501
|
-
}
|
|
502
|
-
return count;
|
|
542
|
+
/** Gets the count of attestations by a specific signer for a given slot. */
|
|
543
|
+
private async getSignerAttestationCountForSlot(slot: SlotNumber, signerAddress: string): Promise<number> {
|
|
544
|
+
const slotSignerKey = this.getSlotSignerKey(slot, signerAddress);
|
|
545
|
+
return await this.checkpointAttestationsPerSlotAndSigner.getValueCountAsync(slotSignerKey);
|
|
503
546
|
}
|
|
504
547
|
}
|
|
505
548
|
|
|
@@ -10,7 +10,11 @@ import {
|
|
|
10
10
|
makeCheckpointProposal,
|
|
11
11
|
} from '@aztec/stdlib/testing';
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
type AttestationPool,
|
|
15
|
+
MAX_BLOCK_PROPOSALS_PER_POSITION,
|
|
16
|
+
MAX_CHECKPOINT_PROPOSALS_PER_SLOT,
|
|
17
|
+
} from './attestation_pool.js';
|
|
14
18
|
import { mockCheckpointAttestation } from './mocks.js';
|
|
15
19
|
|
|
16
20
|
const NUMBER_OF_SIGNERS_PER_TEST = 4;
|
|
@@ -191,7 +195,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
191
195
|
|
|
192
196
|
expect(result.added).toBe(true);
|
|
193
197
|
expect(result.alreadyExists).toBe(false);
|
|
194
|
-
expect(result.
|
|
198
|
+
expect(result.count).toBe(1);
|
|
195
199
|
|
|
196
200
|
const retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
197
201
|
|
|
@@ -258,7 +262,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
258
262
|
|
|
259
263
|
expect(result.added).toBe(true);
|
|
260
264
|
expect(result.alreadyExists).toBe(false);
|
|
261
|
-
expect(result.
|
|
265
|
+
expect(result.count).toBe(1);
|
|
262
266
|
|
|
263
267
|
const retrievedProposal = await ap.getCheckpointProposal(proposalId);
|
|
264
268
|
|
|
@@ -324,12 +328,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
324
328
|
it('should return added=false when exceeding capacity', async () => {
|
|
325
329
|
const slotNumber = 420;
|
|
326
330
|
|
|
327
|
-
// Add
|
|
328
|
-
for (let i = 0; i <
|
|
331
|
+
// Add MAX_CHECKPOINT_PROPOSALS_PER_SLOT proposals
|
|
332
|
+
for (let i = 0; i < MAX_CHECKPOINT_PROPOSALS_PER_SLOT; i++) {
|
|
329
333
|
const proposal = await mockCheckpointProposalForPool(signers[i % NUMBER_OF_SIGNERS_PER_TEST], slotNumber);
|
|
330
334
|
const result = await ap.tryAddCheckpointProposal(proposal);
|
|
331
335
|
expect(result.added).toBe(true);
|
|
332
|
-
expect(result.
|
|
336
|
+
expect(result.count).toBe(i + 1);
|
|
333
337
|
}
|
|
334
338
|
|
|
335
339
|
// The next proposal should not be added
|
|
@@ -337,7 +341,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
337
341
|
const result = await ap.tryAddCheckpointProposal(extraProposal);
|
|
338
342
|
expect(result.added).toBe(false);
|
|
339
343
|
expect(result.alreadyExists).toBe(false);
|
|
340
|
-
expect(result.
|
|
344
|
+
expect(result.count).toBe(MAX_CHECKPOINT_PROPOSALS_PER_SLOT);
|
|
341
345
|
});
|
|
342
346
|
});
|
|
343
347
|
|
|
@@ -358,13 +362,13 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
358
362
|
};
|
|
359
363
|
|
|
360
364
|
describe('tryAddBlockProposal duplicate detection', () => {
|
|
361
|
-
it('should return
|
|
365
|
+
it('should return count=1 when pool is empty', async () => {
|
|
362
366
|
const proposal = await mockBlockProposalWithIndex(signers[0], 100, 0);
|
|
363
367
|
const result = await ap.tryAddBlockProposal(proposal);
|
|
364
368
|
|
|
365
369
|
expect(result.added).toBe(true);
|
|
366
370
|
expect(result.alreadyExists).toBe(false);
|
|
367
|
-
expect(result.
|
|
371
|
+
expect(result.count).toBe(1);
|
|
368
372
|
});
|
|
369
373
|
|
|
370
374
|
it('should return alreadyExists when same proposal exists', async () => {
|
|
@@ -375,17 +379,17 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
375
379
|
|
|
376
380
|
expect(result.added).toBe(false);
|
|
377
381
|
expect(result.alreadyExists).toBe(true);
|
|
378
|
-
expect(result.
|
|
382
|
+
expect(result.count).toBe(1);
|
|
379
383
|
});
|
|
380
384
|
|
|
381
|
-
it('should detect duplicate via
|
|
385
|
+
it('should detect duplicate via count when different proposal exists at same position', async () => {
|
|
382
386
|
const slotNumber = 100;
|
|
383
387
|
const indexWithinCheckpoint = 2;
|
|
384
388
|
|
|
385
389
|
// Add first proposal
|
|
386
390
|
const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
|
|
387
391
|
const result1 = await ap.tryAddBlockProposal(proposal1);
|
|
388
|
-
expect(result1.
|
|
392
|
+
expect(result1.count).toBe(1);
|
|
389
393
|
|
|
390
394
|
// Add a different proposal at same position - this is a duplicate (equivocation)
|
|
391
395
|
const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
|
|
@@ -393,8 +397,8 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
393
397
|
|
|
394
398
|
expect(result2.added).toBe(true);
|
|
395
399
|
expect(result2.alreadyExists).toBe(false);
|
|
396
|
-
//
|
|
397
|
-
expect(result2.
|
|
400
|
+
// count >= 2 indicates duplicate detection
|
|
401
|
+
expect(result2.count).toBe(2);
|
|
398
402
|
});
|
|
399
403
|
|
|
400
404
|
it('should not detect duplicate for different positions in same slot', async () => {
|
|
@@ -409,8 +413,8 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
409
413
|
const result = await ap.tryAddBlockProposal(proposal2);
|
|
410
414
|
|
|
411
415
|
expect(result.added).toBe(true);
|
|
412
|
-
//
|
|
413
|
-
expect(result.
|
|
416
|
+
// count = 1 means no duplicate for this position
|
|
417
|
+
expect(result.count).toBe(1);
|
|
414
418
|
});
|
|
415
419
|
|
|
416
420
|
it('should not detect duplicate for same position in different slots', async () => {
|
|
@@ -425,37 +429,37 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
425
429
|
const result = await ap.tryAddBlockProposal(proposal2);
|
|
426
430
|
|
|
427
431
|
expect(result.added).toBe(true);
|
|
428
|
-
//
|
|
429
|
-
expect(result.
|
|
432
|
+
// count = 1 means no duplicate for this position
|
|
433
|
+
expect(result.count).toBe(1);
|
|
430
434
|
});
|
|
431
435
|
|
|
432
|
-
it('should track multiple duplicates correctly via
|
|
436
|
+
it('should track multiple duplicates correctly via count', async () => {
|
|
433
437
|
const slotNumber = 100;
|
|
434
438
|
const indexWithinCheckpoint = 0;
|
|
435
439
|
|
|
436
440
|
// Add multiple proposals for same position
|
|
437
441
|
const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
|
|
438
442
|
const result1 = await ap.tryAddBlockProposal(proposal1);
|
|
439
|
-
expect(result1.
|
|
443
|
+
expect(result1.count).toBe(1);
|
|
440
444
|
|
|
441
445
|
const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
|
|
442
446
|
const result2 = await ap.tryAddBlockProposal(proposal2);
|
|
443
|
-
expect(result2.
|
|
447
|
+
expect(result2.count).toBe(2);
|
|
444
448
|
|
|
445
449
|
// Add a third proposal for same position
|
|
446
450
|
const proposal3 = await mockBlockProposalWithIndex(signers[2], slotNumber, indexWithinCheckpoint);
|
|
447
451
|
const result3 = await ap.tryAddBlockProposal(proposal3);
|
|
448
452
|
|
|
449
453
|
expect(result3.added).toBe(true);
|
|
450
|
-
expect(result3.
|
|
454
|
+
expect(result3.count).toBe(3);
|
|
451
455
|
});
|
|
452
456
|
|
|
453
457
|
it('should return added=false when exceeding capacity', async () => {
|
|
454
458
|
const slotNumber = 100;
|
|
455
459
|
const indexWithinCheckpoint = 0;
|
|
456
460
|
|
|
457
|
-
// Add
|
|
458
|
-
for (let i = 0; i <
|
|
461
|
+
// Add MAX_BLOCK_PROPOSALS_PER_POSITION proposals
|
|
462
|
+
for (let i = 0; i < MAX_BLOCK_PROPOSALS_PER_POSITION; i++) {
|
|
459
463
|
const proposal = await mockBlockProposalWithIndex(
|
|
460
464
|
signers[i % NUMBER_OF_SIGNERS_PER_TEST],
|
|
461
465
|
slotNumber,
|
|
@@ -463,7 +467,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
463
467
|
);
|
|
464
468
|
const result = await ap.tryAddBlockProposal(proposal);
|
|
465
469
|
expect(result.added).toBe(true);
|
|
466
|
-
expect(result.
|
|
470
|
+
expect(result.count).toBe(i + 1);
|
|
467
471
|
}
|
|
468
472
|
|
|
469
473
|
// The next proposal should not be added
|
|
@@ -471,7 +475,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
471
475
|
const result = await ap.tryAddBlockProposal(extraProposal);
|
|
472
476
|
expect(result.added).toBe(false);
|
|
473
477
|
expect(result.alreadyExists).toBe(false);
|
|
474
|
-
expect(result.
|
|
478
|
+
expect(result.count).toBe(MAX_BLOCK_PROPOSALS_PER_POSITION);
|
|
475
479
|
});
|
|
476
480
|
|
|
477
481
|
it('should clean up block position index when deleting old data', async () => {
|
|
@@ -482,18 +486,18 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
482
486
|
const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
|
|
483
487
|
await ap.tryAddBlockProposal(proposal1);
|
|
484
488
|
|
|
485
|
-
// Verify it's tracked (adding another should show
|
|
489
|
+
// Verify it's tracked (adding another should show count = 2)
|
|
486
490
|
const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
|
|
487
491
|
let result = await ap.tryAddBlockProposal(proposal2);
|
|
488
|
-
expect(result.
|
|
492
|
+
expect(result.count).toBe(2);
|
|
489
493
|
|
|
490
494
|
// Delete old data
|
|
491
495
|
await ap.deleteOlderThan(SlotNumber(slotNumber + 1));
|
|
492
496
|
|
|
493
|
-
// Verify position index is cleaned up (
|
|
497
|
+
// Verify position index is cleaned up (count should be 1 now)
|
|
494
498
|
const proposal3 = await mockBlockProposalWithIndex(signers[2], slotNumber, indexWithinCheckpoint);
|
|
495
499
|
result = await ap.tryAddBlockProposal(proposal3);
|
|
496
|
-
expect(result.
|
|
500
|
+
expect(result.count).toBe(1);
|
|
497
501
|
});
|
|
498
502
|
|
|
499
503
|
it('should correctly delete block proposals at slot boundary', async () => {
|
|
@@ -514,16 +518,16 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
514
518
|
// Slot 99 proposals should have their index cleaned up
|
|
515
519
|
const newProposal99 = await mockBlockProposalWithIndex(signers[0], 99, 0);
|
|
516
520
|
const result99 = await ap.tryAddBlockProposal(newProposal99);
|
|
517
|
-
expect(result99.
|
|
521
|
+
expect(result99.count).toBe(1); // Index was cleaned up
|
|
518
522
|
|
|
519
523
|
// Slot 100 and 101 should still be tracked
|
|
520
524
|
const newProposal100 = await mockBlockProposalWithIndex(signers[1], 100, 0);
|
|
521
525
|
const result100 = await ap.tryAddBlockProposal(newProposal100);
|
|
522
|
-
expect(result100.
|
|
526
|
+
expect(result100.count).toBe(2); // Still has the original
|
|
523
527
|
|
|
524
528
|
const newProposal101 = await mockBlockProposalWithIndex(signers[2], 101, 0);
|
|
525
529
|
const result101 = await ap.tryAddBlockProposal(newProposal101);
|
|
526
|
-
expect(result101.
|
|
530
|
+
expect(result101.count).toBe(2); // Still has the original
|
|
527
531
|
});
|
|
528
532
|
|
|
529
533
|
it('should delete all indices for a given slot', async () => {
|
|
@@ -544,15 +548,15 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
544
548
|
// All indices should be cleaned up
|
|
545
549
|
const newProposal0 = await mockBlockProposalWithIndex(signers[0], slotNumber, 0);
|
|
546
550
|
const result0 = await ap.tryAddBlockProposal(newProposal0);
|
|
547
|
-
expect(result0.
|
|
551
|
+
expect(result0.count).toBe(1);
|
|
548
552
|
|
|
549
553
|
const newProposal1 = await mockBlockProposalWithIndex(signers[1], slotNumber, 1);
|
|
550
554
|
const result1 = await ap.tryAddBlockProposal(newProposal1);
|
|
551
|
-
expect(result1.
|
|
555
|
+
expect(result1.count).toBe(1);
|
|
552
556
|
|
|
553
557
|
const newProposal2 = await mockBlockProposalWithIndex(signers[2], slotNumber, 2);
|
|
554
558
|
const result2 = await ap.tryAddBlockProposal(newProposal2);
|
|
555
|
-
expect(result2.
|
|
559
|
+
expect(result2.count).toBe(1);
|
|
556
560
|
});
|
|
557
561
|
|
|
558
562
|
it('should delete block proposals from storage when deleting old data', async () => {
|
|
@@ -598,13 +602,13 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
598
602
|
return proposal.toCore();
|
|
599
603
|
};
|
|
600
604
|
|
|
601
|
-
it('should return
|
|
605
|
+
it('should return count=1 when pool is empty', async () => {
|
|
602
606
|
const proposal = await mockCheckpointProposalCoreForPool(signers[0], 100);
|
|
603
607
|
const result = await ap.tryAddCheckpointProposal(proposal);
|
|
604
608
|
|
|
605
609
|
expect(result.added).toBe(true);
|
|
606
610
|
expect(result.alreadyExists).toBe(false);
|
|
607
|
-
expect(result.
|
|
611
|
+
expect(result.count).toBe(1);
|
|
608
612
|
});
|
|
609
613
|
|
|
610
614
|
it('should return alreadyExists when same proposal exists', async () => {
|
|
@@ -615,16 +619,16 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
615
619
|
|
|
616
620
|
expect(result.added).toBe(false);
|
|
617
621
|
expect(result.alreadyExists).toBe(true);
|
|
618
|
-
expect(result.
|
|
622
|
+
expect(result.count).toBe(1);
|
|
619
623
|
});
|
|
620
624
|
|
|
621
|
-
it('should detect duplicate via
|
|
625
|
+
it('should detect duplicate via count when different proposal exists for same slot', async () => {
|
|
622
626
|
const slotNumber = 100;
|
|
623
627
|
|
|
624
628
|
// Add first proposal
|
|
625
629
|
const proposal1 = await mockCheckpointProposalCoreForPool(signers[0], slotNumber);
|
|
626
630
|
const result1 = await ap.tryAddCheckpointProposal(proposal1);
|
|
627
|
-
expect(result1.
|
|
631
|
+
expect(result1.count).toBe(1);
|
|
628
632
|
|
|
629
633
|
// Add a different proposal for same slot - this is a duplicate (equivocation)
|
|
630
634
|
const proposal2 = await mockCheckpointProposalCoreForPool(signers[1], slotNumber);
|
|
@@ -632,8 +636,8 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
632
636
|
|
|
633
637
|
expect(result2.added).toBe(true);
|
|
634
638
|
expect(result2.alreadyExists).toBe(false);
|
|
635
|
-
//
|
|
636
|
-
expect(result2.
|
|
639
|
+
// count >= 2 indicates duplicate detection
|
|
640
|
+
expect(result2.count).toBe(2);
|
|
637
641
|
});
|
|
638
642
|
|
|
639
643
|
it('should not detect duplicate for different slots', async () => {
|
|
@@ -646,28 +650,28 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
646
650
|
const result = await ap.tryAddCheckpointProposal(proposal2);
|
|
647
651
|
|
|
648
652
|
expect(result.added).toBe(true);
|
|
649
|
-
//
|
|
650
|
-
expect(result.
|
|
653
|
+
// count = 1 means no duplicate for this slot
|
|
654
|
+
expect(result.count).toBe(1);
|
|
651
655
|
});
|
|
652
656
|
|
|
653
|
-
it('should track multiple duplicates correctly via
|
|
657
|
+
it('should track multiple duplicates correctly via count', async () => {
|
|
654
658
|
const slotNumber = 100;
|
|
655
659
|
|
|
656
660
|
// Add multiple proposals for same slot
|
|
657
661
|
const proposal1 = await mockCheckpointProposalCoreForPool(signers[0], slotNumber);
|
|
658
662
|
const result1 = await ap.tryAddCheckpointProposal(proposal1);
|
|
659
|
-
expect(result1.
|
|
663
|
+
expect(result1.count).toBe(1);
|
|
660
664
|
|
|
661
665
|
const proposal2 = await mockCheckpointProposalCoreForPool(signers[1], slotNumber);
|
|
662
666
|
const result2 = await ap.tryAddCheckpointProposal(proposal2);
|
|
663
|
-
expect(result2.
|
|
667
|
+
expect(result2.count).toBe(2);
|
|
664
668
|
|
|
665
669
|
// Add a third proposal for same slot
|
|
666
670
|
const proposal3 = await mockCheckpointProposalCoreForPool(signers[2], slotNumber);
|
|
667
671
|
const result3 = await ap.tryAddCheckpointProposal(proposal3);
|
|
668
672
|
|
|
669
673
|
expect(result3.added).toBe(true);
|
|
670
|
-
expect(result3.
|
|
674
|
+
expect(result3.count).toBe(3);
|
|
671
675
|
});
|
|
672
676
|
|
|
673
677
|
it('should not count attestations as proposals for duplicate detection', async () => {
|
|
@@ -684,8 +688,8 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
684
688
|
|
|
685
689
|
expect(result.added).toBe(true);
|
|
686
690
|
expect(result.alreadyExists).toBe(false);
|
|
687
|
-
//
|
|
688
|
-
expect(result.
|
|
691
|
+
// count should be 1, NOT 2 - attestations should not count as proposals
|
|
692
|
+
expect(result.count).toBe(1);
|
|
689
693
|
});
|
|
690
694
|
|
|
691
695
|
it('should not count attestations for different proposals as duplicates', async () => {
|
|
@@ -703,14 +707,14 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
703
707
|
const result1 = await ap.tryAddCheckpointProposal(proposal1);
|
|
704
708
|
|
|
705
709
|
expect(result1.added).toBe(true);
|
|
706
|
-
expect(result1.
|
|
710
|
+
expect(result1.count).toBe(1);
|
|
707
711
|
|
|
708
712
|
// Add the second checkpoint proposal - this IS a duplicate (different archive, same slot)
|
|
709
713
|
const proposal2 = await mockCheckpointProposalCoreForPool(signers[3], slotNumber, archive2);
|
|
710
714
|
const result2 = await ap.tryAddCheckpointProposal(proposal2);
|
|
711
715
|
|
|
712
716
|
expect(result2.added).toBe(true);
|
|
713
|
-
expect(result2.
|
|
717
|
+
expect(result2.count).toBe(2);
|
|
714
718
|
});
|
|
715
719
|
});
|
|
716
720
|
});
|
|
@@ -3,7 +3,7 @@ export {
|
|
|
3
3
|
type AttestationPoolApi,
|
|
4
4
|
type TryAddResult,
|
|
5
5
|
createTestAttestationPool,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
MAX_CHECKPOINT_PROPOSALS_PER_SLOT,
|
|
7
|
+
MAX_BLOCK_PROPOSALS_PER_POSITION,
|
|
8
|
+
MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER,
|
|
9
9
|
} from './attestation_pool.js';
|
package/src/mem_pools/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export { AttestationPool, type AttestationPoolApi } from './attestation_pool/attestation_pool.js';
|
|
2
2
|
export { type MemPools } from './interface.js';
|
|
3
|
+
// Old TxPool exports - kept temporarily for external consumers
|
|
3
4
|
export { type TxPool } from './tx_pool/tx_pool.js';
|
|
5
|
+
// New TxPoolV2 exports
|
|
6
|
+
export { type TxPoolV2, type TxPoolV2Config, type TxPoolV2Events, type AddTxsResult } from './tx_pool_v2/index.js';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AttestationPoolApi } from './attestation_pool/attestation_pool.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TxPoolV2 } from './tx_pool_v2/interfaces.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A interface the combines all mempools
|
|
6
6
|
*/
|
|
7
7
|
export type MemPools = {
|
|
8
|
-
txPool:
|
|
8
|
+
txPool: TxPoolV2;
|
|
9
9
|
attestationPool: AttestationPoolApi;
|
|
10
10
|
};
|