@aztec/p2p 0.0.1-commit.e588bc7e5 → 0.0.1-commit.e5a3663dd
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 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +17 -16
- package/dest/client/p2p_client.d.ts +1 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +9 -2
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +4 -1
- package/dest/config.d.ts +107 -99
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +16 -7
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -2
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +5 -3
- package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +6 -4
- package/dest/mem_pools/instrumentation.d.ts +1 -1
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +17 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +4 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +5 -2
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +8 -5
- 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 +2 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +9 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +34 -10
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +7 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
- package/dest/msg_validators/clock_tolerance.d.ts +12 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +57 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +8 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +41 -9
- package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts +2 -2
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +3 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +36 -4
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +50 -33
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +5 -5
- package/dest/services/dummy_service.d.ts +2 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +1 -0
- package/dest/services/gossipsub/topic_score_params.d.ts +13 -2
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +21 -4
- 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 +14 -0
- package/dest/services/libp2p/libp2p_service.d.ts +7 -18
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +52 -74
- 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 +15 -2
- package/dest/services/peer-manager/peer_scoring.d.ts +3 -1
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +4 -0
- package/dest/services/reqresp/config.d.ts +3 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/interface.d.ts +14 -9
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +10 -11
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +0 -1
- package/dest/services/reqresp/protocols/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/tx.d.ts +1 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +1 -3
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
- package/dest/services/reqresp/reqresp.d.ts +4 -2
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +11 -2
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +4 -1
- package/dest/test-helpers/mock-pubsub.d.ts +11 -3
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +36 -11
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +5 -3
- 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 +1 -0
- package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +29 -2
- package/dest/testbench/worker_client_manager.d.ts +8 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +49 -0
- package/package.json +14 -14
- package/src/client/factory.ts +24 -19
- package/src/client/p2p_client.ts +11 -3
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +2 -0
- package/src/config.ts +28 -7
- package/src/mem_pools/attestation_pool/attestation_pool.ts +5 -3
- package/src/mem_pools/attestation_pool/mocks.ts +13 -8
- package/src/mem_pools/instrumentation.ts +5 -1
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +1 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/interfaces.ts +3 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +13 -7
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +2 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +38 -7
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +12 -2
- package/src/msg_validators/clock_tolerance.ts +75 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +11 -2
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +16 -2
- package/src/msg_validators/proposal_validator/proposal_validator.ts +47 -7
- package/src/msg_validators/tx_validator/README.md +11 -3
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/factory.ts +3 -1
- package/src/msg_validators/tx_validator/gas_validator.ts +82 -33
- package/src/services/data_store.ts +5 -13
- package/src/services/dummy_service.ts +1 -0
- package/src/services/gossipsub/topic_score_params.ts +36 -4
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +52 -70
- package/src/services/peer-manager/peer_manager.ts +17 -2
- package/src/services/peer-manager/peer_scoring.ts +6 -0
- package/src/services/reqresp/config.ts +2 -2
- package/src/services/reqresp/interface.ts +21 -11
- package/src/services/reqresp/metrics.ts +0 -1
- package/src/services/reqresp/protocols/index.ts +0 -1
- package/src/services/reqresp/protocols/tx.ts +1 -3
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +18 -1
- package/src/test-helpers/make-test-p2p-clients.ts +2 -0
- package/src/test-helpers/mock-pubsub.ts +34 -5
- package/src/test-helpers/reqresp-nodes.ts +4 -2
- package/src/test-helpers/testbench-utils.ts +1 -0
- package/src/testbench/p2p_client_testbench_worker.ts +30 -0
- package/src/testbench/worker_client_manager.ts +55 -0
- package/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -32
- package/src/services/reqresp/protocols/block.ts +0 -37
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
3
3
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
4
4
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
5
5
|
|
|
@@ -33,14 +33,14 @@ export class InvalidTxsAfterReorgRule implements EvictionRule {
|
|
|
33
33
|
const pendingTxs = pool.getPendingTxs();
|
|
34
34
|
|
|
35
35
|
// Deduplicate block hashes to reduce redundant DB lookups
|
|
36
|
-
const uniqueBlockHashes = new Map<string,
|
|
36
|
+
const uniqueBlockHashes = new Map<string, BlockHash>();
|
|
37
37
|
const txsByBlockHash = new Map<string, string[]>();
|
|
38
38
|
|
|
39
39
|
for (const meta of pendingTxs) {
|
|
40
40
|
const blockHashStr = meta.anchorBlockHeaderHash;
|
|
41
41
|
if (!txsByBlockHash.has(blockHashStr)) {
|
|
42
42
|
txsByBlockHash.set(blockHashStr, []);
|
|
43
|
-
uniqueBlockHashes.set(blockHashStr,
|
|
43
|
+
uniqueBlockHashes.set(blockHashStr, BlockHash.fromString(blockHashStr));
|
|
44
44
|
}
|
|
45
45
|
txsByBlockHash.get(blockHashStr)!.push(meta.txHash);
|
|
46
46
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
3
3
|
import type { L2Block, L2BlockId, L2BlockSource } from '@aztec/stdlib/block';
|
|
4
|
+
import type { BlockMinFeesProvider } from '@aztec/stdlib/gas';
|
|
4
5
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
5
6
|
import type { BlockHeader, Tx, TxHash, TxValidator } from '@aztec/stdlib/tx';
|
|
6
7
|
|
|
@@ -74,6 +75,8 @@ export type TxPoolV2Dependencies = {
|
|
|
74
75
|
createTxValidator: () => Promise<TxValidator<TxMetaData>>;
|
|
75
76
|
/** Checks whether a tx's setup-phase calls are on the allow list. Precomputed at receipt time. */
|
|
76
77
|
checkAllowedSetupCalls: (tx: Tx) => Promise<boolean>;
|
|
78
|
+
/** Provides projected minimum fees for the next block. Used by eviction rules instead of stale block header fees. */
|
|
79
|
+
blockMinFeesProvider: BlockMinFeesProvider;
|
|
77
80
|
};
|
|
78
81
|
|
|
79
82
|
/**
|
|
@@ -3,7 +3,7 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
5
5
|
import { BlockHash, type L2BlockId } from '@aztec/stdlib/block';
|
|
6
|
-
import { Gas } from '@aztec/stdlib/gas';
|
|
6
|
+
import { Gas, GasFees } from '@aztec/stdlib/gas';
|
|
7
7
|
import { type Tx, TxHash } from '@aztec/stdlib/tx';
|
|
8
8
|
|
|
9
9
|
import { getFeePayerBalanceDelta } from '../../msg_validators/tx_validator/fee_payer_balance.js';
|
|
@@ -23,7 +23,7 @@ export type TxMetaValidationData = {
|
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
25
|
txContext: {
|
|
26
|
-
gasSettings: { gasLimits: Gas };
|
|
26
|
+
gasSettings: { gasLimits: Gas; maxFeesPerGas: GasFees };
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
@@ -132,7 +132,10 @@ export async function buildTxMetaData(tx: Tx, allowedSetupCalls: boolean = true)
|
|
|
132
132
|
globalVariables: { blockNumber: anchorBlockNumber },
|
|
133
133
|
},
|
|
134
134
|
txContext: {
|
|
135
|
-
gasSettings: {
|
|
135
|
+
gasSettings: {
|
|
136
|
+
gasLimits: tx.data.constants.txContext.gasSettings.gasLimits,
|
|
137
|
+
maxFeesPerGas: tx.data.constants.txContext.gasSettings.maxFeesPerGas,
|
|
138
|
+
},
|
|
136
139
|
},
|
|
137
140
|
},
|
|
138
141
|
},
|
|
@@ -285,17 +288,19 @@ export function checkNullifierConflict(
|
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
/** Creates a stub TxMetaValidationData for tests that don't exercise validators. */
|
|
288
|
-
export function stubTxMetaValidationData(
|
|
291
|
+
export function stubTxMetaValidationData(
|
|
292
|
+
overrides: { expirationTimestamp?: bigint; maxFeesPerGas?: GasFees } = {},
|
|
293
|
+
): TxMetaValidationData {
|
|
289
294
|
return {
|
|
290
295
|
getNonEmptyNullifiers: () => [],
|
|
291
296
|
expirationTimestamp: overrides.expirationTimestamp ?? 0n,
|
|
292
297
|
constants: {
|
|
293
298
|
anchorBlockHeader: {
|
|
294
|
-
hash: () => Promise.resolve(
|
|
299
|
+
hash: () => Promise.resolve(BlockHash.ZERO),
|
|
295
300
|
globalVariables: { blockNumber: BlockNumber(0) },
|
|
296
301
|
},
|
|
297
302
|
txContext: {
|
|
298
|
-
gasSettings: { gasLimits: Gas.empty() },
|
|
303
|
+
gasSettings: { gasLimits: Gas.empty(), maxFeesPerGas: overrides.maxFeesPerGas ?? GasFees.empty() },
|
|
299
304
|
},
|
|
300
305
|
},
|
|
301
306
|
};
|
|
@@ -313,6 +318,7 @@ export function stubTxMetaData(
|
|
|
313
318
|
expirationTimestamp?: bigint;
|
|
314
319
|
anchorBlockHeaderHash?: string;
|
|
315
320
|
allowedSetupCalls?: boolean;
|
|
321
|
+
maxFeesPerGas?: GasFees;
|
|
316
322
|
} = {},
|
|
317
323
|
): TxMetaData {
|
|
318
324
|
const txHashBigInt = Fr.fromHexString(txHash).toBigInt();
|
|
@@ -332,7 +338,7 @@ export function stubTxMetaData(
|
|
|
332
338
|
allowedSetupCalls: overrides.allowedSetupCalls ?? true,
|
|
333
339
|
receivedAt: 0,
|
|
334
340
|
estimatedSizeBytes: 0,
|
|
335
|
-
data: stubTxMetaValidationData({ expirationTimestamp }),
|
|
341
|
+
data: stubTxMetaValidationData({ expirationTimestamp, maxFeesPerGas: overrides.maxFeesPerGas }),
|
|
336
342
|
};
|
|
337
343
|
}
|
|
338
344
|
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
EvictionManager,
|
|
18
18
|
FeePayerBalanceEvictionRule,
|
|
19
19
|
FeePayerBalancePreAddRule,
|
|
20
|
+
InsufficientFeePerGasEvictionRule,
|
|
20
21
|
InvalidTxsAfterMiningRule,
|
|
21
22
|
InvalidTxsAfterReorgRule,
|
|
22
23
|
LowPriorityEvictionRule,
|
|
@@ -116,6 +117,7 @@ export class TxPoolV2Impl {
|
|
|
116
117
|
|
|
117
118
|
// Post-event eviction rules (run after events to check ALL pending txs)
|
|
118
119
|
this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
|
|
120
|
+
this.#evictionManager.registerRule(new InsufficientFeePerGasEvictionRule(deps.blockMinFeesProvider));
|
|
119
121
|
this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(deps.worldStateSynchronizer));
|
|
120
122
|
this.#evictionManager.registerRule(new FeePayerBalanceEvictionRule(deps.worldStateSynchronizer));
|
|
121
123
|
// LowPriorityEvictionRule handles cases where txs become pending via prepareForSlot (unprotect)
|
|
@@ -3,19 +3,35 @@ import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import {
|
|
5
5
|
type CheckpointAttestation,
|
|
6
|
+
type CoordinationSignatureContext,
|
|
6
7
|
type P2PValidator,
|
|
7
8
|
PeerErrorSeverity,
|
|
8
9
|
type ValidationResult,
|
|
10
|
+
hasValidSignatureContext,
|
|
9
11
|
} from '@aztec/stdlib/p2p';
|
|
10
12
|
|
|
11
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
13
|
+
import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
|
|
12
14
|
|
|
13
15
|
export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
|
|
14
16
|
protected epochCache: EpochCacheInterface;
|
|
15
17
|
protected logger: Logger;
|
|
18
|
+
private readonly pipeliningWindow: PipeliningWindow;
|
|
19
|
+
protected readonly signatureContext: CoordinationSignatureContext;
|
|
16
20
|
|
|
17
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
epochCache: EpochCacheInterface,
|
|
23
|
+
opts: {
|
|
24
|
+
l1PublishingTime?: number;
|
|
25
|
+
p2pPropagationTime?: number;
|
|
26
|
+
signatureContext: CoordinationSignatureContext;
|
|
27
|
+
},
|
|
28
|
+
) {
|
|
18
29
|
this.epochCache = epochCache;
|
|
30
|
+
this.pipeliningWindow = new PipeliningWindow(epochCache, {
|
|
31
|
+
l1PublishingTime: opts.l1PublishingTime,
|
|
32
|
+
p2pPropagationTime: opts.p2pPropagationTime,
|
|
33
|
+
});
|
|
34
|
+
this.signatureContext = opts.signatureContext;
|
|
19
35
|
this.logger = createLogger('p2p:checkpoint-attestation-validator');
|
|
20
36
|
}
|
|
21
37
|
|
|
@@ -23,19 +39,34 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
|
|
|
23
39
|
const slotNumber = message.payload.header.slotNumber;
|
|
24
40
|
|
|
25
41
|
try {
|
|
26
|
-
//
|
|
42
|
+
// Cross-chain replay check: reject attestations that carry a foreign signing domain.
|
|
43
|
+
if (!hasValidSignatureContext(message.payload, this.signatureContext)) {
|
|
44
|
+
this.logger.warn(`Rejecting checkpoint attestation with foreign signature context for slot ${slotNumber}`, {
|
|
45
|
+
chainId: message.payload.signatureContext.chainId,
|
|
46
|
+
rollupAddress: message.payload.signatureContext.rollupAddress.toString(),
|
|
47
|
+
expectedChainId: this.signatureContext.chainId,
|
|
48
|
+
expectedRollupAddress: this.signatureContext.rollupAddress.toString(),
|
|
49
|
+
});
|
|
50
|
+
return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Use target slots since proposals target pipeline slots (slot + 1 when pipelining).
|
|
27
54
|
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
|
|
28
55
|
|
|
29
56
|
if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
|
|
30
|
-
//
|
|
31
|
-
|
|
57
|
+
// When pipelining, accept attestations for the current slot (built in the previous slot)
|
|
58
|
+
// until the target slot reaches its L1 publish cutoff.
|
|
59
|
+
if (this.pipeliningWindow.acceptsAttestation(slotNumber)) {
|
|
60
|
+
// Fall through to remaining validation (signature, committee, etc.)
|
|
61
|
+
} else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
|
|
32
62
|
this.logger.warn(
|
|
33
63
|
`Checkpoint attestation slot ${slotNumber} is not current (${targetSlot}) or next (${nextSlot}) slot`,
|
|
34
64
|
);
|
|
35
65
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
66
|
+
} else {
|
|
67
|
+
this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
|
|
68
|
+
return { result: 'ignore' };
|
|
36
69
|
}
|
|
37
|
-
this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
|
|
38
|
-
return { result: 'ignore' };
|
|
39
70
|
}
|
|
40
71
|
|
|
41
72
|
// Verify the signature is valid
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type CheckpointAttestation,
|
|
4
|
+
type CoordinationSignatureContext,
|
|
5
|
+
PeerErrorSeverity,
|
|
6
|
+
type ValidationResult,
|
|
7
|
+
} from '@aztec/stdlib/p2p';
|
|
3
8
|
import { Attributes, Metrics, type TelemetryClient, createUpDownCounterWithDefault } from '@aztec/telemetry-client';
|
|
4
9
|
|
|
5
10
|
import type { AttestationPoolApi } from '../../mem_pools/attestation_pool/attestation_pool.js';
|
|
@@ -20,8 +25,13 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
20
25
|
epochCache: EpochCacheInterface,
|
|
21
26
|
private attestationPool: AttestationPoolApi,
|
|
22
27
|
telemetryClient: TelemetryClient,
|
|
28
|
+
opts: {
|
|
29
|
+
l1PublishingTime?: number;
|
|
30
|
+
p2pPropagationTime?: number;
|
|
31
|
+
signatureContext: CoordinationSignatureContext;
|
|
32
|
+
},
|
|
23
33
|
) {
|
|
24
|
-
super(epochCache);
|
|
34
|
+
super(epochCache, opts);
|
|
25
35
|
this.logger = this.logger.createChild('[FISHERMAN]');
|
|
26
36
|
|
|
27
37
|
const meter = telemetryClient.getMeter('FishermanAttestationValidator');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { DEFAULT_P2P_PROPAGATION_TIME, createPipelinedCheckpointTimingModel } from '@aztec/stdlib/timetable';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Maximum clock disparity tolerance for P2P message validation (in milliseconds).
|
|
@@ -50,3 +51,77 @@ export function isWithinClockTolerance(
|
|
|
50
51
|
|
|
51
52
|
return elapsedMs < MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Checks if a straggler message for the previous target slot should be accepted.
|
|
57
|
+
*
|
|
58
|
+
* Under pipelining, proposals and attestations carry the target slot N. Most of the
|
|
59
|
+
* time the receiver is either still in the build slot N-1 (accepted via the main
|
|
60
|
+
* `slotNumber === targetSlot` match) or in the target slot N (accepted via
|
|
61
|
+
* `slotNumber === nextSlot` when pipelining is disabled, or again via `targetSlot`
|
|
62
|
+
* when the receiver itself is pipelining). Stragglers that arrive after the receiver
|
|
63
|
+
* has rolled past the target slot fall to this check: accept `messageSlot === slotNow`
|
|
64
|
+
* while we're still within the first `windowSeconds + clock-disparity` of the slot.
|
|
65
|
+
*
|
|
66
|
+
* Under the early-pipelining schedule `windowSeconds` is small (0 for proposals,
|
|
67
|
+
* `2*p2pPropagationTime` for attestations) since the proposer collects everything
|
|
68
|
+
* before the slot boundary.
|
|
69
|
+
*
|
|
70
|
+
* @param messageSlot - The slot number from the received message
|
|
71
|
+
* @param epochCache - EpochCache to get timing and pipelining state
|
|
72
|
+
* @param windowSeconds - How far into the current slot we still accept previous-target messages
|
|
73
|
+
* @returns true if pipelining is enabled, the message is for the current wallclock slot, and we're within the grace period
|
|
74
|
+
*/
|
|
75
|
+
function isWithinPipeliningWindow(
|
|
76
|
+
messageSlot: SlotNumber,
|
|
77
|
+
epochCache: EpochCacheInterface,
|
|
78
|
+
windowSeconds: number,
|
|
79
|
+
): boolean {
|
|
80
|
+
if (!epochCache.isProposerPipeliningEnabled()) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const currentSlot = epochCache.getSlotNow();
|
|
85
|
+
if (messageSlot !== currentSlot) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
|
|
90
|
+
const slotStartMs = slotStartTs * 1000n;
|
|
91
|
+
const elapsedMs = Number(nowMs - slotStartMs);
|
|
92
|
+
const windowMs = windowSeconds * 1000 + MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
|
|
93
|
+
|
|
94
|
+
return elapsedMs < windowMs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class PipeliningWindow {
|
|
98
|
+
private readonly proposalWindowIntoTargetSlot: number;
|
|
99
|
+
private readonly attestationWindowIntoTargetSlot: number;
|
|
100
|
+
|
|
101
|
+
constructor(
|
|
102
|
+
private readonly epochCache: EpochCacheInterface,
|
|
103
|
+
opts: {
|
|
104
|
+
p2pPropagationTime?: number;
|
|
105
|
+
l1PublishingTime?: number;
|
|
106
|
+
} = {},
|
|
107
|
+
) {
|
|
108
|
+
const l1Constants = epochCache.getL1Constants();
|
|
109
|
+
const checkpointTiming = createPipelinedCheckpointTimingModel({
|
|
110
|
+
aztecSlotDuration: l1Constants.slotDuration,
|
|
111
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
112
|
+
l1PublishingTime: opts.l1PublishingTime ?? l1Constants.ethereumSlotDuration,
|
|
113
|
+
p2pPropagationTime: opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
this.proposalWindowIntoTargetSlot = checkpointTiming.proposalWindowIntoTargetSlot;
|
|
117
|
+
this.attestationWindowIntoTargetSlot = checkpointTiming.attestationWindowIntoTargetSlot;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public acceptsProposal(messageSlot: SlotNumber): boolean {
|
|
121
|
+
return isWithinPipeliningWindow(messageSlot, this.epochCache, this.proposalWindowIntoTargetSlot);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public acceptsAttestation(messageSlot: SlotNumber): boolean {
|
|
125
|
+
return isWithinPipeliningWindow(messageSlot, this.epochCache, this.attestationWindowIntoTargetSlot);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type { BlockProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { BlockProposal, CoordinationSignatureContext, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
3
3
|
|
|
4
4
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
5
|
|
|
6
6
|
export class BlockProposalValidator implements P2PValidator<BlockProposal> {
|
|
7
7
|
private proposalValidator: ProposalValidator;
|
|
8
8
|
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
epochCache: EpochCacheInterface,
|
|
11
|
+
opts: {
|
|
12
|
+
txsPermitted: boolean;
|
|
13
|
+
maxTxsPerBlock?: number;
|
|
14
|
+
maxBlocksPerCheckpoint?: number;
|
|
15
|
+
p2pPropagationTime?: number;
|
|
16
|
+
signatureContext: CoordinationSignatureContext;
|
|
17
|
+
},
|
|
18
|
+
) {
|
|
10
19
|
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
|
|
11
20
|
}
|
|
12
21
|
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CheckpointProposal,
|
|
4
|
+
CoordinationSignatureContext,
|
|
5
|
+
P2PValidator,
|
|
6
|
+
ValidationResult,
|
|
7
|
+
} from '@aztec/stdlib/p2p';
|
|
3
8
|
|
|
4
9
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
10
|
|
|
6
11
|
export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
|
|
7
12
|
private proposalValidator: ProposalValidator;
|
|
8
13
|
|
|
9
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
epochCache: EpochCacheInterface,
|
|
16
|
+
opts: {
|
|
17
|
+
txsPermitted: boolean;
|
|
18
|
+
maxTxsPerBlock?: number;
|
|
19
|
+
maxBlocksPerCheckpoint?: number;
|
|
20
|
+
p2pPropagationTime?: number;
|
|
21
|
+
signatureContext: CoordinationSignatureContext;
|
|
22
|
+
},
|
|
23
|
+
) {
|
|
10
24
|
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
|
|
11
25
|
}
|
|
12
26
|
|
|
@@ -4,11 +4,13 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
|
4
4
|
import {
|
|
5
5
|
type BlockProposal,
|
|
6
6
|
type CheckpointProposalCore,
|
|
7
|
+
type CoordinationSignatureContext,
|
|
7
8
|
PeerErrorSeverity,
|
|
8
9
|
type ValidationResult,
|
|
10
|
+
hasValidSignatureContext,
|
|
9
11
|
} from '@aztec/stdlib/p2p';
|
|
10
12
|
|
|
11
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
13
|
+
import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
|
|
12
14
|
|
|
13
15
|
/** Validates header-level and tx-level fields of block and checkpoint proposals. */
|
|
14
16
|
export class ProposalValidator {
|
|
@@ -16,33 +18,60 @@ export class ProposalValidator {
|
|
|
16
18
|
private logger: Logger;
|
|
17
19
|
private txsPermitted: boolean;
|
|
18
20
|
private maxTxsPerBlock?: number;
|
|
21
|
+
private maxBlocksPerCheckpoint?: number;
|
|
22
|
+
private pipeliningWindow: PipeliningWindow;
|
|
23
|
+
private signatureContext: CoordinationSignatureContext;
|
|
19
24
|
|
|
20
25
|
constructor(
|
|
21
26
|
epochCache: EpochCacheInterface,
|
|
22
|
-
opts: {
|
|
27
|
+
opts: {
|
|
28
|
+
txsPermitted: boolean;
|
|
29
|
+
maxTxsPerBlock?: number;
|
|
30
|
+
maxBlocksPerCheckpoint?: number;
|
|
31
|
+
p2pPropagationTime?: number;
|
|
32
|
+
signatureContext: CoordinationSignatureContext;
|
|
33
|
+
},
|
|
23
34
|
loggerName: string,
|
|
24
35
|
) {
|
|
25
36
|
this.epochCache = epochCache;
|
|
26
37
|
this.txsPermitted = opts.txsPermitted;
|
|
27
38
|
this.maxTxsPerBlock = opts.maxTxsPerBlock;
|
|
39
|
+
this.maxBlocksPerCheckpoint = opts.maxBlocksPerCheckpoint;
|
|
40
|
+
this.pipeliningWindow = new PipeliningWindow(epochCache, { p2pPropagationTime: opts.p2pPropagationTime });
|
|
41
|
+
this.signatureContext = opts.signatureContext;
|
|
28
42
|
this.logger = createLogger(loggerName);
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
/** Validates header-level fields: slot, signature, and proposer. */
|
|
32
46
|
public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
|
|
33
47
|
try {
|
|
34
|
-
//
|
|
48
|
+
// Cross-chain replay check: reject proposals that carry a foreign signing domain.
|
|
49
|
+
if (!hasValidSignatureContext(proposal, this.signatureContext)) {
|
|
50
|
+
this.logger.warn(`Penalizing peer for proposal with foreign signature context`, {
|
|
51
|
+
chainId: proposal.signatureContext.chainId,
|
|
52
|
+
rollupAddress: proposal.signatureContext.rollupAddress.toString(),
|
|
53
|
+
expectedChainId: this.signatureContext.chainId,
|
|
54
|
+
expectedRollupAddress: this.signatureContext.rollupAddress.toString(),
|
|
55
|
+
});
|
|
56
|
+
return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Slot check: use target slots since proposals target pipeline slots (slot + 1 when pipelining).
|
|
35
60
|
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
|
|
36
61
|
|
|
37
62
|
const slotNumber = proposal.slotNumber;
|
|
38
63
|
if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
|
|
39
|
-
//
|
|
40
|
-
if
|
|
64
|
+
// When pipelining, accept proposals for the current slot (built in the previous slot)
|
|
65
|
+
// if they're still within the shared proposal acceptance window.
|
|
66
|
+
if (this.pipeliningWindow.acceptsProposal(slotNumber)) {
|
|
67
|
+
// Fall through to remaining validation (signature, proposer, etc.)
|
|
68
|
+
} else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
|
|
41
69
|
this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { targetSlot, nextSlot });
|
|
42
70
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
71
|
+
} else {
|
|
72
|
+
this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
73
|
+
return { result: 'ignore' };
|
|
43
74
|
}
|
|
44
|
-
this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
45
|
-
return { result: 'ignore' };
|
|
46
75
|
}
|
|
47
76
|
|
|
48
77
|
// Signature validity
|
|
@@ -62,6 +91,17 @@ export class ProposalValidator {
|
|
|
62
91
|
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
63
92
|
}
|
|
64
93
|
|
|
94
|
+
if (
|
|
95
|
+
this.maxBlocksPerCheckpoint !== undefined &&
|
|
96
|
+
'indexWithinCheckpoint' in proposal &&
|
|
97
|
+
proposal.indexWithinCheckpoint >= this.maxBlocksPerCheckpoint
|
|
98
|
+
) {
|
|
99
|
+
this.logger.warn(
|
|
100
|
+
`Penalizing peer for proposal with indexWithinCheckpoint ${proposal.indexWithinCheckpoint} >= max ${this.maxBlocksPerCheckpoint}`,
|
|
101
|
+
);
|
|
102
|
+
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
103
|
+
}
|
|
104
|
+
|
|
65
105
|
return { result: 'accept' };
|
|
66
106
|
} catch (e) {
|
|
67
107
|
if (e instanceof NoCommitteeError) {
|
|
@@ -75,7 +75,7 @@ This validator is invoked on **every** transaction potentially entering the pend
|
|
|
75
75
|
- Startup hydration — revalidating persisted non-mined txs on node restart
|
|
76
76
|
|
|
77
77
|
Runs:
|
|
78
|
-
- DoubleSpend, BlockHeader, GasLimits, Timestamp, AllowedSetupCalls
|
|
78
|
+
- DoubleSpend, BlockHeader, GasLimits, MaxFeePerGas, Timestamp, AllowedSetupCalls
|
|
79
79
|
|
|
80
80
|
Operates on `TxMetaData` (pre-built by the pool) rather than full `Tx` objects.
|
|
81
81
|
|
|
@@ -91,8 +91,9 @@ The `AllowedSetupCallsMetaValidator` checks a precomputed boolean flag (`TxMetaD
|
|
|
91
91
|
| `MetadataTxValidator` | Chain ID, rollup version, protocol contracts hash, VK tree root | 4.18 us |
|
|
92
92
|
| `TimestampTxValidator` | Transaction has not expired (expiration timestamp vs next slot) | 1.56 us |
|
|
93
93
|
| `DoubleSpendTxValidator` | Nullifiers do not already exist in the nullifier tree | 106.08 us |
|
|
94
|
-
| `GasTxValidator` | Gas limits are within bounds (delegates to `GasLimitsValidator`), max fee per gas meets current block fees, and fee payer has sufficient FeeJuice balance | 1.02 ms |
|
|
94
|
+
| `GasTxValidator` | Gas limits are within bounds (delegates to `GasLimitsValidator`), max fee per gas meets current block fees (delegates to `MaxFeePerGasValidator`), and fee payer has sufficient FeeJuice balance | 1.02 ms |
|
|
95
95
|
| `GasLimitsValidator` | Gas limits are >= fixed minimums and <= AVM max processable L2 gas. Used standalone in pool migration; also called internally by `GasTxValidator` | 3–10 us |
|
|
96
|
+
| `MaxFeePerGasValidator` | Max fee per gas >= current block gas fees on both dimensions (DA and L2). Used standalone in pool migration; also called internally by `GasTxValidator` | 3–10 us |
|
|
96
97
|
| `PhasesTxValidator` | Public function calls in setup phase are on the allow list | 10.12–13.12 us |
|
|
97
98
|
| `AllowedSetupCallsMetaValidator` | Checks the precomputed `allowedSetupCalls` flag on `TxMetaData`. Used in pool migration instead of the full `PhasesTxValidator` | — |
|
|
98
99
|
| `BlockHeaderTxValidator` | Transaction's anchor block hash exists in the archive tree | 98.88 us |
|
|
@@ -110,10 +111,17 @@ The `AllowedSetupCallsMetaValidator` checks a precomputed boolean flag (`TxMetaD
|
|
|
110
111
|
| DoubleSpend | Stage 1 | Yes | — | Yes | Yes |
|
|
111
112
|
| Gas (balance + limits) | Stage 1 | Optional* | — | Yes | — |
|
|
112
113
|
| GasLimits (standalone) | — | — | — | — | Yes |
|
|
114
|
+
| MaxFeePerGas (standalone) | — | — | — | — | Yes |
|
|
113
115
|
| Phases | Stage 1 | Yes | — | Yes | — |
|
|
114
116
|
| AllowedSetupCalls | — | — | — | — | Yes |
|
|
115
117
|
| BlockHeader | Stage 1 | Yes | — | Yes | Yes |
|
|
116
118
|
| Proof | Stage 2 | Optional** | Yes | — | — |
|
|
117
119
|
|
|
118
|
-
\* Gas balance check is skipped when `skipFeeEnforcement` is set (testing/dev). `GasTxValidator` internally delegates to `GasLimitsValidator` as its first
|
|
120
|
+
\* Gas balance check is skipped when `skipFeeEnforcement` is set (testing/dev). `GasTxValidator` internally delegates to `GasLimitsValidator` and `MaxFeePerGasValidator` as its first steps, so gas limits and fee-per-gas are checked wherever `GasTxValidator` runs. Pool migration uses `GasLimitsValidator` and `MaxFeePerGasValidator` standalone because it doesn't need the balance check.
|
|
119
121
|
\** Proof verification is skipped for simulations (no verifier provided).
|
|
122
|
+
|
|
123
|
+
## Fee-Per-Gas Rejection Strategy
|
|
124
|
+
|
|
125
|
+
The `MaxFeePerGasValidator` and `InsufficientFeePerGasEvictionRule` reject and evict transactions whose `maxFeesPerGas` falls below the current block's gas fees. This is a simple strategy: if a tx can't pay the current fees, it gets rejected on entry and evicted after each new block.
|
|
126
|
+
|
|
127
|
+
**Caveat**: This may evict transactions that would become valid again if block fees drop. A more nuanced approach would be to define a threshold (e.g., 50%) and only reject/evict when the tx's max fee falls below that fraction of the current fees. The current approach is simpler and ensures the pool doesn't accumulate transactions with low max fees that are unlikely to be mined soon.
|
|
@@ -15,7 +15,7 @@ export class ArchiveCache implements ArchiveSource {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
public async getArchiveIndices(archives: BlockHash[]): Promise<(bigint | undefined)[]> {
|
|
18
|
-
const toCheckDb = archives.filter(n => !this.archives.has(n.toString()))
|
|
18
|
+
const toCheckDb = archives.filter(n => !this.archives.has(n.toString()));
|
|
19
19
|
const dbHits = await this.db.findLeafIndices(MerkleTreeId.ARCHIVE, toCheckDb);
|
|
20
20
|
dbHits.forEach((x, index) => {
|
|
21
21
|
if (x !== undefined) {
|
|
@@ -56,7 +56,7 @@ import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_valid
|
|
|
56
56
|
import { ContractInstanceTxValidator } from './contract_instance_validator.js';
|
|
57
57
|
import { DataTxValidator } from './data_validator.js';
|
|
58
58
|
import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
|
|
59
|
-
import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
|
|
59
|
+
import { GasLimitsValidator, GasTxValidator, MaxFeePerGasValidator } from './gas_validator.js';
|
|
60
60
|
import { MetadataTxValidator } from './metadata_validator.js';
|
|
61
61
|
import { NullifierCache } from './nullifier_cache.js';
|
|
62
62
|
import { AllowedSetupCallsMetaValidator, PhasesTxValidator } from './phases_validator.js';
|
|
@@ -423,6 +423,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
|
|
|
423
423
|
timestamp: bigint,
|
|
424
424
|
blockNumber: BlockNumber,
|
|
425
425
|
gasLimitOpts: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
|
|
426
|
+
gasFees: GasFees,
|
|
426
427
|
bindings?: LoggerBindings,
|
|
427
428
|
): Promise<TxValidator<TxMetaData>> {
|
|
428
429
|
await worldStateSynchronizer.syncImmediate();
|
|
@@ -440,6 +441,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
|
|
|
440
441
|
};
|
|
441
442
|
return new AggregateTxValidator<TxMetaData>(
|
|
442
443
|
new GasLimitsValidator<TxMetaData>({ ...gasLimitOpts, bindings }),
|
|
444
|
+
new MaxFeePerGasValidator<TxMetaData>(gasFees, bindings),
|
|
443
445
|
new TimestampTxValidator<TxMetaData>({ timestamp, blockNumber }, bindings),
|
|
444
446
|
new DoubleSpendTxValidator<TxMetaData>(nullifierSource, bindings),
|
|
445
447
|
new BlockHeaderTxValidator<TxMetaData>(archiveSource, bindings),
|