@aztec/p2p 0.0.1-commit.d6f2b3f94 → 0.0.1-commit.dbf9cec
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 +6 -6
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +23 -30
- package/dest/client/interface.d.ts +14 -19
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +9 -18
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +52 -72
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +6 -7
- package/dest/config.d.ts +13 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +5 -5
- package/dest/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- 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 -0
- package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +3 -3
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +30 -13
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +91 -20
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +5 -2
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -2
- 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 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +48 -5
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +7 -5
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
- 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 +14 -4
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
- 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/index.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +1 -1
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +20 -6
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +4 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +34 -8
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +76 -10
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +12 -3
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +36 -14
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -4
- 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 +11 -6
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +13 -5
- 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 +297 -143
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
- package/dest/msg_validators/tx_validator/factory.d.ts +114 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +219 -58
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +58 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +73 -36
- 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/nullifier_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +2 -2
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
- package/dest/services/dummy_service.d.ts +4 -4
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +4 -4
- package/dest/services/encoding.d.ts +2 -2
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +9 -8
- package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
- package/dest/services/gossipsub/topic_score_params.js +32 -10
- package/dest/services/libp2p/libp2p_service.d.ts +16 -13
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +69 -81
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
- 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 +19 -46
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -13
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +25 -46
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +17 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +49 -15
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
- 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 +2 -1
- package/dest/services/service.d.ts +5 -3
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +13 -1
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +30 -0
- package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +39 -33
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +38 -29
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_collection.js +126 -77
- package/dest/services/tx_collection/file_store_tx_source.d.ts +16 -6
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/file_store_tx_source.js +49 -16
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +2 -1
- package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
- package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
- package/dest/services/tx_collection/slow_tx_collection.d.ts +5 -3
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +17 -12
- package/dest/services/tx_collection/tx_collection.d.ts +9 -6
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +26 -10
- package/dest/services/tx_collection/tx_collection_sink.d.ts +6 -5
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +13 -22
- package/dest/services/tx_collection/tx_source.d.ts +8 -3
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +19 -2
- package/dest/services/tx_file_store/tx_file_store.d.ts +3 -2
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +9 -6
- package/dest/services/tx_provider.d.ts +3 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +4 -4
- package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +1 -2
- package/dest/test-helpers/mock-pubsub.d.ts +4 -4
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +8 -2
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +2 -2
- package/dest/test-helpers/testbench-utils.d.ts +8 -3
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +7 -1
- package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +13 -13
- package/dest/util.d.ts +2 -2
- package/dest/util.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +39 -48
- package/src/client/interface.ts +17 -20
- package/src/client/p2p_client.ts +60 -104
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -10
- package/src/config.ts +10 -10
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +8 -0
- package/src/mem_pools/attestation_pool/mocks.ts +2 -1
- package/src/mem_pools/tx_pool/README.md +1 -1
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/README.md +43 -27
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +109 -22
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +5 -2
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +49 -4
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +24 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +3 -3
- package/src/mem_pools/tx_pool_v2/index.ts +1 -1
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +21 -6
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +107 -17
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +43 -16
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +18 -7
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +326 -138
- package/src/msg_validators/tx_validator/README.md +115 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
- package/src/msg_validators/tx_validator/factory.ts +353 -77
- package/src/msg_validators/tx_validator/gas_validator.ts +90 -27
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/timestamp_validator.ts +7 -7
- package/src/services/dummy_service.ts +6 -6
- package/src/services/encoding.ts +7 -7
- package/src/services/gossipsub/README.md +29 -14
- package/src/services/gossipsub/topic_score_params.ts +49 -13
- package/src/services/libp2p/libp2p_service.ts +80 -90
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +20 -48
- package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +63 -24
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
- package/src/services/reqresp/reqresp.ts +3 -1
- package/src/services/service.ts +11 -2
- package/src/services/tx_collection/config.ts +42 -0
- package/src/services/tx_collection/fast_tx_collection.ts +51 -30
- package/src/services/tx_collection/file_store_tx_collection.ts +143 -93
- package/src/services/tx_collection/file_store_tx_source.ts +64 -17
- package/src/services/tx_collection/instrumentation.ts +7 -1
- package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
- package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
- package/src/services/tx_collection/slow_tx_collection.ts +17 -13
- package/src/services/tx_collection/tx_collection.ts +45 -14
- package/src/services/tx_collection/tx_collection_sink.ts +15 -29
- package/src/services/tx_collection/tx_source.ts +22 -3
- package/src/services/tx_file_store/tx_file_store.ts +6 -4
- package/src/services/tx_provider.ts +2 -2
- package/src/test-helpers/make-test-p2p-clients.ts +0 -2
- package/src/test-helpers/mock-pubsub.ts +13 -6
- package/src/test-helpers/reqresp-nodes.ts +2 -5
- package/src/test-helpers/testbench-utils.ts +11 -3
- package/src/testbench/p2p_client_testbench_worker.ts +22 -19
- package/src/util.ts +7 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
MAX_PROCESSABLE_L2_GAS,
|
|
3
|
+
PRIVATE_TX_L2_GAS_OVERHEAD,
|
|
4
|
+
PUBLIC_TX_L2_GAS_OVERHEAD,
|
|
5
|
+
TX_DA_GAS_OVERHEAD,
|
|
6
|
+
} from '@aztec/constants';
|
|
2
7
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
8
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
4
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -16,6 +21,86 @@ import {
|
|
|
16
21
|
|
|
17
22
|
import { getFeePayerClaimAmount, getTxFeeLimit } from './fee_payer_balance.js';
|
|
18
23
|
|
|
24
|
+
/** Structural interface for types that carry gas limit data, used by {@link GasLimitsValidator}. */
|
|
25
|
+
export interface HasGasLimitData {
|
|
26
|
+
txHash: { toString(): string };
|
|
27
|
+
data: {
|
|
28
|
+
// We just need to know whether there is something here or not
|
|
29
|
+
forPublic?: unknown;
|
|
30
|
+
constants: {
|
|
31
|
+
txContext: {
|
|
32
|
+
gasSettings: { gasLimits: Gas };
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validates that a transaction's gas limits are within acceptable bounds.
|
|
40
|
+
*
|
|
41
|
+
* Rejects transactions whose gas limits fall below the fixed minimums (FIXED_DA_GAS,
|
|
42
|
+
* FIXED_L2_GAS) or exceed the AVM's maximum processable L2 gas. This is a cheap,
|
|
43
|
+
* stateless check that operates on gas settings alone.
|
|
44
|
+
*
|
|
45
|
+
* Generic over T so it can validate both full {@link Tx} objects and {@link TxMetaData}
|
|
46
|
+
* (used during pending pool migration).
|
|
47
|
+
*
|
|
48
|
+
* Used by: pending pool migration (via factory), and indirectly by {@link GasTxValidator}.
|
|
49
|
+
*/
|
|
50
|
+
export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidator<T> {
|
|
51
|
+
#log: Logger;
|
|
52
|
+
|
|
53
|
+
constructor(bindings?: LoggerBindings) {
|
|
54
|
+
this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
validateTx(tx: T): Promise<TxValidationResult> {
|
|
58
|
+
return Promise.resolve(this.validateGasLimit(tx));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Checks gas limits are >= fixed minimums and <= AVM max processable L2 gas. */
|
|
62
|
+
validateGasLimit(tx: T): TxValidationResult {
|
|
63
|
+
const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
64
|
+
const minGasLimits = new Gas(
|
|
65
|
+
TX_DA_GAS_OVERHEAD,
|
|
66
|
+
tx.data.forPublic ? PUBLIC_TX_L2_GAS_OVERHEAD : PRIVATE_TX_L2_GAS_OVERHEAD,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (minGasLimits.gtAny(gasLimits)) {
|
|
70
|
+
this.#log.verbose(`Rejecting transaction due to the gas limit(s) not being above the minimum gas limit`, {
|
|
71
|
+
gasLimits,
|
|
72
|
+
minGasLimits,
|
|
73
|
+
});
|
|
74
|
+
return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (gasLimits.l2Gas > MAX_PROCESSABLE_L2_GAS) {
|
|
78
|
+
this.#log.verbose(`Rejecting transaction due to the gas limit(s) being higher than the maximum processable gas`, {
|
|
79
|
+
gasLimits,
|
|
80
|
+
minGasLimits,
|
|
81
|
+
});
|
|
82
|
+
return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { result: 'valid' };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validates that a transaction can pay its gas fees.
|
|
91
|
+
*
|
|
92
|
+
* Runs three checks in order:
|
|
93
|
+
* 1. **Gas limits** (delegates to {@link GasLimitsValidator}) — rejects if limits are
|
|
94
|
+
* out of bounds.
|
|
95
|
+
* 2. **Max fee per gas** — skips (not rejects) the tx if its maxFeesPerGas is below
|
|
96
|
+
* the current block's gas fees. We skip rather than reject because the tx may
|
|
97
|
+
* become eligible in a later block with lower fees.
|
|
98
|
+
* 3. **Fee payer balance** — reads the fee payer's FeeJuice balance from public state,
|
|
99
|
+
* adds any pending claim from a setup-phase `_increase_public_balance` call, and
|
|
100
|
+
* rejects if the total is less than the tx's fee limit (gasLimits * maxFeePerGas).
|
|
101
|
+
*
|
|
102
|
+
* Used by: gossip (stage 1), RPC, and block building validators.
|
|
103
|
+
*/
|
|
19
104
|
export class GasTxValidator implements TxValidator<Tx> {
|
|
20
105
|
#log: Logger;
|
|
21
106
|
#publicDataSource: PublicStateSource;
|
|
@@ -26,7 +111,7 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
26
111
|
publicDataSource: PublicStateSource,
|
|
27
112
|
feeJuiceAddress: AztecAddress,
|
|
28
113
|
gasFees: GasFees,
|
|
29
|
-
bindings?: LoggerBindings,
|
|
114
|
+
private bindings?: LoggerBindings,
|
|
30
115
|
) {
|
|
31
116
|
this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
|
|
32
117
|
this.#publicDataSource = publicDataSource;
|
|
@@ -35,7 +120,7 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
35
120
|
}
|
|
36
121
|
|
|
37
122
|
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
38
|
-
const gasLimitValidation = this
|
|
123
|
+
const gasLimitValidation = new GasLimitsValidator(this.bindings).validateGasLimit(tx);
|
|
39
124
|
if (gasLimitValidation.result === 'invalid') {
|
|
40
125
|
return Promise.resolve(gasLimitValidation);
|
|
41
126
|
}
|
|
@@ -69,31 +154,9 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
69
154
|
}
|
|
70
155
|
|
|
71
156
|
/**
|
|
72
|
-
*
|
|
157
|
+
* Checks the fee payer has enough FeeJuice balance to cover the tx's fee limit.
|
|
158
|
+
* Accounts for any pending claim from a setup-phase `_increase_public_balance` call.
|
|
73
159
|
*/
|
|
74
|
-
#validateGasLimit(tx: Tx): TxValidationResult {
|
|
75
|
-
const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
76
|
-
const minGasLimits = new Gas(FIXED_DA_GAS, FIXED_L2_GAS);
|
|
77
|
-
|
|
78
|
-
if (minGasLimits.gtAny(gasLimits)) {
|
|
79
|
-
this.#log.verbose(`Rejecting transaction due to the gas limit(s) not being above the minimum gas limit`, {
|
|
80
|
-
gasLimits,
|
|
81
|
-
minGasLimits,
|
|
82
|
-
});
|
|
83
|
-
return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (gasLimits.l2Gas > AVM_MAX_PROCESSABLE_L2_GAS) {
|
|
87
|
-
this.#log.verbose(`Rejecting transaction due to the gas limit(s) being higher than the maximum processable gas`, {
|
|
88
|
-
gasLimits,
|
|
89
|
-
minGasLimits,
|
|
90
|
-
});
|
|
91
|
-
return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return { result: 'valid' };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
160
|
public async validateTxFee(tx: Tx): Promise<TxValidationResult> {
|
|
98
161
|
const feePayer = tx.data.feePayer;
|
|
99
162
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NullifierSource } from '@aztec/p2p';
|
|
2
|
+
import type { MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
|
|
3
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Implements a nullifier source by checking a DB and an in-memory collection.
|
|
7
|
+
* Intended for validating transactions as they are added to a block.
|
|
8
|
+
*/
|
|
9
|
+
export class NullifierCache implements NullifierSource {
|
|
10
|
+
nullifiers: Set<string>;
|
|
11
|
+
|
|
12
|
+
constructor(private db: MerkleTreeReadOperations) {
|
|
13
|
+
this.nullifiers = new Set();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async nullifiersExist(nullifiers: Buffer[]): Promise<boolean[]> {
|
|
17
|
+
const cacheResults = nullifiers.map(n => this.nullifiers.has(n.toString()));
|
|
18
|
+
const toCheckDb = nullifiers.filter((_n, index) => !cacheResults[index]);
|
|
19
|
+
const dbHits = await this.db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, toCheckDb);
|
|
20
|
+
|
|
21
|
+
let dbIndex = 0;
|
|
22
|
+
return nullifiers.map((_n, index) => cacheResults[index] || dbHits[dbIndex++] !== undefined);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public addNullifiers(nullifiers: Buffer[]) {
|
|
26
|
+
for (const nullifier of nullifiers) {
|
|
27
|
+
this.nullifiers.add(nullifier.toString());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import {
|
|
3
|
+
import { TX_ERROR_INVALID_EXPIRATION_TIMESTAMP, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
4
4
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
5
5
|
|
|
6
6
|
/** Structural interface for timestamp validation. */
|
|
7
7
|
export interface HasTimestampData {
|
|
8
8
|
txHash: { toString(): string };
|
|
9
9
|
data: {
|
|
10
|
-
|
|
10
|
+
expirationTimestamp: bigint;
|
|
11
11
|
constants: {
|
|
12
12
|
anchorBlockHeader: {
|
|
13
13
|
globalVariables: {
|
|
@@ -35,21 +35,21 @@ export class TimestampTxValidator<T extends HasTimestampData> implements TxValid
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
validateTx(tx: T): Promise<TxValidationResult> {
|
|
38
|
-
const
|
|
39
|
-
// If building block 1, we skip the expiration check. For details on why see the `
|
|
38
|
+
const expirationTimestamp = tx.data.expirationTimestamp;
|
|
39
|
+
// If building block 1, we skip the expiration check. For details on why see the `validate_expiration_timestamp`
|
|
40
40
|
// function in `noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/validation_requests.nr`.
|
|
41
41
|
const buildingBlock1 = this.values.blockNumber === 1;
|
|
42
42
|
|
|
43
|
-
if (!buildingBlock1 &&
|
|
43
|
+
if (!buildingBlock1 && expirationTimestamp < this.values.timestamp) {
|
|
44
44
|
if (tx.data.constants.anchorBlockHeader.globalVariables.blockNumber === 0) {
|
|
45
45
|
this.#log.warn(
|
|
46
46
|
`A tx built against a genesis block failed to be included in block 1 which is the only block in which txs built against a genesis block are allowed to be included.`,
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
this.#log.verbose(
|
|
50
|
-
`Rejecting tx ${tx.txHash} for low expiration timestamp. Tx expiration timestamp: ${
|
|
50
|
+
`Rejecting tx ${tx.txHash} for low expiration timestamp. Tx expiration timestamp: ${expirationTimestamp}, timestamp: ${this.values.timestamp}.`,
|
|
51
51
|
);
|
|
52
|
-
return Promise.resolve({ result: 'invalid', reason: [
|
|
52
|
+
return Promise.resolve({ result: 'invalid', reason: [TX_ERROR_INVALID_EXPIRATION_TIMESTAMP] });
|
|
53
53
|
} else {
|
|
54
54
|
return Promise.resolve({ result: 'valid' });
|
|
55
55
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
2
|
import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
3
|
-
import type { Gossipable, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
|
+
import type { Gossipable, PeerErrorSeverity, TopicType } from '@aztec/stdlib/p2p';
|
|
4
4
|
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
5
5
|
|
|
6
6
|
import type { PeerId } from '@libp2p/interface';
|
|
@@ -44,6 +44,10 @@ export class DummyP2PService implements P2PService {
|
|
|
44
44
|
return [];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
getGossipMeshPeerCount(_topicType: TopicType): number {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
47
51
|
/**
|
|
48
52
|
* Starts the dummy implementation.
|
|
49
53
|
* @returns A resolved promise.
|
|
@@ -137,14 +141,10 @@ export class DummyP2PService implements P2PService {
|
|
|
137
141
|
return undefined;
|
|
138
142
|
}
|
|
139
143
|
|
|
140
|
-
|
|
144
|
+
validateTxsReceivedInBlockProposal(_txs: Tx[]): Promise<void> {
|
|
141
145
|
return Promise.resolve();
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
validatePropagatedTx(_tx: Tx, _peerId: PeerId): Promise<boolean> {
|
|
145
|
-
return Promise.resolve(true);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
148
|
addReqRespSubProtocol(
|
|
149
149
|
_subProtocol: ReqRespSubProtocol,
|
|
150
150
|
_handler: ReqRespSubProtocolHandler,
|
package/src/services/encoding.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Taken from lodestar: https://github.com/ChainSafe/lodestar
|
|
2
|
-
import { sha256 } from '@aztec/foundation/crypto/sha256';
|
|
3
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { MAX_TX_SIZE_KB, TopicType, getTopicFromString } from '@aztec/stdlib/p2p';
|
|
5
4
|
|
|
6
5
|
import type { RPC } from '@chainsafe/libp2p-gossipsub/message';
|
|
7
6
|
import type { DataTransform } from '@chainsafe/libp2p-gossipsub/types';
|
|
8
7
|
import type { Message } from '@libp2p/interface';
|
|
8
|
+
import { webcrypto } from 'node:crypto';
|
|
9
9
|
import { compressSync, uncompressSync } from 'snappy';
|
|
10
10
|
import xxhashFactory from 'xxhash-wasm';
|
|
11
11
|
|
|
@@ -44,11 +44,10 @@ export function msgIdToStrFn(msgId: Uint8Array): string {
|
|
|
44
44
|
* @param message - The libp2p message
|
|
45
45
|
* @returns The message identifier
|
|
46
46
|
*/
|
|
47
|
-
export function getMsgIdFn(
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return sha256(Buffer.concat(vec)).subarray(0, 20);
|
|
47
|
+
export async function getMsgIdFn({ topic, data }: Message): Promise<Uint8Array> {
|
|
48
|
+
const buffer = Buffer.concat([Buffer.from(topic), data]);
|
|
49
|
+
const hash = await webcrypto.subtle.digest('SHA-256', buffer);
|
|
50
|
+
return Buffer.from(hash.slice(0, 20));
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
const DefaultMaxSizesKb: Record<TopicType, number> = {
|
|
@@ -58,7 +57,8 @@ const DefaultMaxSizesKb: Record<TopicType, number> = {
|
|
|
58
57
|
// Proposals may carry some tx objects, so we allow a larger size capped at 10mb
|
|
59
58
|
// Note this may not be enough for carrying all tx objects in a block
|
|
60
59
|
[TopicType.block_proposal]: 1024 * 10,
|
|
61
|
-
//
|
|
60
|
+
// Checkpoint proposals carry almost the same data as a block proposal (see the lastBlockProposal)
|
|
61
|
+
// Only diff is an additional header, which is pretty small compared to the 10mb limit
|
|
62
62
|
[TopicType.checkpoint_proposal]: 1024 * 10,
|
|
63
63
|
};
|
|
64
64
|
|
|
@@ -40,7 +40,7 @@ We configure all parameters (P1-P4) with values calculated dynamically from netw
|
|
|
40
40
|
| P3b: meshFailurePenalty | -34 per topic | Sticky penalty after pruning |
|
|
41
41
|
| P4: invalidMessageDeliveries | -20 per message | Attack detection |
|
|
42
42
|
|
|
43
|
-
**Important:** P1 and P2 are only enabled on topics with P3 enabled
|
|
43
|
+
**Important:** P1 and P2 are only enabled on topics with P3 enabled. By default, P3 is enabled for checkpoint_proposal and checkpoint_attestation (2 topics). Block proposal scoring is controlled by `expectedBlockProposalsPerSlot` (current default: `0`, including when env var is unset, so disabled) - see [Block Proposals](#block-proposals-block_proposal) for details. The tx topic has all scoring disabled except P4, to prevent free positive score accumulation that would offset penalties from other topics.
|
|
44
44
|
|
|
45
45
|
## Exponential Decay
|
|
46
46
|
|
|
@@ -217,7 +217,21 @@ Transactions are submitted unpredictably by users, so we cannot set meaningful d
|
|
|
217
217
|
|
|
218
218
|
### Block Proposals (block_proposal)
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
Block proposal scoring is controlled by the `expectedBlockProposalsPerSlot` config (`SEQ_EXPECTED_BLOCK_PROPOSALS_PER_SLOT` env var):
|
|
221
|
+
|
|
222
|
+
| Config Value | Behavior |
|
|
223
|
+
|-------------|----------|
|
|
224
|
+
| `0` (current default) | Block proposal P3 scoring is **disabled** |
|
|
225
|
+
| Positive number | Uses the provided value as expected proposals per slot |
|
|
226
|
+
| `undefined` | Falls back to `blocksPerSlot - 1` (MBPS mode: N-1, single block: 0) |
|
|
227
|
+
|
|
228
|
+
**Current behavior note:** In the current implementation, if `SEQ_EXPECTED_BLOCK_PROPOSALS_PER_SLOT` is not set, config mapping applies `0` by default (scoring disabled). The `undefined` fallback above is currently reachable only if the value is explicitly provided as `undefined` in code.
|
|
229
|
+
|
|
230
|
+
**Future intent:** Once throughput is stable, we may change env parsing/defaults so an unset env var resolves to `undefined` again (re-enabling automatic fallback to `blocksPerSlot - 1`).
|
|
231
|
+
|
|
232
|
+
**Why disabled by default?** In MBPS mode, gossipsub expects N-1 block proposals per slot. When transaction throughput is low (as expected at launch), fewer blocks are actually built, causing peers to be incorrectly penalized for under-delivering block proposals. The default of 0 disables this scoring. Set to a positive value when throughput increases and block production is consistent.
|
|
233
|
+
|
|
234
|
+
In MBPS mode (when enabled), N-1 block proposals are gossiped per slot (the last block is bundled with the checkpoint). In single-block mode, this is 0.
|
|
221
235
|
|
|
222
236
|
### Checkpoint Proposals (checkpoint_proposal)
|
|
223
237
|
|
|
@@ -241,6 +255,7 @@ The scoring parameters depend on:
|
|
|
241
255
|
| `targetCommitteeSize` | L1RollupConstants | 48 |
|
|
242
256
|
| `heartbeatInterval` | P2PConfig.gossipsubInterval | 700ms |
|
|
243
257
|
| `blockDurationMs` | P2PConfig.blockDurationMs | undefined (single block) |
|
|
258
|
+
| `expectedBlockProposalsPerSlot` | P2PConfig.expectedBlockProposalsPerSlot | 0 (disabled; current unset-env behavior) |
|
|
244
259
|
|
|
245
260
|
## Invalid Message Handling (P4)
|
|
246
261
|
|
|
@@ -320,9 +335,9 @@ Conversely, if topic scores are low, a peer slightly above the disconnect thresh
|
|
|
320
335
|
|
|
321
336
|
Topic scores provide **burst response** to attacks, while app score provides **stable baseline**:
|
|
322
337
|
|
|
323
|
-
- P1 (time in mesh): Max +8 per topic (+24
|
|
324
|
-
- P2 (first deliveries): Max +25 per topic (+75
|
|
325
|
-
- P3 (under-delivery): Max -34 per topic (-
|
|
338
|
+
- P1 (time in mesh): Max +8 per topic (+16 default, +24 with block proposal scoring enabled)
|
|
339
|
+
- P2 (first deliveries): Max +25 per topic (+50 default, +75 with block proposal scoring, but decays fast)
|
|
340
|
+
- P3 (under-delivery): Max -34 per topic (-68 default with 2 topics, -102 with block proposal scoring enabled)
|
|
326
341
|
- P4 (invalid messages): -20 per invalid message, can spike to -2000+ during attacks
|
|
327
342
|
|
|
328
343
|
Example attack scenario:
|
|
@@ -373,21 +388,21 @@ When a peer is pruned from the mesh:
|
|
|
373
388
|
3. **P3b captures the penalty**: The P3 deficit at prune time becomes P3b, which decays slowly
|
|
374
389
|
|
|
375
390
|
After pruning, the peer's score consists mainly of P3b:
|
|
376
|
-
- **Total P3b
|
|
391
|
+
- **Total P3b: -68** (default, 2 topics) or **-102** (with block proposal scoring enabled, 3 topics)
|
|
377
392
|
- **Recovery time**: P3b decays to ~1% over one decay window (2-5 slots = 2-6 minutes)
|
|
378
393
|
- **Grafting eligibility**: Peer can be grafted when score ≥ 0, but asymptotic decay means recovery is slow
|
|
379
394
|
|
|
380
395
|
### Why Non-Contributors Aren't Disconnected
|
|
381
396
|
|
|
382
|
-
With P3b capped at -
|
|
397
|
+
With P3b capped at -68 (default, 2 topics) or -102 (with block proposal scoring, 3 topics) after pruning:
|
|
383
398
|
|
|
384
399
|
| Threshold | Value | P3b Score | Triggered? |
|
|
385
400
|
|-----------|-------|-----------|------------|
|
|
386
|
-
| gossipThreshold | -500 | -
|
|
387
|
-
| publishThreshold | -1000 | -
|
|
388
|
-
| graylistThreshold | -2000 | -
|
|
401
|
+
| gossipThreshold | -500 | -68 (default) / -102 (block scoring on) | No |
|
|
402
|
+
| publishThreshold | -1000 | -68 (default) / -102 (block scoring on) | No |
|
|
403
|
+
| graylistThreshold | -2000 | -68 (default) / -102 (block scoring on) | No |
|
|
389
404
|
|
|
390
|
-
**A score of -
|
|
405
|
+
**A score of -68 or -102 is well above -500**, so non-contributing peers:
|
|
391
406
|
- Are pruned from mesh (good - stops them slowing propagation)
|
|
392
407
|
- Still receive gossip (can recover by reconnecting/restarting)
|
|
393
408
|
- Are NOT disconnected unless they also have application-level penalties
|
|
@@ -547,7 +562,7 @@ What happens when a peer experiences a network outage and stops delivering messa
|
|
|
547
562
|
While the peer is disconnected:
|
|
548
563
|
|
|
549
564
|
1. **P3 penalty accumulates**: The message delivery counter decays toward 0, causing increasing P3 penalty
|
|
550
|
-
2. **Max P3 penalty reached**: Once counter drops below threshold, penalty hits -34 per topic (-102
|
|
565
|
+
2. **Max P3 penalty reached**: Once counter drops below threshold, penalty hits -34 per topic (-68 default, -102 with block proposal scoring)
|
|
551
566
|
3. **Mesh pruning**: Topic score goes negative → peer is pruned from mesh
|
|
552
567
|
4. **P3b captures penalty**: The P3 deficit at prune time becomes P3b (sticky penalty)
|
|
553
568
|
|
|
@@ -569,13 +584,13 @@ Note: If the peer just joined the mesh, P3 penalties only start after
|
|
|
569
584
|
During a network outage, the peer:
|
|
570
585
|
- **Does NOT send invalid messages** → No P4 penalty
|
|
571
586
|
- **Does NOT violate protocols** → No application-level penalty
|
|
572
|
-
- **Only accumulates topic-level penalties** → Max -
|
|
587
|
+
- **Only accumulates topic-level penalties** → Max -68 (default) or -102 (with block proposal scoring)
|
|
573
588
|
|
|
574
589
|
This is the crucial difference from malicious behavior:
|
|
575
590
|
|
|
576
591
|
| Scenario | App Score | Topic Score | Total | Threshold Hit |
|
|
577
592
|
|----------|-----------|-------------|-------|---------------|
|
|
578
|
-
| Network outage | 0 | -
|
|
593
|
+
| Network outage | 0 | -68 (default) / -102 (block scoring on) | -68 / -102 | None |
|
|
579
594
|
| Validation failure | -50 | -20 | -520 | gossipThreshold |
|
|
580
595
|
| Malicious peer | -100 | -2000+ | -2100+ | graylistThreshold |
|
|
581
596
|
|
|
@@ -15,6 +15,8 @@ export type TopicScoringNetworkParams = {
|
|
|
15
15
|
targetCommitteeSize: number;
|
|
16
16
|
/** Duration per block in milliseconds when building multiple blocks per slot. If undefined, single block mode. */
|
|
17
17
|
blockDurationMs?: number;
|
|
18
|
+
/** Expected number of block proposals per slot for scoring override. 0 disables scoring, undefined falls back to blocksPerSlot - 1. */
|
|
19
|
+
expectedBlockProposalsPerSlot?: number;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -89,18 +91,41 @@ export function computeThreshold(convergence: number, conservativeFactor: number
|
|
|
89
91
|
return convergence * conservativeFactor;
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Determines the effective expected block proposals per slot for scoring.
|
|
96
|
+
* Returns undefined if scoring should be disabled, or a positive number if enabled.
|
|
97
|
+
*
|
|
98
|
+
* @param blocksPerSlot - Number of blocks per slot from timetable
|
|
99
|
+
* @param expectedBlockProposalsPerSlot - Config override. 0 disables scoring, undefined falls back to blocksPerSlot - 1.
|
|
100
|
+
* @returns Positive number of expected block proposals, or undefined if scoring is disabled
|
|
101
|
+
*/
|
|
102
|
+
export function getEffectiveBlockProposalsPerSlot(
|
|
103
|
+
blocksPerSlot: number,
|
|
104
|
+
expectedBlockProposalsPerSlot?: number,
|
|
105
|
+
): number | undefined {
|
|
106
|
+
if (expectedBlockProposalsPerSlot !== undefined) {
|
|
107
|
+
return expectedBlockProposalsPerSlot > 0 ? expectedBlockProposalsPerSlot : undefined;
|
|
108
|
+
}
|
|
109
|
+
// Fallback: In MBPS mode, N-1 block proposals per slot (last one bundled with checkpoint)
|
|
110
|
+
// In single block mode (blocksPerSlot=1), this is 0 → disabled
|
|
111
|
+
const fallback = Math.max(0, blocksPerSlot - 1);
|
|
112
|
+
return fallback > 0 ? fallback : undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
92
115
|
/**
|
|
93
116
|
* Gets the expected messages per slot for a given topic type.
|
|
94
117
|
*
|
|
95
118
|
* @param topicType - The topic type
|
|
96
119
|
* @param targetCommitteeSize - Target committee size
|
|
97
120
|
* @param blocksPerSlot - Number of blocks per slot
|
|
121
|
+
* @param expectedBlockProposalsPerSlot - Override for block proposals. 0 disables scoring, undefined falls back to blocksPerSlot - 1.
|
|
98
122
|
* @returns Expected messages per slot, or undefined if unpredictable
|
|
99
123
|
*/
|
|
100
124
|
export function getExpectedMessagesPerSlot(
|
|
101
125
|
topicType: TopicType,
|
|
102
126
|
targetCommitteeSize: number,
|
|
103
127
|
blocksPerSlot: number,
|
|
128
|
+
expectedBlockProposalsPerSlot?: number,
|
|
104
129
|
): number | undefined {
|
|
105
130
|
switch (topicType) {
|
|
106
131
|
case TopicType.tx:
|
|
@@ -108,9 +133,7 @@ export function getExpectedMessagesPerSlot(
|
|
|
108
133
|
return undefined;
|
|
109
134
|
|
|
110
135
|
case TopicType.block_proposal:
|
|
111
|
-
|
|
112
|
-
// In single block mode (blocksPerSlot=1), this is 0
|
|
113
|
-
return Math.max(0, blocksPerSlot - 1);
|
|
136
|
+
return getEffectiveBlockProposalsPerSlot(blocksPerSlot, expectedBlockProposalsPerSlot);
|
|
114
137
|
|
|
115
138
|
case TopicType.checkpoint_proposal:
|
|
116
139
|
// Exactly 1 checkpoint proposal per slot
|
|
@@ -190,10 +213,12 @@ const P2_DECAY_WINDOW_SLOTS = 2;
|
|
|
190
213
|
// |P3| > 8 + 25 = 33
|
|
191
214
|
//
|
|
192
215
|
// We set P3 max = -34 per topic (slightly more than P1+P2) to ensure pruning.
|
|
193
|
-
//
|
|
216
|
+
// The number of P3-enabled topics depends on config: by default 2 (checkpoint_proposal +
|
|
217
|
+
// checkpoint_attestation), or 3 if block proposal scoring is enabled via
|
|
218
|
+
// expectedBlockProposalsPerSlot. Total P3b after pruning = -68 (2 topics) or -102 (3 topics).
|
|
194
219
|
//
|
|
195
|
-
// With appSpecificWeight=10, ~20 HighTolerance errors (-40 app score) plus max P3b (-102)
|
|
196
|
-
// would cross gossipThreshold (-500). This keeps non-contributors from being disconnected
|
|
220
|
+
// With appSpecificWeight=10, ~20 HighTolerance errors (-40 app score) plus max P3b (-68 or -102)
|
|
221
|
+
// would not cross gossipThreshold (-500). This keeps non-contributors from being disconnected
|
|
197
222
|
// unless they also accrue app-level penalties.
|
|
198
223
|
//
|
|
199
224
|
// The weight formula ensures max penalty equals MAX_P3_PENALTY_PER_TOPIC:
|
|
@@ -203,12 +228,6 @@ const P2_DECAY_WINDOW_SLOTS = 2;
|
|
|
203
228
|
/** Maximum P3 penalty per topic (must exceed P1 + P2 to cause pruning) */
|
|
204
229
|
export const MAX_P3_PENALTY_PER_TOPIC = -(MAX_P1_SCORE + MAX_P2_SCORE + 1); // -34
|
|
205
230
|
|
|
206
|
-
/** Number of topics with P3 enabled in MBPS mode (block_proposal + checkpoint_proposal + checkpoint_attestation) */
|
|
207
|
-
export const NUM_P3_ENABLED_TOPICS = 3;
|
|
208
|
-
|
|
209
|
-
/** Total maximum P3b penalty across all topics after pruning in MBPS mode */
|
|
210
|
-
export const TOTAL_MAX_P3B_PENALTY = MAX_P3_PENALTY_PER_TOPIC * NUM_P3_ENABLED_TOPICS; // -102
|
|
211
|
-
|
|
212
231
|
/**
|
|
213
232
|
* Factory class for creating gossipsub topic scoring parameters.
|
|
214
233
|
* Computes shared values once and reuses them across all topics.
|
|
@@ -384,6 +403,18 @@ export class TopicScoreParamsFactory {
|
|
|
384
403
|
});
|
|
385
404
|
}
|
|
386
405
|
|
|
406
|
+
/** Number of topics with P3 enabled, computed from config. Always 2 (checkpoint_proposal + checkpoint_attestation) plus optionally block_proposal. */
|
|
407
|
+
get numP3EnabledTopics(): number {
|
|
408
|
+
const blockProposalP3Enabled =
|
|
409
|
+
getEffectiveBlockProposalsPerSlot(this.blocksPerSlot, this.params.expectedBlockProposalsPerSlot) !== undefined;
|
|
410
|
+
return blockProposalP3Enabled ? 3 : 2;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Total maximum P3b penalty across all topics after pruning, computed from config */
|
|
414
|
+
get totalMaxP3bPenalty(): number {
|
|
415
|
+
return MAX_P3_PENALTY_PER_TOPIC * this.numP3EnabledTopics;
|
|
416
|
+
}
|
|
417
|
+
|
|
387
418
|
/**
|
|
388
419
|
* Creates topic score parameters for a specific topic type.
|
|
389
420
|
*
|
|
@@ -391,7 +422,12 @@ export class TopicScoreParamsFactory {
|
|
|
391
422
|
* @returns TopicScoreParams for the topic
|
|
392
423
|
*/
|
|
393
424
|
createForTopic(topicType: TopicType): ReturnType<typeof createTopicScoreParams> {
|
|
394
|
-
const expectedPerSlot = getExpectedMessagesPerSlot(
|
|
425
|
+
const expectedPerSlot = getExpectedMessagesPerSlot(
|
|
426
|
+
topicType,
|
|
427
|
+
this.params.targetCommitteeSize,
|
|
428
|
+
this.blocksPerSlot,
|
|
429
|
+
this.params.expectedBlockProposalsPerSlot,
|
|
430
|
+
);
|
|
395
431
|
|
|
396
432
|
// For unpredictable topics (tx) or topics with 0 expected messages, disable P3/P3b
|
|
397
433
|
if (expectedPerSlot === undefined || expectedPerSlot === 0) {
|