@aztec/p2p 0.0.1-commit.f504929 → 0.0.1-commit.f81dbcf
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 +1 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +7 -2
- 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 +8 -26
- package/dest/config.d.ts +24 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +65 -6
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +1 -5
- package/dest/mem_pools/instrumentation.d.ts +2 -4
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +14 -16
- package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
- package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/priority.js +4 -4
- 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 +3 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
- 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/interfaces.js +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +13 -4
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +26 -9
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +0 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -2
- 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 +2 -11
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +46 -44
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
- package/dest/msg_validators/tx_validator/factory.d.ts +15 -4
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +21 -8
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
- package/dest/msg_validators/tx_validator/index.d.ts +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -0
- package/dest/msg_validators/tx_validator/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 +21 -1
- package/dest/services/libp2p/libp2p_service.d.ts +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +20 -14
- package/dest/services/peer-manager/metrics.d.ts +1 -3
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +0 -6
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +1 -2
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +37 -14
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +11 -17
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +15 -49
- 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 +1 -2
- package/dest/test-helpers/testbench-utils.d.ts +1 -1
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +2 -1
- package/dest/testbench/p2p_client_testbench_worker.js +2 -1
- package/dest/testbench/worker_client_manager.d.ts +3 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +4 -1
- package/package.json +14 -14
- package/src/client/factory.ts +7 -1
- package/src/client/p2p_client.ts +5 -26
- package/src/config.ts +92 -4
- package/src/mem_pools/attestation_pool/attestation_pool.ts +4 -5
- package/src/mem_pools/instrumentation.ts +13 -17
- package/src/mem_pools/tx_pool/priority.ts +4 -4
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
- package/src/mem_pools/tx_pool_v2/README.md +9 -1
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
- package/src/mem_pools/tx_pool_v2/interfaces.ts +3 -3
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +37 -7
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +0 -3
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +3 -12
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
- package/src/msg_validators/proposal_validator/proposal_validator.ts +57 -48
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/factory.ts +22 -2
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +29 -0
- package/src/services/libp2p/libp2p_service.ts +21 -13
- package/src/services/peer-manager/metrics.ts +0 -7
- package/src/services/peer-manager/peer_manager.ts +1 -2
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +42 -14
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +24 -63
- package/src/services/reqresp/reqresp.ts +1 -3
- package/src/test-helpers/testbench-utils.ts +1 -0
- package/src/testbench/p2p_client_testbench_worker.ts +1 -0
- package/src/testbench/worker_client_manager.ts +11 -4
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
3
|
SecretValue,
|
|
4
|
+
bigintConfigHelper,
|
|
4
5
|
booleanConfigHelper,
|
|
5
6
|
getConfigFromMappings,
|
|
6
7
|
getDefaultConfig,
|
|
@@ -39,6 +40,18 @@ export interface P2PConfig
|
|
|
39
40
|
TxCollectionConfig,
|
|
40
41
|
TxFileStoreConfig,
|
|
41
42
|
Pick<SequencerConfig, 'blockDurationMs' | 'expectedBlockProposalsPerSlot' | 'maxTxsPerBlock'> {
|
|
43
|
+
/** Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set. */
|
|
44
|
+
validateMaxTxsPerBlock?: number;
|
|
45
|
+
|
|
46
|
+
/** Maximum transactions per checkpoint for validation. Used as fallback for maxTxsPerBlock when that is not set. */
|
|
47
|
+
validateMaxTxsPerCheckpoint?: number;
|
|
48
|
+
|
|
49
|
+
/** Maximum L2 gas per block for validation. When set, txs exceeding this limit are rejected. */
|
|
50
|
+
validateMaxL2BlockGas?: number;
|
|
51
|
+
|
|
52
|
+
/** Maximum DA gas per block for validation. When set, txs exceeding this limit are rejected. */
|
|
53
|
+
validateMaxDABlockGas?: number;
|
|
54
|
+
|
|
42
55
|
/** A flag dictating whether the P2P subsystem should be enabled. */
|
|
43
56
|
p2pEnabled: boolean;
|
|
44
57
|
|
|
@@ -173,7 +186,10 @@ export interface P2PConfig
|
|
|
173
186
|
/** Whether transactions are disabled for this node. This means transactions will be rejected at the RPC and P2P layers. */
|
|
174
187
|
disableTransactions: boolean;
|
|
175
188
|
|
|
176
|
-
/**
|
|
189
|
+
/** True to simulate discarding transactions. - For testing purposes only*/
|
|
190
|
+
dropTransactions: boolean;
|
|
191
|
+
|
|
192
|
+
/** The probability that a transaction is discarded. - For testing purposes only */
|
|
177
193
|
dropTransactionsProbability: number;
|
|
178
194
|
|
|
179
195
|
/** Whether to delete transactions from the pool after a reorg instead of moving them back to pending. */
|
|
@@ -190,11 +206,36 @@ export interface P2PConfig
|
|
|
190
206
|
|
|
191
207
|
/** Minimum age (ms) a transaction must have been in the pool before it's eligible for block building. */
|
|
192
208
|
minTxPoolAgeMs: number;
|
|
209
|
+
|
|
210
|
+
/** Minimum percentage fee increase required to replace an existing tx via RPC (0 = no bump). */
|
|
211
|
+
priceBumpPercentage: bigint;
|
|
193
212
|
}
|
|
194
213
|
|
|
195
214
|
export const DEFAULT_P2P_PORT = 40400;
|
|
196
215
|
|
|
197
216
|
export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
217
|
+
validateMaxTxsPerBlock: {
|
|
218
|
+
env: 'VALIDATOR_MAX_TX_PER_BLOCK',
|
|
219
|
+
description:
|
|
220
|
+
'Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set.',
|
|
221
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
222
|
+
},
|
|
223
|
+
validateMaxTxsPerCheckpoint: {
|
|
224
|
+
env: 'VALIDATOR_MAX_TX_PER_CHECKPOINT',
|
|
225
|
+
description:
|
|
226
|
+
'Maximum transactions per checkpoint for validation. Used as fallback for maxTxsPerBlock when that is not set.',
|
|
227
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
228
|
+
},
|
|
229
|
+
validateMaxL2BlockGas: {
|
|
230
|
+
env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
|
|
231
|
+
description: 'Maximum L2 gas per block for validation. When set, txs exceeding this limit are rejected.',
|
|
232
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
233
|
+
},
|
|
234
|
+
validateMaxDABlockGas: {
|
|
235
|
+
env: 'VALIDATOR_MAX_DA_BLOCK_GAS',
|
|
236
|
+
description: 'Maximum DA gas per block for validation. When set, txs exceeding this limit are rejected.',
|
|
237
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
238
|
+
},
|
|
198
239
|
p2pEnabled: {
|
|
199
240
|
env: 'P2P_ENABLED',
|
|
200
241
|
description: 'A flag dictating whether the P2P subsystem should be enabled.',
|
|
@@ -397,9 +438,9 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
397
438
|
env: 'TX_PUBLIC_SETUP_ALLOWLIST',
|
|
398
439
|
parseEnv: (val: string) => parseAllowList(val),
|
|
399
440
|
description:
|
|
400
|
-
'Additional entries to extend the default setup allow list. Format: I:address:selector,C:classId:selector',
|
|
441
|
+
'Additional entries to extend the default setup allow list. Format: I:address:selector[:flags],C:classId:selector[:flags]. Flags: os (onlySelf), rn (rejectNullMsgSender), cl=N (calldataLength), joined with +.',
|
|
401
442
|
printDefault: () =>
|
|
402
|
-
'Default: AuthRegistry._set_authorized,
|
|
443
|
+
'Default: AuthRegistry._set_authorized, AuthRegistry.set_authorized, FeeJuice._increase_public_balance',
|
|
403
444
|
},
|
|
404
445
|
maxPendingTxCount: {
|
|
405
446
|
env: 'P2P_MAX_PENDING_TX_COUNT',
|
|
@@ -428,6 +469,11 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
428
469
|
description: 'Number of auth attempts to allow before peer is banned. Number is inclusive',
|
|
429
470
|
...numberConfigHelper(3),
|
|
430
471
|
},
|
|
472
|
+
dropTransactions: {
|
|
473
|
+
env: 'P2P_DROP_TX',
|
|
474
|
+
description: 'True to simulate discarding transactions. - For testing purposes only',
|
|
475
|
+
...booleanConfigHelper(false),
|
|
476
|
+
},
|
|
431
477
|
dropTransactionsProbability: {
|
|
432
478
|
env: 'P2P_DROP_TX_CHANCE',
|
|
433
479
|
description: 'The probability that a transaction is discarded (0 - 1). - For testing purposes only',
|
|
@@ -465,6 +511,12 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
465
511
|
description: 'Minimum age (ms) a transaction must have been in the pool before it is eligible for block building.',
|
|
466
512
|
...numberConfigHelper(2_000),
|
|
467
513
|
},
|
|
514
|
+
priceBumpPercentage: {
|
|
515
|
+
env: 'P2P_RPC_PRICE_BUMP_PERCENTAGE',
|
|
516
|
+
description:
|
|
517
|
+
'Minimum percentage fee increase required to replace an existing tx via RPC. Even at 0%, replacement still requires paying at least 1 unit more.',
|
|
518
|
+
...bigintConfigHelper(10n),
|
|
519
|
+
},
|
|
468
520
|
...sharedSequencerConfigMappings,
|
|
469
521
|
...p2pReqRespConfigMappings,
|
|
470
522
|
...batchTxRequesterConfigMappings,
|
|
@@ -522,12 +574,45 @@ export const bootnodeConfigMappings = pickConfigMappings(
|
|
|
522
574
|
bootnodeConfigKeys,
|
|
523
575
|
);
|
|
524
576
|
|
|
577
|
+
/**
|
|
578
|
+
* Parses a `+`-separated flags string into validation properties for an allow list entry.
|
|
579
|
+
* Supported flags: `os` (onlySelf), `rn` (rejectNullMsgSender), `cl=N` (calldataLength).
|
|
580
|
+
*/
|
|
581
|
+
function parseFlags(
|
|
582
|
+
flags: string,
|
|
583
|
+
entry: string,
|
|
584
|
+
): { onlySelf?: boolean; rejectNullMsgSender?: boolean; calldataLength?: number } {
|
|
585
|
+
const result: { onlySelf?: boolean; rejectNullMsgSender?: boolean; calldataLength?: number } = {};
|
|
586
|
+
for (const flag of flags.split('+')) {
|
|
587
|
+
if (flag === 'os') {
|
|
588
|
+
result.onlySelf = true;
|
|
589
|
+
} else if (flag === 'rn') {
|
|
590
|
+
result.rejectNullMsgSender = true;
|
|
591
|
+
} else if (flag.startsWith('cl=')) {
|
|
592
|
+
const n = parseInt(flag.slice(3), 10);
|
|
593
|
+
if (isNaN(n) || n < 0) {
|
|
594
|
+
throw new Error(
|
|
595
|
+
`Invalid allow list entry "${entry}": invalid calldataLength in flag "${flag}". Expected a non-negative integer.`,
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
result.calldataLength = n;
|
|
599
|
+
} else {
|
|
600
|
+
throw new Error(`Invalid allow list entry "${entry}": unknown flag "${flag}". Supported flags: os, rn, cl=N.`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return result;
|
|
604
|
+
}
|
|
605
|
+
|
|
525
606
|
/**
|
|
526
607
|
* Parses a string to a list of allowed elements.
|
|
527
608
|
* Each entry is expected to be of one of the following formats:
|
|
528
609
|
* `I:${address}:${selector}` — instance (contract address) with function selector
|
|
529
610
|
* `C:${classId}:${selector}` — class with function selector
|
|
530
611
|
*
|
|
612
|
+
* An optional flags segment can be appended after the selector:
|
|
613
|
+
* `I:${address}:${selector}:${flags}` or `C:${classId}:${selector}:${flags}`
|
|
614
|
+
* where flags is a `+`-separated list of: `os` (onlySelf), `rn` (rejectNullMsgSender), `cl=N` (calldataLength).
|
|
615
|
+
*
|
|
531
616
|
* @param value The string to parse
|
|
532
617
|
* @returns A list of allowed elements
|
|
533
618
|
*/
|
|
@@ -543,7 +628,7 @@ export function parseAllowList(value: string): AllowedElement[] {
|
|
|
543
628
|
if (!trimmed) {
|
|
544
629
|
continue;
|
|
545
630
|
}
|
|
546
|
-
const [typeString, identifierString, selectorString] = trimmed.split(':');
|
|
631
|
+
const [typeString, identifierString, selectorString, flagsString] = trimmed.split(':');
|
|
547
632
|
|
|
548
633
|
if (!selectorString) {
|
|
549
634
|
throw new Error(
|
|
@@ -552,16 +637,19 @@ export function parseAllowList(value: string): AllowedElement[] {
|
|
|
552
637
|
}
|
|
553
638
|
|
|
554
639
|
const selector = FunctionSelector.fromString(selectorString);
|
|
640
|
+
const flags = flagsString ? parseFlags(flagsString, trimmed) : {};
|
|
555
641
|
|
|
556
642
|
if (typeString === 'I') {
|
|
557
643
|
entries.push({
|
|
558
644
|
address: AztecAddress.fromString(identifierString),
|
|
559
645
|
selector,
|
|
646
|
+
...flags,
|
|
560
647
|
});
|
|
561
648
|
} else if (typeString === 'C') {
|
|
562
649
|
entries.push({
|
|
563
650
|
classId: Fr.fromHexString(identifierString),
|
|
564
651
|
selector,
|
|
652
|
+
...flags,
|
|
565
653
|
});
|
|
566
654
|
} else {
|
|
567
655
|
throw new Error(
|
|
@@ -359,10 +359,11 @@ export class AttestationPool {
|
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
const address = sender.toString();
|
|
362
|
-
const ownKey = this.getAttestationKey(slotNumber, proposalId, address);
|
|
363
362
|
|
|
364
|
-
await this.checkpointAttestations.set(
|
|
365
|
-
|
|
363
|
+
await this.checkpointAttestations.set(
|
|
364
|
+
this.getAttestationKey(slotNumber, proposalId, address),
|
|
365
|
+
attestation.toBuffer(),
|
|
366
|
+
);
|
|
366
367
|
|
|
367
368
|
this.log.debug(`Added own checkpoint attestation for slot ${slotNumber} from ${address}`, {
|
|
368
369
|
signature: attestation.signature.toString(),
|
|
@@ -428,7 +429,6 @@ export class AttestationPool {
|
|
|
428
429
|
const attestationEndKey = new Fr(oldestSlot).toString();
|
|
429
430
|
for await (const key of this.checkpointAttestations.keysAsync({ end: attestationEndKey })) {
|
|
430
431
|
await this.checkpointAttestations.delete(key);
|
|
431
|
-
this.metrics.trackMempoolItemRemoved(key);
|
|
432
432
|
numberOfAttestations++;
|
|
433
433
|
}
|
|
434
434
|
|
|
@@ -526,7 +526,6 @@ export class AttestationPool {
|
|
|
526
526
|
|
|
527
527
|
// Add the attestation
|
|
528
528
|
await this.checkpointAttestations.set(key, attestation.toBuffer());
|
|
529
|
-
this.metrics.trackMempoolItemAdded(key);
|
|
530
529
|
|
|
531
530
|
// Track this attestation in the per-signer-per-slot index for duplicate detection
|
|
532
531
|
const slotSignerKey = this.getSlotSignerKey(slotNumber, signerAddress);
|
|
@@ -73,7 +73,7 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
73
73
|
private defaultAttributes;
|
|
74
74
|
private meter: Meter;
|
|
75
75
|
|
|
76
|
-
private
|
|
76
|
+
private txAddedTimestamp: Map<bigint, number> = new Map<bigint, number>();
|
|
77
77
|
|
|
78
78
|
constructor(
|
|
79
79
|
telemetry: TelemetryClient,
|
|
@@ -114,26 +114,22 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
public transactionsAdded(transactions: Tx[]) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
public transactionsRemoved(hashes: Iterable<bigint> | Iterable<string>) {
|
|
121
|
-
for (const hash of hashes) {
|
|
122
|
-
this.trackMempoolItemRemoved(BigInt(hash));
|
|
117
|
+
const timestamp = Date.now();
|
|
118
|
+
for (const transaction of transactions) {
|
|
119
|
+
this.txAddedTimestamp.set(transaction.txHash.toBigInt(), timestamp);
|
|
123
120
|
}
|
|
124
121
|
}
|
|
125
122
|
|
|
126
|
-
public
|
|
127
|
-
this.mempoolItemAddedTimestamp.set(key, Date.now());
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public trackMempoolItemRemoved(key: bigint | string): void {
|
|
123
|
+
public transactionsRemoved(hashes: Iterable<bigint> | Iterable<string>) {
|
|
131
124
|
const timestamp = Date.now();
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
this.
|
|
135
|
-
if (addedAt
|
|
136
|
-
this.
|
|
125
|
+
for (const hash of hashes) {
|
|
126
|
+
const key = BigInt(hash);
|
|
127
|
+
const addedAt = this.txAddedTimestamp.get(key);
|
|
128
|
+
if (addedAt !== undefined) {
|
|
129
|
+
this.txAddedTimestamp.delete(key);
|
|
130
|
+
if (addedAt < timestamp) {
|
|
131
|
+
this.minedDelay.record(timestamp - addedAt);
|
|
132
|
+
}
|
|
137
133
|
}
|
|
138
134
|
}
|
|
139
135
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { minBigint } from '@aztec/foundation/bigint';
|
|
1
2
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
3
|
import type { Tx } from '@aztec/stdlib/tx';
|
|
3
4
|
|
|
@@ -11,10 +12,9 @@ export function getPendingTxPriority(tx: Tx): string {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Returns the priority of a tx.
|
|
15
|
+
* Returns the priority of a tx based on the L2 priority fee only, capped by the max fees per gas.
|
|
15
16
|
*/
|
|
16
17
|
export function getTxPriorityFee(tx: Tx): bigint {
|
|
17
|
-
const priorityFees = tx.getGasSettings()
|
|
18
|
-
|
|
19
|
-
return totalFees;
|
|
18
|
+
const { maxPriorityFeesPerGas: priorityFees, maxFeesPerGas } = tx.getGasSettings();
|
|
19
|
+
return minBigint(maxFeesPerGas.feePerL2Gas, priorityFees.feePerL2Gas);
|
|
20
20
|
}
|
|
@@ -204,7 +204,9 @@ export function describeTxPool(getTxPool: () => TxPool) {
|
|
|
204
204
|
|
|
205
205
|
it('returns pending tx hashes sorted by priority', async () => {
|
|
206
206
|
const withPriorityFee = (tx: Tx, fee: number) => {
|
|
207
|
-
unfreeze(tx.data.constants.txContext.gasSettings)
|
|
207
|
+
const gs = unfreeze(tx.data.constants.txContext.gasSettings);
|
|
208
|
+
gs.maxPriorityFeesPerGas = new GasFees(fee, fee);
|
|
209
|
+
gs.maxFeesPerGas = new GasFees(fee, fee);
|
|
208
210
|
return tx;
|
|
209
211
|
};
|
|
210
212
|
|
|
@@ -158,7 +158,7 @@ Checked before adding a transaction to the pending pool:
|
|
|
158
158
|
|
|
159
159
|
| Rule | Purpose |
|
|
160
160
|
|------|---------|
|
|
161
|
-
| `NullifierConflictRule` | Handles transactions with conflicting nullifiers. Higher priority tx wins. |
|
|
161
|
+
| `NullifierConflictRule` | Handles transactions with conflicting nullifiers. Higher priority tx wins. For RPC submissions, a configurable price bump percentage is required. |
|
|
162
162
|
| `FeePayerBalancePreAddRule` | Ensures fee payer has sufficient balance for all their pending txs. |
|
|
163
163
|
| `LowPriorityPreAddRule` | Rejects txs when pool is full and new tx has lowest priority. |
|
|
164
164
|
|
|
@@ -233,6 +233,14 @@ await pool.updateConfig({
|
|
|
233
233
|
});
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
### Price Bump (RPC Transaction Replacement)
|
|
237
|
+
|
|
238
|
+
When a transaction is submitted via RPC and clashes on nullifiers with an existing pool transaction, the incoming tx must pay at least `priceBumpPercentage`% more in priority fee (i.e. `>= existingFee + existingFee * bump / 100`) to replace it. This prevents spam via small fee increments. The same bump applies when the pool is full and the incoming tx needs to evict the lowest-priority tx.
|
|
239
|
+
|
|
240
|
+
- **Env var**: `P2P_RPC_PRICE_BUMP_PERCENTAGE` (default: 10)
|
|
241
|
+
- **Scope**: RPC submissions only. P2P gossip uses `comparePriority` (fee + hash tiebreaker) with no bump.
|
|
242
|
+
- Even with a 0% bump, a replacement tx must pay at least 1 unit more than the existing fee.
|
|
243
|
+
|
|
236
244
|
## Return Values
|
|
237
245
|
|
|
238
246
|
### AddTxsResult
|
|
@@ -100,7 +100,15 @@ export type TxPoolRejectionError =
|
|
|
100
100
|
availableBalance: bigint;
|
|
101
101
|
feeLimit: bigint;
|
|
102
102
|
}
|
|
103
|
-
| {
|
|
103
|
+
| {
|
|
104
|
+
code: typeof TxPoolRejectionCode.NULLIFIER_CONFLICT;
|
|
105
|
+
message: string;
|
|
106
|
+
conflictingTxHash: string;
|
|
107
|
+
/** Minimum fee needed to replace the conflicting tx (only set when price bump applies). */
|
|
108
|
+
minimumPriceBumpFee?: bigint;
|
|
109
|
+
/** Incoming tx's priority fee. */
|
|
110
|
+
txPriorityFee?: bigint;
|
|
111
|
+
}
|
|
104
112
|
| { code: typeof TxPoolRejectionCode.INTERNAL_ERROR; message: string };
|
|
105
113
|
|
|
106
114
|
/**
|
|
@@ -121,6 +129,8 @@ export interface PreAddResult {
|
|
|
121
129
|
export interface PreAddContext {
|
|
122
130
|
/** If true, compare priority fee only (no tx hash tiebreaker). Used for RPC submissions. */
|
|
123
131
|
feeComparisonOnly?: boolean;
|
|
132
|
+
/** Percentage-based price bump required for tx replacement. Only set for RPC submissions. */
|
|
133
|
+
priceBumpPercentage?: bigint;
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
|
|
3
|
-
import { type TxMetaData, comparePriority } from '../tx_metadata.js';
|
|
3
|
+
import { type TxMetaData, comparePriority, getMinimumPriceBumpFee } from '../tx_metadata.js';
|
|
4
4
|
import {
|
|
5
5
|
type EvictionConfig,
|
|
6
6
|
type PreAddContext,
|
|
@@ -48,10 +48,14 @@ export class LowPriorityPreAddRule implements PreAddRule {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// Compare incoming tx against lowest priority tx.
|
|
51
|
-
// feeOnly mode (RPC): use strict fee comparison only — avoids churn from hash ordering
|
|
52
|
-
//
|
|
51
|
+
// feeOnly mode (RPC): use strict fee comparison only — avoids churn from hash ordering.
|
|
52
|
+
// When price bump is also set, require the bumped fee threshold.
|
|
53
|
+
// Default (gossip): use full comparePriority (fee + tx hash tiebreaker) for determinism.
|
|
53
54
|
const isHigherPriority = context?.feeComparisonOnly
|
|
54
|
-
?
|
|
55
|
+
? context.priceBumpPercentage !== undefined
|
|
56
|
+
? incomingMeta.priorityFee >=
|
|
57
|
+
getMinimumPriceBumpFee(lowestPriorityMeta.priorityFee, context.priceBumpPercentage)
|
|
58
|
+
: incomingMeta.priorityFee > lowestPriorityMeta.priorityFee
|
|
55
59
|
: comparePriority(incomingMeta, lowestPriorityMeta) > 0;
|
|
56
60
|
|
|
57
61
|
if (isHigherPriority) {
|
|
@@ -66,6 +70,11 @@ export class LowPriorityPreAddRule implements PreAddRule {
|
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// Incoming tx has equal or lower priority - ignore it (it would be evicted anyway)
|
|
73
|
+
const minimumFee =
|
|
74
|
+
context?.feeComparisonOnly && context.priceBumpPercentage !== undefined
|
|
75
|
+
? getMinimumPriceBumpFee(lowestPriorityMeta.priorityFee, context.priceBumpPercentage)
|
|
76
|
+
: lowestPriorityMeta.priorityFee + 1n;
|
|
77
|
+
|
|
69
78
|
this.log.debug(
|
|
70
79
|
`Pool at capacity (${currentCount}/${this.maxPoolSize}), ignoring ${incomingMeta.txHash} ` +
|
|
71
80
|
`(priority ${incomingMeta.priorityFee}) - lower than existing minimum (priority ${lowestPriorityMeta.priorityFee})`,
|
|
@@ -75,8 +84,8 @@ export class LowPriorityPreAddRule implements PreAddRule {
|
|
|
75
84
|
txHashesToEvict: [],
|
|
76
85
|
reason: {
|
|
77
86
|
code: TxPoolRejectionCode.LOW_PRIORITY_FEE,
|
|
78
|
-
message: `Tx does not meet minimum priority fee. Required: ${
|
|
79
|
-
minimumPriorityFee:
|
|
87
|
+
message: `Tx does not meet minimum priority fee. Required: ${minimumFee}, got: ${incomingMeta.priorityFee}`,
|
|
88
|
+
minimumPriorityFee: minimumFee,
|
|
80
89
|
txPriorityFee: incomingMeta.priorityFee,
|
|
81
90
|
},
|
|
82
91
|
});
|
|
@@ -15,11 +15,12 @@ export class NullifierConflictRule implements PreAddRule {
|
|
|
15
15
|
|
|
16
16
|
private log = createLogger('p2p:tx_pool_v2:nullifier_conflict_rule');
|
|
17
17
|
|
|
18
|
-
check(incomingMeta: TxMetaData, poolAccess: PreAddPoolAccess,
|
|
18
|
+
check(incomingMeta: TxMetaData, poolAccess: PreAddPoolAccess, context?: PreAddContext): Promise<PreAddResult> {
|
|
19
19
|
const result = checkNullifierConflict(
|
|
20
20
|
incomingMeta,
|
|
21
21
|
nullifier => poolAccess.getTxHashByNullifier(nullifier),
|
|
22
22
|
txHash => poolAccess.getMetadata(txHash),
|
|
23
|
+
context?.priceBumpPercentage,
|
|
23
24
|
);
|
|
24
25
|
|
|
25
26
|
if (result.shouldIgnore) {
|
|
@@ -44,8 +44,8 @@ export type TxPoolV2Config = {
|
|
|
44
44
|
minTxPoolAgeMs: number;
|
|
45
45
|
/** Maximum number of evicted tx hashes to remember for metrics tracking */
|
|
46
46
|
evictedTxCacheSize: number;
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/** Minimum percentage fee increase required to replace an existing tx via RPC (0 = no bump). */
|
|
48
|
+
priceBumpPercentage: bigint;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -56,7 +56,7 @@ export const DEFAULT_TX_POOL_V2_CONFIG: TxPoolV2Config = {
|
|
|
56
56
|
archivedTxLimit: 0, // 0 = disabled
|
|
57
57
|
minTxPoolAgeMs: 2_000,
|
|
58
58
|
evictedTxCacheSize: 10_000,
|
|
59
|
-
|
|
59
|
+
priceBumpPercentage: 10n,
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -190,21 +190,38 @@ export function comparePriority(a: PriorityComparable, b: PriorityComparable): n
|
|
|
190
190
|
return compareTxHash(a.txHashBigInt, b.txHashBigInt);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Returns the minimum fee required to replace an existing tx with the given price bump percentage.
|
|
195
|
+
* Uses integer arithmetic: `existingFee + existingFee * priceBumpPercentage / 100`.
|
|
196
|
+
*/
|
|
197
|
+
export function getMinimumPriceBumpFee(existingFee: bigint, priceBumpPercentage: bigint): bigint {
|
|
198
|
+
const bump = (existingFee * priceBumpPercentage) / 100n;
|
|
199
|
+
// Ensure the minimum bump is at least 1, so that replacement always requires
|
|
200
|
+
// paying strictly more — even with 0% bump or zero existing fee.
|
|
201
|
+
const effectiveBump = bump > 0n ? bump : 1n;
|
|
202
|
+
return existingFee + effectiveBump;
|
|
203
|
+
}
|
|
204
|
+
|
|
193
205
|
/**
|
|
194
206
|
* Checks for nullifier conflicts between an incoming transaction and existing pool state.
|
|
195
207
|
*
|
|
196
208
|
* When the incoming tx shares nullifiers with existing pending txs:
|
|
197
|
-
* - If the incoming tx
|
|
198
|
-
* -
|
|
209
|
+
* - If the incoming tx meets or exceeds the required priority, mark conflicting txs for eviction
|
|
210
|
+
* - Otherwise, ignore the incoming tx
|
|
211
|
+
*
|
|
212
|
+
* When `priceBumpPercentage` is provided (RPC path), uses fee-only comparison with the
|
|
213
|
+
* percentage bump instead of `comparePriority`.
|
|
199
214
|
*
|
|
200
215
|
* @param incomingMeta - Metadata for the incoming transaction
|
|
201
216
|
* @param getTxHashByNullifier - Accessor to find which tx uses a nullifier
|
|
202
217
|
* @param getMetadata - Accessor to get metadata for a tx hash
|
|
218
|
+
* @param priceBumpPercentage - Optional percentage bump required for fee-based replacement
|
|
203
219
|
*/
|
|
204
220
|
export function checkNullifierConflict(
|
|
205
221
|
incomingMeta: TxMetaData,
|
|
206
222
|
getTxHashByNullifier: (nullifier: string) => string | undefined,
|
|
207
223
|
getMetadata: (txHash: string) => TxMetaData | undefined,
|
|
224
|
+
priceBumpPercentage?: bigint,
|
|
208
225
|
): PreAddResult {
|
|
209
226
|
const txHashesToEvict: string[] = [];
|
|
210
227
|
|
|
@@ -225,19 +242,32 @@ export function checkNullifierConflict(
|
|
|
225
242
|
continue;
|
|
226
243
|
}
|
|
227
244
|
|
|
228
|
-
//
|
|
229
|
-
// Otherwise,
|
|
230
|
-
|
|
231
|
-
|
|
245
|
+
// When price bump is set (RPC path), require the incoming fee to meet the bumped threshold.
|
|
246
|
+
// Otherwise (P2P path), use full comparePriority with tx hash tiebreaker.
|
|
247
|
+
const isHigherPriority =
|
|
248
|
+
priceBumpPercentage !== undefined
|
|
249
|
+
? incomingMeta.priorityFee >= getMinimumPriceBumpFee(conflictingMeta.priorityFee, priceBumpPercentage)
|
|
250
|
+
: comparePriority(incomingMeta, conflictingMeta) > 0;
|
|
251
|
+
|
|
252
|
+
if (isHigherPriority) {
|
|
232
253
|
txHashesToEvict.push(conflictingHashStr);
|
|
233
254
|
} else {
|
|
255
|
+
const minimumFee =
|
|
256
|
+
priceBumpPercentage !== undefined
|
|
257
|
+
? getMinimumPriceBumpFee(conflictingMeta.priorityFee, priceBumpPercentage)
|
|
258
|
+
: undefined;
|
|
234
259
|
return {
|
|
235
260
|
shouldIgnore: true,
|
|
236
261
|
txHashesToEvict: [],
|
|
237
262
|
reason: {
|
|
238
263
|
code: TxPoolRejectionCode.NULLIFIER_CONFLICT,
|
|
239
|
-
message:
|
|
264
|
+
message:
|
|
265
|
+
minimumFee !== undefined
|
|
266
|
+
? `Nullifier conflict with existing tx ${conflictingHashStr}. Minimum required fee: ${minimumFee}, got: ${incomingMeta.priorityFee}`
|
|
267
|
+
: `Nullifier conflict with existing tx ${conflictingHashStr}`,
|
|
240
268
|
conflictingTxHash: conflictingHashStr,
|
|
269
|
+
minimumPriceBumpFee: minimumFee,
|
|
270
|
+
txPriorityFee: minimumFee !== undefined ? incomingMeta.priorityFee : undefined,
|
|
241
271
|
},
|
|
242
272
|
};
|
|
243
273
|
}
|
|
@@ -58,9 +58,6 @@ export class AztecKVTxPoolV2 extends (EventEmitter as new () => TypedEventEmitte
|
|
|
58
58
|
const hashes = txHashes.map(h => (typeof h === 'string' ? TxHash.fromString(h) : TxHash.fromBigInt(h)));
|
|
59
59
|
this.emit('txs-removed', { txHashes: hashes });
|
|
60
60
|
},
|
|
61
|
-
onTxsMined: (txHashes: string[]) => {
|
|
62
|
-
this.#metrics?.transactionsRemoved(txHashes);
|
|
63
|
-
},
|
|
64
61
|
};
|
|
65
62
|
|
|
66
63
|
// Create the implementation
|
|
@@ -45,7 +45,6 @@ import { TxPoolIndices } from './tx_pool_indices.js';
|
|
|
45
45
|
export interface TxPoolV2Callbacks {
|
|
46
46
|
onTxsAdded: (txs: Tx[], opts: { source?: string }) => void;
|
|
47
47
|
onTxsRemoved: (txHashes: string[] | bigint[]) => void;
|
|
48
|
-
onTxsMined: (txHashes: string[]) => void;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -214,7 +213,9 @@ export class TxPoolV2Impl {
|
|
|
214
213
|
// in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
|
|
215
214
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
216
215
|
const preAddContext: PreAddContext | undefined =
|
|
217
|
-
opts.feeComparisonOnly !== undefined
|
|
216
|
+
opts.feeComparisonOnly !== undefined
|
|
217
|
+
? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
|
|
218
|
+
: undefined;
|
|
218
219
|
|
|
219
220
|
await this.#store.transactionAsync(async () => {
|
|
220
221
|
for (const tx of txs) {
|
|
@@ -336,12 +337,6 @@ export class TxPoolV2Impl {
|
|
|
336
337
|
}
|
|
337
338
|
}
|
|
338
339
|
|
|
339
|
-
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
340
|
-
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
341
|
-
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
342
|
-
return { status: 'accepted' };
|
|
343
|
-
}
|
|
344
|
-
|
|
345
340
|
// Add the transaction
|
|
346
341
|
await this.#addTx(tx, 'pending', opts, precomputedMeta);
|
|
347
342
|
return { status: 'accepted' };
|
|
@@ -499,10 +494,6 @@ export class TxPoolV2Impl {
|
|
|
499
494
|
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
500
495
|
});
|
|
501
496
|
|
|
502
|
-
if (found.length > 0) {
|
|
503
|
-
this.#callbacks.onTxsMined(found.map(m => m.txHash));
|
|
504
|
-
}
|
|
505
|
-
|
|
506
497
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
507
498
|
}
|
|
508
499
|
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type { BlockProposal, P2PValidator } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { BlockProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
3
3
|
|
|
4
4
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
5
|
|
|
6
|
-
export class BlockProposalValidator
|
|
6
|
+
export class BlockProposalValidator implements P2PValidator<BlockProposal> {
|
|
7
|
+
private proposalValidator: ProposalValidator;
|
|
8
|
+
|
|
7
9
|
constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
|
|
8
|
-
|
|
10
|
+
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async validate(proposal: BlockProposal): Promise<ValidationResult> {
|
|
14
|
+
const headerResult = await this.proposalValidator.validate(proposal);
|
|
15
|
+
if (headerResult.result !== 'accept') {
|
|
16
|
+
return headerResult;
|
|
17
|
+
}
|
|
18
|
+
return this.proposalValidator.validateTxs(proposal);
|
|
9
19
|
}
|
|
10
20
|
}
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type { CheckpointProposal, P2PValidator } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { CheckpointProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
3
3
|
|
|
4
4
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
5
|
|
|
6
|
-
export class CheckpointProposalValidator
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
6
|
+
export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
|
|
7
|
+
private proposalValidator: ProposalValidator;
|
|
8
|
+
|
|
10
9
|
constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
|
|
11
|
-
|
|
10
|
+
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async validate(proposal: CheckpointProposal): Promise<ValidationResult> {
|
|
14
|
+
const headerResult = await this.proposalValidator.validate(proposal);
|
|
15
|
+
if (headerResult.result !== 'accept') {
|
|
16
|
+
return headerResult;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const blockProposal = proposal.getBlockProposal();
|
|
20
|
+
if (blockProposal) {
|
|
21
|
+
return this.proposalValidator.validateTxs(blockProposal);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return { result: 'accept' };
|
|
12
25
|
}
|
|
13
26
|
}
|