@aztec/p2p 0.0.1-commit.3e3d0c9cd → 0.0.1-commit.3f5453c7b
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 +5 -4
- package/dest/client/interface.d.ts +9 -2
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +3 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +21 -6
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +17 -6
- package/dest/config.d.ts +10 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +15 -0
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +7 -5
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +11 -8
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
- package/dest/mem_pools/index.d.ts +1 -2
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +4 -4
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +5 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +20 -11
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +4 -2
- 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 +54 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
- 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 +2 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +19 -11
- 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/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +35 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +1 -1
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +8 -2
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +11 -9
- package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
- 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 +6 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +6 -1
- package/dest/services/encoding.d.ts +5 -1
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +7 -1
- 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/libp2p_service.d.ts +15 -25
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +121 -112
- package/dest/services/peer-manager/peer_manager.d.ts +6 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +37 -10
- package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +32 -10
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -7
- 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 +43 -56
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +1 -2
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +4 -4
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +7 -7
- 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_limiter.d.ts +5 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
- 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 +27 -10
- package/dest/services/service.d.ts +5 -2
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +57 -73
- package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_source.js +39 -29
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/slow_tx_collection.js +1 -1
- package/dest/services/tx_collection/tx_collection.d.ts +3 -6
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.d.ts +6 -5
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +9 -7
- 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 +35 -10
- 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 +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 +21 -2
- package/dest/testbench/p2p_client_testbench_worker.js +66 -15
- 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 -1
- package/package.json +14 -14
- package/src/client/factory.ts +7 -2
- package/src/client/interface.ts +9 -1
- package/src/client/p2p_client.ts +23 -6
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +18 -8
- package/src/config.ts +30 -1
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/index.ts +0 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +12 -8
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
- package/src/mem_pools/index.ts +0 -3
- package/src/mem_pools/tx_pool_v2/interfaces.ts +4 -4
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +7 -1
- package/src/msg_validators/attestation_validator/README.md +1 -1
- package/src/msg_validators/attestation_validator/attestation_validator.ts +21 -9
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +4 -1
- package/src/msg_validators/clock_tolerance.ts +72 -3
- package/src/msg_validators/proposal_validator/README.md +4 -4
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +4 -1
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +4 -1
- package/src/msg_validators/proposal_validator/proposal_validator.ts +17 -10
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +42 -1
- package/src/msg_validators/tx_validator/factory.ts +7 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +25 -9
- package/src/msg_validators/tx_validator/phases_validator.ts +1 -1
- package/src/services/data_store.ts +5 -13
- package/src/services/dummy_service.ts +8 -2
- package/src/services/encoding.ts +9 -1
- package/src/services/gossipsub/topic_score_params.ts +36 -4
- package/src/services/libp2p/libp2p_service.ts +122 -128
- package/src/services/peer-manager/peer_manager.ts +43 -10
- package/src/services/peer-manager/peer_scoring.ts +27 -5
- package/src/services/reqresp/batch-tx-requester/README.md +46 -7
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +35 -60
- package/src/services/reqresp/batch-tx-requester/interface.ts +0 -1
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +6 -6
- 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_limiter.ts +13 -9
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +36 -11
- package/src/services/service.ts +6 -1
- package/src/services/tx_collection/fast_tx_collection.ts +57 -83
- package/src/services/tx_collection/file_store_tx_source.ts +43 -31
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/slow_tx_collection.ts +1 -1
- package/src/services/tx_collection/tx_collection.ts +3 -5
- package/src/services/tx_collection/tx_source.ts +8 -7
- package/src/test-helpers/mock-pubsub.ts +31 -5
- package/src/test-helpers/reqresp-nodes.ts +2 -2
- package/src/test-helpers/testbench-utils.ts +29 -3
- package/src/testbench/p2p_client_testbench_worker.ts +70 -14
- package/src/testbench/worker_client_manager.ts +55 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -123
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
- package/dest/mem_pools/tx_pool/index.d.ts +0 -3
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -2
- package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -15
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -402
- 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/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
- package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
- package/src/mem_pools/tx_pool/README.md +0 -270
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -163
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
- package/src/mem_pools/tx_pool/index.ts +0 -2
- package/src/mem_pools/tx_pool/priority.ts +0 -20
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -321
- package/src/services/reqresp/protocols/block.ts +0 -37
- package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
|
@@ -446,12 +446,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
446
446
|
const result2 = await ap.tryAddBlockProposal(proposal2);
|
|
447
447
|
expect(result2.count).toBe(2);
|
|
448
448
|
|
|
449
|
-
//
|
|
449
|
+
// Third proposal for same position should be rejected (cap is 2)
|
|
450
450
|
const proposal3 = await mockBlockProposalWithIndex(signers[2], slotNumber, indexWithinCheckpoint);
|
|
451
451
|
const result3 = await ap.tryAddBlockProposal(proposal3);
|
|
452
452
|
|
|
453
|
-
expect(result3.added).toBe(
|
|
454
|
-
expect(result3.count).toBe(
|
|
453
|
+
expect(result3.added).toBe(false);
|
|
454
|
+
expect(result3.count).toBe(2);
|
|
455
455
|
});
|
|
456
456
|
|
|
457
457
|
it('should return added=false when exceeding capacity', async () => {
|
|
@@ -666,12 +666,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
666
666
|
const result2 = await ap.tryAddCheckpointProposal(proposal2);
|
|
667
667
|
expect(result2.count).toBe(2);
|
|
668
668
|
|
|
669
|
-
//
|
|
669
|
+
// Third proposal for same slot should be rejected (cap is 2)
|
|
670
670
|
const proposal3 = await mockCheckpointProposalCoreForPool(signers[2], slotNumber);
|
|
671
671
|
const result3 = await ap.tryAddCheckpointProposal(proposal3);
|
|
672
672
|
|
|
673
|
-
expect(result3.added).toBe(
|
|
674
|
-
expect(result3.count).toBe(
|
|
673
|
+
expect(result3.added).toBe(false);
|
|
674
|
+
expect(result3.count).toBe(2);
|
|
675
675
|
});
|
|
676
676
|
|
|
677
677
|
it('should not count attestations as proposals for duplicate detection', async () => {
|
package/src/mem_pools/index.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
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
|
|
4
|
-
export { type TxPool } from './tx_pool/tx_pool.js';
|
|
5
|
-
// New TxPoolV2 exports
|
|
6
3
|
export { type TxPoolV2, type TxPoolV2Config, type TxPoolV2Events, type AddTxsResult } from './tx_pool_v2/index.js';
|
|
@@ -160,10 +160,10 @@ export interface TxPoolV2 extends TypedEventEmitter<TxPoolV2Events> {
|
|
|
160
160
|
handleMinedBlock(block: L2Block): Promise<void>;
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
|
-
* Prepares the pool for a new slot
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
163
|
+
* Prepares the pool for a new slot by unprotecting transactions from earlier
|
|
164
|
+
* slots and re-validating them before returning to pending state.
|
|
165
|
+
* @param slotNumber - The pipeline slot we are building for (i.e. the slot
|
|
166
|
+
* the resulting blocks will target on L1).
|
|
167
167
|
*/
|
|
168
168
|
prepareForSlot(slotNumber: SlotNumber): Promise<void>;
|
|
169
169
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { minBigint } from '@aztec/foundation/bigint';
|
|
1
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
@@ -6,7 +7,6 @@ import { Gas } from '@aztec/stdlib/gas';
|
|
|
6
7
|
import { type Tx, TxHash } from '@aztec/stdlib/tx';
|
|
7
8
|
|
|
8
9
|
import { getFeePayerBalanceDelta } from '../../msg_validators/tx_validator/fee_payer_balance.js';
|
|
9
|
-
import { getTxPriorityFee } from '../tx_pool/priority.js';
|
|
10
10
|
import { type PreAddResult, TxPoolRejectionCode } from './eviction/interfaces.js';
|
|
11
11
|
|
|
12
12
|
/** Validator-compatible data interface, mirroring the subset of PrivateKernelTailCircuitPublicInputs used by validators. */
|
|
@@ -335,3 +335,9 @@ export function stubTxMetaData(
|
|
|
335
335
|
data: stubTxMetaValidationData({ expirationTimestamp }),
|
|
336
336
|
};
|
|
337
337
|
}
|
|
338
|
+
|
|
339
|
+
/** Returns the priority fee for a tx, based on the L2 priority fee capped by the max fee per gas. */
|
|
340
|
+
function getTxPriorityFee(tx: Tx): bigint {
|
|
341
|
+
const { maxPriorityFeesPerGas: priorityFees, maxFeesPerGas } = tx.getGasSettings();
|
|
342
|
+
return minBigint(maxFeesPerGas.feePerL2Gas, priorityFees.feePerL2Gas);
|
|
343
|
+
}
|
|
@@ -24,7 +24,7 @@ This module validates `CheckpointAttestation` gossipsub messages. Attestations a
|
|
|
24
24
|
|---|------|-------------|
|
|
25
25
|
| 8 | Sender recoverable (pool-side) | Silent drop |
|
|
26
26
|
| 9 | Not a duplicate (same slot + proposalId + signer) | IGNORE |
|
|
27
|
-
| 10 | Per-signer cap: `MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER` =
|
|
27
|
+
| 10 | Per-signer cap: `MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER` = 2 | IGNORE |
|
|
28
28
|
|
|
29
29
|
Own attestations added via `addOwnCheckpointAttestations` bypass the per-signer cap.
|
|
30
30
|
|
|
@@ -8,14 +8,21 @@ import {
|
|
|
8
8
|
type ValidationResult,
|
|
9
9
|
} from '@aztec/stdlib/p2p';
|
|
10
10
|
|
|
11
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
11
|
+
import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
|
|
12
12
|
|
|
13
13
|
export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
|
|
14
14
|
protected epochCache: EpochCacheInterface;
|
|
15
15
|
protected logger: Logger;
|
|
16
|
+
private readonly pipeliningWindow: PipeliningWindow;
|
|
16
17
|
|
|
17
|
-
constructor(
|
|
18
|
+
constructor(
|
|
19
|
+
epochCache: EpochCacheInterface,
|
|
20
|
+
opts: {
|
|
21
|
+
l1PublishingTime?: number;
|
|
22
|
+
},
|
|
23
|
+
) {
|
|
18
24
|
this.epochCache = epochCache;
|
|
25
|
+
this.pipeliningWindow = new PipeliningWindow(epochCache, { l1PublishingTime: opts.l1PublishingTime });
|
|
19
26
|
this.logger = createLogger('p2p:checkpoint-attestation-validator');
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -23,18 +30,23 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
|
|
|
23
30
|
const slotNumber = message.payload.header.slotNumber;
|
|
24
31
|
|
|
25
32
|
try {
|
|
26
|
-
|
|
33
|
+
// Use target slots since proposals target pipeline slots (slot + 1 when pipelining).
|
|
34
|
+
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
|
|
27
35
|
|
|
28
|
-
if (slotNumber !==
|
|
29
|
-
//
|
|
30
|
-
|
|
36
|
+
if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
|
|
37
|
+
// When pipelining, accept attestations for the current slot (built in the previous slot)
|
|
38
|
+
// until the target slot reaches its L1 publish cutoff.
|
|
39
|
+
if (this.pipeliningWindow.acceptsAttestation(slotNumber)) {
|
|
40
|
+
// Fall through to remaining validation (signature, committee, etc.)
|
|
41
|
+
} else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
|
|
31
42
|
this.logger.warn(
|
|
32
|
-
`Checkpoint attestation slot ${slotNumber} is not current (${
|
|
43
|
+
`Checkpoint attestation slot ${slotNumber} is not current (${targetSlot}) or next (${nextSlot}) slot`,
|
|
33
44
|
);
|
|
34
45
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
46
|
+
} else {
|
|
47
|
+
this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
|
|
48
|
+
return { result: 'ignore' };
|
|
35
49
|
}
|
|
36
|
-
this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
|
|
37
|
-
return { result: 'ignore' };
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
// Verify the signature is valid
|
|
@@ -20,8 +20,11 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
20
20
|
epochCache: EpochCacheInterface,
|
|
21
21
|
private attestationPool: AttestationPoolApi,
|
|
22
22
|
telemetryClient: TelemetryClient,
|
|
23
|
+
opts: {
|
|
24
|
+
l1PublishingTime?: number;
|
|
25
|
+
} = {},
|
|
23
26
|
) {
|
|
24
|
-
super(epochCache);
|
|
27
|
+
super(epochCache, opts);
|
|
25
28
|
this.logger = this.logger.createChild('[FISHERMAN]');
|
|
26
29
|
|
|
27
30
|
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).
|
|
@@ -36,10 +37,11 @@ export function isWithinClockTolerance(
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// Check how far we are into the current slot (in milliseconds)
|
|
39
|
-
const { ts: slotStartTs, nowMs
|
|
40
|
+
const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
|
|
41
|
+
const targetSlot = epochCache.getTargetSlot();
|
|
40
42
|
|
|
41
|
-
// Sanity check: ensure the epoch cache's
|
|
42
|
-
if (
|
|
43
|
+
// Sanity check: ensure the epoch cache's target slot matches the expected current slot
|
|
44
|
+
if (targetSlot !== currentSlot) {
|
|
43
45
|
return false;
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -49,3 +51,70 @@ export function isWithinClockTolerance(
|
|
|
49
51
|
|
|
50
52
|
return elapsedMs < MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
|
|
51
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Checks if a message should be accepted under the pipelining grace period.
|
|
57
|
+
*
|
|
58
|
+
* When pipelining is enabled, `targetSlot = slotNow + 1`. A proposal built in slot N-1
|
|
59
|
+
* for slot N arrives when validators are in slot N, so their `targetSlot = N+1`.
|
|
60
|
+
* This function accepts proposals for the current wallclock slot if we're within the
|
|
61
|
+
* first `windowSeconds` seconds of the slot (the pipelining grace period). - see stdlib/timetable/index.ts
|
|
62
|
+
*
|
|
63
|
+
* @param messageSlot - The slot number from the received message
|
|
64
|
+
* @param epochCache - EpochCache to get timing and pipelining state
|
|
65
|
+
* @param windowSeconds - The window grace period allowed for attestations into the next slot
|
|
66
|
+
* @returns true if pipelining is enabled, the message is for the current slot, and we're within the grace period
|
|
67
|
+
*/
|
|
68
|
+
function isWithinPipeliningWindow(
|
|
69
|
+
messageSlot: SlotNumber,
|
|
70
|
+
epochCache: EpochCacheInterface,
|
|
71
|
+
windowSeconds: number,
|
|
72
|
+
): boolean {
|
|
73
|
+
if (!epochCache.isProposerPipeliningEnabled()) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const currentSlot = epochCache.getSlotNow();
|
|
78
|
+
if (messageSlot !== currentSlot) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { ts: slotStartTs, nowMs } = epochCache.getEpochAndSlotNow();
|
|
83
|
+
const slotStartMs = slotStartTs * 1000n;
|
|
84
|
+
const elapsedMs = Number(nowMs - slotStartMs);
|
|
85
|
+
const windowMs = windowSeconds * 1000 + MAXIMUM_GOSSIP_CLOCK_DISPARITY_MS;
|
|
86
|
+
|
|
87
|
+
return elapsedMs < windowMs;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class PipeliningWindow {
|
|
91
|
+
private readonly proposalWindowIntoTargetSlot: number;
|
|
92
|
+
private readonly attestationWindowIntoTargetSlot: number;
|
|
93
|
+
|
|
94
|
+
constructor(
|
|
95
|
+
private readonly epochCache: EpochCacheInterface,
|
|
96
|
+
opts: {
|
|
97
|
+
p2pPropagationTime?: number;
|
|
98
|
+
l1PublishingTime?: number;
|
|
99
|
+
} = {},
|
|
100
|
+
) {
|
|
101
|
+
const l1Constants = epochCache.getL1Constants();
|
|
102
|
+
const checkpointTiming = createPipelinedCheckpointTimingModel({
|
|
103
|
+
aztecSlotDuration: l1Constants.slotDuration,
|
|
104
|
+
ethereumSlotDuration: l1Constants.ethereumSlotDuration,
|
|
105
|
+
l1PublishingTime: opts.l1PublishingTime ?? l1Constants.ethereumSlotDuration,
|
|
106
|
+
p2pPropagationTime: opts.p2pPropagationTime ?? DEFAULT_P2P_PROPAGATION_TIME,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
this.proposalWindowIntoTargetSlot = checkpointTiming.proposalWindowIntoTargetSlot;
|
|
110
|
+
this.attestationWindowIntoTargetSlot = checkpointTiming.attestationWindowIntoTargetSlot;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public acceptsProposal(messageSlot: SlotNumber): boolean {
|
|
114
|
+
return isWithinPipeliningWindow(messageSlot, this.epochCache, this.proposalWindowIntoTargetSlot);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public acceptsAttestation(messageSlot: SlotNumber): boolean {
|
|
118
|
+
return isWithinPipeliningWindow(messageSlot, this.epochCache, this.attestationWindowIntoTargetSlot);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -28,7 +28,7 @@ Deserialization guards: `BlockProposal.fromBuffer` and `SignedTxs.fromBuffer` bo
|
|
|
28
28
|
| # | Rule | Consequence |
|
|
29
29
|
|---|------|-------------|
|
|
30
30
|
| 9 | **Duplicate**: same archive root already stored | IGNORE (no penalty) |
|
|
31
|
-
| 10 | **Per-position cap**: max
|
|
31
|
+
| 10 | **Per-position cap**: max 2 proposals per (slot, indexWithinCheckpoint) | REJECT + HighToleranceError |
|
|
32
32
|
| 11 | **Equivocation**: >1 distinct proposal for same (slot, index) | ACCEPT (rebroadcast for detection). At count=2: `duplicateProposalCallback` fires -> slash event (`OffenseType.DUPLICATE_PROPOSAL`, configured via `slashDuplicateProposalPenalty`) |
|
|
33
33
|
|
|
34
34
|
### Stage 3: Validator-Client Processing (BlockProposalHandler)
|
|
@@ -53,7 +53,7 @@ Only runs on validator nodes. Non-validator nodes use a default handler that tri
|
|
|
53
53
|
|
|
54
54
|
**Escape hatch**: during escape hatch periods (`isEscapeHatchOpenAtSlot`), re-execution and slashing are both disabled, and the proposal is rejected locally.
|
|
55
55
|
|
|
56
|
-
**Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0
|
|
56
|
+
**Conditional re-execution**: rules 22-24 only run when at least one condition is true: `fishermanMode` enabled, `slashBroadcastedInvalidBlockPenalty > 0`, committee membership, `alwaysReexecuteBlockProposals`, or `blobClient.canUpload()`.
|
|
57
57
|
|
|
58
58
|
**Slashing**: only `state_mismatch` and `failed_txs` trigger on-chain slashing (`OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL`, gated by `slashBroadcastedInvalidBlockPenalty > 0`). Unknown errors during re-execution do NOT slash.
|
|
59
59
|
|
|
@@ -84,7 +84,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
|
|
|
84
84
|
| Rule | Consequence | File |
|
|
85
85
|
|------|-------------|------|
|
|
86
86
|
| Block proposal must pass `BlockProposalValidator.validate()` | If REJECT: entire checkpoint REJECTED | `libp2p_service.ts` |
|
|
87
|
-
| Block proposal must not exceed per-position cap (
|
|
87
|
+
| Block proposal must not exceed per-position cap (2) | Checkpoint REJECTED + HighToleranceError | same |
|
|
88
88
|
| Block equivocation detected (>1 proposals for same slot+index) | Checkpoint REJECTED (block itself is ACCEPT for re-broadcast) | same |
|
|
89
89
|
|
|
90
90
|
### Stage 3: Mempool (Attestation Pool)
|
|
@@ -92,7 +92,7 @@ The checkpoint's embedded `lastBlock` is extracted via `getBlockProposal()` and
|
|
|
92
92
|
| Rule | Consequence | File |
|
|
93
93
|
|------|-------------|------|
|
|
94
94
|
| Duplicate (same archive ID) | IGNORE (no penalty). Embedded block still processed if valid. | `attestation_pool.ts` |
|
|
95
|
-
| Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` =
|
|
95
|
+
| Per-slot cap: `MAX_CHECKPOINT_PROPOSALS_PER_SLOT` = 2 | REJECT + HighToleranceError. Embedded block still processed. | same |
|
|
96
96
|
|
|
97
97
|
### Stage 4: Equivocation Detection
|
|
98
98
|
|
|
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
|
6
6
|
export class BlockProposalValidator implements P2PValidator<BlockProposal> {
|
|
7
7
|
private proposalValidator: ProposalValidator;
|
|
8
8
|
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
epochCache: EpochCacheInterface,
|
|
11
|
+
opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
|
|
12
|
+
) {
|
|
10
13
|
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
|
|
11
14
|
}
|
|
12
15
|
|
|
@@ -6,7 +6,10 @@ import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
|
6
6
|
export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
|
|
7
7
|
private proposalValidator: ProposalValidator;
|
|
8
8
|
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
epochCache: EpochCacheInterface,
|
|
11
|
+
opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
|
|
12
|
+
) {
|
|
10
13
|
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
|
|
11
14
|
}
|
|
12
15
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type ValidationResult,
|
|
9
9
|
} from '@aztec/stdlib/p2p';
|
|
10
10
|
|
|
11
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
11
|
+
import { PipeliningWindow, isWithinClockTolerance } from '../clock_tolerance.js';
|
|
12
12
|
|
|
13
13
|
/** Validates header-level and tx-level fields of block and checkpoint proposals. */
|
|
14
14
|
export class ProposalValidator {
|
|
@@ -16,32 +16,39 @@ export class ProposalValidator {
|
|
|
16
16
|
private logger: Logger;
|
|
17
17
|
private txsPermitted: boolean;
|
|
18
18
|
private maxTxsPerBlock?: number;
|
|
19
|
+
private pipeliningWindow: PipeliningWindow;
|
|
19
20
|
|
|
20
21
|
constructor(
|
|
21
22
|
epochCache: EpochCacheInterface,
|
|
22
|
-
opts: { txsPermitted: boolean; maxTxsPerBlock?: number },
|
|
23
|
+
opts: { txsPermitted: boolean; maxTxsPerBlock?: number; p2pPropagationTime?: number },
|
|
23
24
|
loggerName: string,
|
|
24
25
|
) {
|
|
25
26
|
this.epochCache = epochCache;
|
|
26
27
|
this.txsPermitted = opts.txsPermitted;
|
|
27
28
|
this.maxTxsPerBlock = opts.maxTxsPerBlock;
|
|
29
|
+
this.pipeliningWindow = new PipeliningWindow(epochCache, { p2pPropagationTime: opts.p2pPropagationTime });
|
|
28
30
|
this.logger = createLogger(loggerName);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/** Validates header-level fields: slot, signature, and proposer. */
|
|
32
34
|
public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
|
|
33
35
|
try {
|
|
34
|
-
// Slot check
|
|
35
|
-
const {
|
|
36
|
+
// Slot check: use target slots since proposals target pipeline slots (slot + 1 when pipelining).
|
|
37
|
+
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();
|
|
38
|
+
|
|
36
39
|
const slotNumber = proposal.slotNumber;
|
|
37
|
-
if (slotNumber !==
|
|
38
|
-
//
|
|
39
|
-
if
|
|
40
|
-
|
|
40
|
+
if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
|
|
41
|
+
// When pipelining, accept proposals for the current slot (built in the previous slot)
|
|
42
|
+
// if they're still within the shared proposal acceptance window.
|
|
43
|
+
if (this.pipeliningWindow.acceptsProposal(slotNumber)) {
|
|
44
|
+
// Fall through to remaining validation (signature, proposer, etc.)
|
|
45
|
+
} else if (!isWithinClockTolerance(slotNumber, targetSlot, this.epochCache)) {
|
|
46
|
+
this.logger.warn(`Penalizing peer for invalid slot number ${slotNumber}`, { targetSlot, nextSlot });
|
|
41
47
|
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
48
|
+
} else {
|
|
49
|
+
this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
50
|
+
return { result: 'ignore' };
|
|
42
51
|
}
|
|
43
|
-
this.logger.verbose(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
44
|
-
return { result: 'ignore' };
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
// Signature validity
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { ContractInstancePublishedEvent } from '@aztec/protocol-contracts/instance-registry';
|
|
3
|
+
import { computeContractAddressFromInstance } from '@aztec/stdlib/contract';
|
|
4
|
+
import {
|
|
5
|
+
TX_ERROR_INCORRECT_CONTRACT_ADDRESS,
|
|
6
|
+
TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG,
|
|
7
|
+
type Tx,
|
|
8
|
+
type TxValidationResult,
|
|
9
|
+
type TxValidator,
|
|
10
|
+
} from '@aztec/stdlib/tx';
|
|
11
|
+
|
|
12
|
+
/** Validates that contract instance deployment logs contain correct addresses. */
|
|
13
|
+
export class ContractInstanceTxValidator implements TxValidator<Tx> {
|
|
14
|
+
#log: Logger;
|
|
15
|
+
|
|
16
|
+
constructor(bindings?: LoggerBindings) {
|
|
17
|
+
this.#log = createLogger('p2p:tx_validator:contract_instance', bindings);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
21
|
+
const reason = await this.#hasCorrectContractInstanceAddresses(tx);
|
|
22
|
+
return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async #hasCorrectContractInstanceAddresses(tx: Tx): Promise<string | undefined> {
|
|
26
|
+
const privateLogs = tx.data.getNonEmptyPrivateLogs();
|
|
27
|
+
for (const log of privateLogs) {
|
|
28
|
+
if (!ContractInstancePublishedEvent.isContractInstancePublishedEvent(log)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let event;
|
|
33
|
+
try {
|
|
34
|
+
event = ContractInstancePublishedEvent.fromLog(log);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract instance event: ${e}`);
|
|
37
|
+
return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const instance = event.toContractInstance();
|
|
42
|
+
const computedAddress = await computeContractAddressFromInstance(instance);
|
|
43
|
+
if (!computedAddress.equals(instance.address)) {
|
|
44
|
+
this.#log.warn(
|
|
45
|
+
`Rejecting tx ${tx.getTxHash()}: contract instance address mismatch. Claimed ${instance.address}, computed ${computedAddress}`,
|
|
46
|
+
);
|
|
47
|
+
return TX_ERROR_INCORRECT_CONTRACT_ADDRESS;
|
|
48
|
+
}
|
|
49
|
+
} catch (e) {
|
|
50
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract instance address: ${e}`);
|
|
51
|
+
return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS } from '@aztec/constants';
|
|
2
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
4
|
+
import { computeContractClassId } from '@aztec/stdlib/contract';
|
|
3
5
|
import { computeCalldataHash } from '@aztec/stdlib/hash';
|
|
4
6
|
import {
|
|
5
7
|
TX_ERROR_CALLDATA_COUNT_MISMATCH,
|
|
@@ -9,7 +11,9 @@ import {
|
|
|
9
11
|
TX_ERROR_CONTRACT_CLASS_LOG_LENGTH,
|
|
10
12
|
TX_ERROR_CONTRACT_CLASS_LOG_SORTING,
|
|
11
13
|
TX_ERROR_INCORRECT_CALLDATA,
|
|
14
|
+
TX_ERROR_INCORRECT_CONTRACT_CLASS_ID,
|
|
12
15
|
TX_ERROR_INCORRECT_HASH,
|
|
16
|
+
TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG,
|
|
13
17
|
Tx,
|
|
14
18
|
type TxValidationResult,
|
|
15
19
|
type TxValidator,
|
|
@@ -26,7 +30,8 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
26
30
|
const reason =
|
|
27
31
|
(await this.#hasCorrectHash(tx)) ??
|
|
28
32
|
(await this.#hasCorrectCalldata(tx)) ??
|
|
29
|
-
(await this.#hasCorrectContractClassLogs(tx))
|
|
33
|
+
(await this.#hasCorrectContractClassLogs(tx)) ??
|
|
34
|
+
(await this.#hasCorrectContractClassIds(tx));
|
|
30
35
|
return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -127,4 +132,40 @@ export class DataTxValidator implements TxValidator<Tx> {
|
|
|
127
132
|
|
|
128
133
|
return undefined;
|
|
129
134
|
}
|
|
135
|
+
|
|
136
|
+
async #hasCorrectContractClassIds(tx: Tx): Promise<string | undefined> {
|
|
137
|
+
const contractClassLogs = tx.getContractClassLogs();
|
|
138
|
+
for (const log of contractClassLogs) {
|
|
139
|
+
if (!ContractClassPublishedEvent.isContractClassPublishedEvent(log)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let event;
|
|
144
|
+
try {
|
|
145
|
+
event = ContractClassPublishedEvent.fromLog(log);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract class event: ${e}`);
|
|
148
|
+
return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const { publicBytecodeCommitment } = await event.toContractClassPublicWithBytecodeCommitment();
|
|
153
|
+
const computedClassId = await computeContractClassId({
|
|
154
|
+
artifactHash: event.artifactHash,
|
|
155
|
+
privateFunctionsRoot: event.privateFunctionsRoot,
|
|
156
|
+
publicBytecodeCommitment,
|
|
157
|
+
});
|
|
158
|
+
if (!computedClassId.equals(event.contractClassId)) {
|
|
159
|
+
this.#log.warn(
|
|
160
|
+
`Rejecting tx ${tx.getTxHash()}: contract class id mismatch. Claimed ${event.contractClassId}, computed ${computedClassId}`,
|
|
161
|
+
);
|
|
162
|
+
return TX_ERROR_INCORRECT_CONTRACT_CLASS_ID;
|
|
163
|
+
}
|
|
164
|
+
} catch (e) {
|
|
165
|
+
this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract class id: ${e}`);
|
|
166
|
+
return TX_ERROR_MALFORMED_CONTRACT_CLASS_LOG;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
130
171
|
}
|
|
@@ -53,6 +53,7 @@ import type { TxMetaData } from '../../mem_pools/tx_pool_v2/tx_metadata.js';
|
|
|
53
53
|
import { AggregateTxValidator } from './aggregate_tx_validator.js';
|
|
54
54
|
import { ArchiveCache } from './archive_cache.js';
|
|
55
55
|
import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_validator.js';
|
|
56
|
+
import { ContractInstanceTxValidator } from './contract_instance_validator.js';
|
|
56
57
|
import { DataTxValidator } from './data_validator.js';
|
|
57
58
|
import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
|
|
58
59
|
import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
|
|
@@ -167,6 +168,10 @@ export function createFirstStageTxValidationsForGossipedTransactions(
|
|
|
167
168
|
validator: new DataTxValidator(bindings),
|
|
168
169
|
severity: PeerErrorSeverity.MidToleranceError,
|
|
169
170
|
},
|
|
171
|
+
contractInstanceValidator: {
|
|
172
|
+
validator: new ContractInstanceTxValidator(bindings),
|
|
173
|
+
severity: PeerErrorSeverity.MidToleranceError,
|
|
174
|
+
},
|
|
170
175
|
};
|
|
171
176
|
}
|
|
172
177
|
|
|
@@ -218,6 +223,7 @@ function createTxValidatorForMinimumTxIntegrityChecks(
|
|
|
218
223
|
),
|
|
219
224
|
new SizeTxValidator(bindings),
|
|
220
225
|
new DataTxValidator(bindings),
|
|
226
|
+
new ContractInstanceTxValidator(bindings),
|
|
221
227
|
new TxProofValidator(verifier, bindings),
|
|
222
228
|
);
|
|
223
229
|
}
|
|
@@ -321,6 +327,7 @@ export function createTxValidatorForAcceptingTxsOverRPC(
|
|
|
321
327
|
new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
|
|
322
328
|
new DoubleSpendTxValidator(new NullifierCache(db), bindings),
|
|
323
329
|
new DataTxValidator(bindings),
|
|
330
|
+
new ContractInstanceTxValidator(bindings),
|
|
324
331
|
];
|
|
325
332
|
|
|
326
333
|
if (!skipFeeEnforcement) {
|
|
@@ -87,7 +87,12 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
|
|
|
87
87
|
gasLimits,
|
|
88
88
|
minGasLimits,
|
|
89
89
|
});
|
|
90
|
-
return {
|
|
90
|
+
return {
|
|
91
|
+
result: 'invalid',
|
|
92
|
+
reason: [
|
|
93
|
+
`${TX_ERROR_INSUFFICIENT_GAS_LIMIT} (required=da:${minGasLimits.daGas},l2:${minGasLimits.l2Gas} got=da:${gasLimits.daGas},l2:${gasLimits.l2Gas})`,
|
|
94
|
+
],
|
|
95
|
+
};
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
if (gasLimits.l2Gas > this.#effectiveMaxL2Gas) {
|
|
@@ -97,7 +102,10 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
|
|
|
97
102
|
rollupManaLimit: this.#rollupManaLimit,
|
|
98
103
|
maxBlockL2Gas: this.#maxBlockL2Gas,
|
|
99
104
|
});
|
|
100
|
-
return {
|
|
105
|
+
return {
|
|
106
|
+
result: 'invalid',
|
|
107
|
+
reason: [`${TX_ERROR_GAS_LIMIT_TOO_HIGH} (l2Gas=${gasLimits.l2Gas}, max=${this.#effectiveMaxL2Gas})`],
|
|
108
|
+
};
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
if (gasLimits.daGas > this.#effectiveMaxDAGas) {
|
|
@@ -106,7 +114,10 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
|
|
|
106
114
|
effectiveMaxDAGas: this.#effectiveMaxDAGas,
|
|
107
115
|
maxBlockDAGas: this.#maxBlockDAGas,
|
|
108
116
|
});
|
|
109
|
-
return {
|
|
117
|
+
return {
|
|
118
|
+
result: 'invalid',
|
|
119
|
+
reason: [`${TX_ERROR_GAS_LIMIT_TOO_HIGH} (daGas=${gasLimits.daGas}, max=${this.#effectiveMaxDAGas})`],
|
|
120
|
+
};
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
return { result: 'valid' };
|
|
@@ -157,19 +168,20 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
157
168
|
if (gasLimitValidation.result === 'invalid') {
|
|
158
169
|
return Promise.resolve(gasLimitValidation);
|
|
159
170
|
}
|
|
160
|
-
|
|
161
|
-
|
|
171
|
+
const skipReason = this.#getSkipReason(tx);
|
|
172
|
+
if (skipReason) {
|
|
173
|
+
return Promise.resolve({ result: 'skipped', reason: [skipReason] });
|
|
162
174
|
}
|
|
163
175
|
return await this.validateTxFee(tx);
|
|
164
176
|
}
|
|
165
177
|
|
|
166
178
|
/**
|
|
167
|
-
* Check whether the tx's max fees are valid for the current block, and skip if not.
|
|
179
|
+
* Check whether the tx's max fees are valid for the current block, and return a skip reason if not.
|
|
168
180
|
* We skip instead of invalidating since the tx may become eligible later.
|
|
169
181
|
* Note that circuits check max fees even if fee payer is unset, so we
|
|
170
182
|
* keep this validation even if the tx does not pay fees.
|
|
171
183
|
*/
|
|
172
|
-
#
|
|
184
|
+
#getSkipReason(tx: Tx): string | undefined {
|
|
173
185
|
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
174
186
|
|
|
175
187
|
// Skip the tx if its max fees are not enough for the current block's gas fees.
|
|
@@ -182,8 +194,9 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
182
194
|
txMaxFeesPerGas: maxFeesPerGas.toInspect(),
|
|
183
195
|
currentGasFees: this.#gasFees.toInspect(),
|
|
184
196
|
});
|
|
197
|
+
return `${TX_ERROR_INSUFFICIENT_FEE_PER_GAS} (maxFee=da:${maxFeesPerGas.feePerDaGas},l2:${maxFeesPerGas.feePerL2Gas} required=da:${this.#gasFees.feePerDaGas},l2:${this.#gasFees.feePerL2Gas})`;
|
|
185
198
|
}
|
|
186
|
-
return
|
|
199
|
+
return undefined;
|
|
187
200
|
}
|
|
188
201
|
|
|
189
202
|
/**
|
|
@@ -212,7 +225,10 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
212
225
|
balance,
|
|
213
226
|
feeLimit,
|
|
214
227
|
});
|
|
215
|
-
return {
|
|
228
|
+
return {
|
|
229
|
+
result: 'invalid',
|
|
230
|
+
reason: [`${TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE} (required=${feeLimit}, available=${balance})`],
|
|
231
|
+
};
|
|
216
232
|
}
|
|
217
233
|
return { result: 'valid' };
|
|
218
234
|
}
|
|
@@ -40,7 +40,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
40
40
|
// which are needed for public FPC flows, but fail if the account contract hasnt been deployed yet,
|
|
41
41
|
// which is what we're trying to do as part of the current txs.
|
|
42
42
|
// We only need to create/revert checkpoint here because of this addNewContracts call.
|
|
43
|
-
|
|
43
|
+
this.contractsDB.addNewContracts(tx);
|
|
44
44
|
|
|
45
45
|
if (!tx.data.forPublic) {
|
|
46
46
|
this.#log.debug(
|