Skip to main content

iota_protocol_config/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    cell::RefCell,
7    cmp::min,
8    sync::atomic::{AtomicBool, Ordering},
9};
10
11use clap::*;
12use iota_protocol_config_macros::{
13    ProtocolConfigAccessors, ProtocolConfigFeatureFlagsGetters, ProtocolConfigOverride,
14};
15use move_vm_config::verifier::VerifierConfig;
16use serde::{Deserialize, Serialize};
17use serde_with::skip_serializing_none;
18use tracing::{info, warn};
19
20/// The minimum and maximum protocol versions supported by this build.
21const MIN_PROTOCOL_VERSION: u64 = 1;
22pub const MAX_PROTOCOL_VERSION: u64 = 29;
23
24/// Protocol version that IIP8 took effect.
25pub const PROTOCOL_VERSION_IIP8: u64 = 20;
26// Record history of protocol version allocations here:
27//
28// Version 1:  Original version.
29// Version 2:  Don't redistribute slashed staking rewards, fix computation of
30//             SystemEpochInfoEventV1.
31// Version 3:  Set the `relocate_event_module` to be true so that the module
32//             that is associated as the "sending module" for an event is
33//             relocated by linkage.
34//             Add `Clock` based unlock to `Timelock` objects.
35// Version 4:  Introduce the `max_type_to_layout_nodes` config that sets the
36//             maximal nodes which are allowed when converting to a type layout.
37// Version 5:  Introduce fixed protocol-defined base fee, IotaSystemStateV2 and
38//             SystemEpochInfoEventV2.
39//             Disallow adding new modules in `deps-only` packages.
40//             Improve gas/wall time efficiency of some Move stdlib vector
41//             functions.
42//             Add new gas model version to update charging of functions.
43//             Enable proper conversion of certain type argument errors in the
44//             execution layer.
45// Version 6:  Bound size of values created in the adapter.
46// Version 7:  Improve handling of stake withdrawal from candidate validators.
47// Version 8:  Variants as type nodes.
48//             Enable smart ancestor selection for testnet.
49//             Enable probing for accepted rounds in round prober for testnet.
50//             Switch to distributed vote scoring in consensus in testnet.
51//             Enable zstd compression for consensus tonic network in testnet.
52//             Enable consensus garbage collection for testnet
53//             Enable the new consensus commit rule for testnet.
54//             Enable min_free_execution_slot for the shared object congestion
55//             tracker in devnet.
56// Version 9:  Disable smart ancestor selection for the testnet.
57//             Enable zstd compression for consensus tonic network in mainnet.
58//             Enable passkey auth in multisig for devnet.
59//             Remove the iota-bridge from the framework.
60// Version 10: Enable min_free_execution_slot for the shared object congestion
61//             tracker in all networks.
62//             Increase the committee size to 80 on all networks.
63//             Enable round prober in consensus for mainnet.
64//             Enable probing for accepted rounds in round prober for mainnet.
65//             Switch to distributed vote scoring in consensus for mainnet.
66//             Enable the new consensus commit rule for mainnet.
67//             Enable consensus garbage collection for mainnet with GC depth set
68//             to 60 rounds.
69//             Enable batching in synchronizer for testnet
70//             Enable the gas price feedback mechanism in devnet.
71//             Enable Identifier input validation.
72//             Removes unnecessary child object mutations
73//             Add additional signature checks
74//             Add additional linkage checks
75// Version 11: Framework fix regarding candidate validator commission rate.
76// Version 12: Enable the gas price feedback mechanism in all networks.
77//             Enable the normalization of PTB arguments.
78// Version 13: Introduce logic to allow the committee to be selected from a set
79//             of eligible active validators.
80//             Enable processing and tracking AuthorityCapabilitiesV1 from
81//             non-committee validators in the devnet.
82// Version 14: Switches the consensus protocol to Starfish in devnet.
83//             Enable median-based commit timestamp calculation in consensus,
84//             and enforce checkpoint timestamp monotonicity for testnet.
85//             Enable batched block sync for mainnet.
86//             Enable selecting committee only from active validators that
87//             support the next epoch's version and issued valid
88//             AuthorityCapabilities notification in testnet.
89// Version 15: Enable shared object transaction bursts of 10 times average load
90//             on devnet.
91// Version 16: Enable selecting committee only from active validators that
92//             support the next epoch's version and issued valid
93//             AuthorityCapabilities notification.
94//             Enable committing transactions only for traversed headers in
95//             Starfish.
96// Version 17: Increase the committee size to 100 on all networks.
97// Version 18: Enable passkey authentication support in testnet.
98// Version 19: Enable congestion limit overshoot in the gas price feedback
99//             mechanism on devnet.
100//             Enable a separate gas price feedback mechanism for transactions
101//             using randomness on devnet.
102//             Allow metadata bytes indexed with a dedicated key in compiled
103//             Move modules in devnet.
104//             Enable publishing package metadata v1 along with the package in
105//             devnet.
106//             Enable Move-based account authentication in devnet.
107//             Increase the base cost for transfer receive object in devnet.
108//             Switch consensus protocol to Starfish in testnet.
109//             Enable passkey authentication support in mainnet.
110//             Change epoch transaction will contain validator scores.
111//             Enable validator scoring on testnet and enable adjustment of
112//             validator rewards based on scores on Devnet.
113// Version 20: Supports the calculation of validator scores while still passing
114//             a default score value to the advance_epoch call. Enables this
115//             decoupling on Testnet; Devnet and Mainnet behavior remain the
116//             same.
117//             Introduce Dynamic Minimum Commission (IIP-8) on all networks.
118// Version 21: Enable overshoot of 100 in congestion control on testnet.
119//             Enable congestion limit overshoot in the gas price feedback
120//             mechanism on testnet.
121//             Enable a separate gas price feedback mechanism for transactions
122//             using randomness on testnet.
123//             Enable fast commit syncer for faster recovery in devnet.
124//             Add auth_context_tx native functions costs.
125//             Reduce max_auth_gas in Devnet.
126// Version 22: Enable overshoot of 100 in congestion control on all networks.
127//             Enable congestion limit overshoot in the gas price feedback
128//             mechanism on all networks.
129//             Enable a separate gas price feedback mechanism for transactions
130//             using randomness on all networks.
131//             Enable Move-based account authentication in testnet.
132//             Enable fast commit syncer for faster recovery on testnet.
133// Version 23: Enable Move native context (TxContext via native functions) in
134//             all networks. TxContext fields are read via native functions
135//             instead of being deserialized from a BCS-encoded struct.
136//             Enables sponsor, rgp, gas_price, and gas_budget to be exposed to
137//             Move.
138// Version 24: Switch consensus protocol to Starfish in all networks.
139//             Enable Move-based sponsor account authentication in devnet.
140//             Add AuthContext native functions cost for reading tx_data_bytes.
141//             Enable additional borrow checks.
142// Version 25: Deprecate zkLogin related parameters since zkLogin is no longer
143//             supported.
144// Version 26: Introduce a module to allow Move code to query protocol feature
145//             flags at runtime.
146// Version 27: Only sponsor Move authentication is performed pre-consensus in
147//             devnet.
148//             Enable consensus block restrictions on testnet and devnet:
149//             bound block-header size to O(committee_size) and enable
150//             garbage collection in the block manager.
151// Version 28: Move authenticator contracts can now inspect which authenticator
152//             function the sender and sponsor used during transaction execution
153//             via new AuthContext accessors.
154//             Enable Move-based account authentication in mainnet.
155//             Enable Move-based sponsor account authentication in testnet.
156// Version 29: Keep advancing the random beacon DKG state machine on every
157//             commit while it is still pending -- regardless of whether new DKG
158//             messages or confirmations arrived that commit -- so DKG resolves
159//             from persisted state (completing, or failing once the timeout
160//             round passes) even with no fresh inbound traffic, e.g. after a
161//             validator restart. Without this it can stay pending forever and
162//             block epoch close.
163//             Enable median-based commit timestamp calculation in consensus,
164//             and enforce checkpoint timestamp monotonicity for mainnet.
165//             Enable fast commit syncer for faster recovery on all networks.
166//             Enable consensus block restrictions on all networks:
167//             bound block-header size to O(committee_size) and enable
168//             garbage collection in the block manager.
169#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
170pub struct ProtocolVersion(u64);
171
172impl ProtocolVersion {
173    // The minimum and maximum protocol version supported by this binary.
174    // Counterintuitively, this constant may change over time as support for old
175    // protocol versions is removed from the source. This ensures that when a
176    // new network (such as a testnet) is created, its genesis committee will
177    // use a protocol version that is actually supported by the binary.
178    pub const MIN: Self = Self(MIN_PROTOCOL_VERSION);
179
180    pub const MAX: Self = Self(MAX_PROTOCOL_VERSION);
181
182    #[cfg(not(msim))]
183    const MAX_ALLOWED: Self = Self::MAX;
184
185    // We create one additional "fake" version in simulator builds so that we can
186    // test upgrades.
187    #[cfg(msim)]
188    pub const MAX_ALLOWED: Self = Self(MAX_PROTOCOL_VERSION + 1);
189
190    pub fn new(v: u64) -> Self {
191        Self(v)
192    }
193
194    pub const fn as_u64(&self) -> u64 {
195        self.0
196    }
197
198    // For serde deserialization - we don't define a Default impl because there
199    // isn't a single universally appropriate default value.
200    pub fn max() -> Self {
201        Self::MAX
202    }
203}
204
205impl From<u64> for ProtocolVersion {
206    fn from(v: u64) -> Self {
207        Self::new(v)
208    }
209}
210
211impl std::ops::Sub<u64> for ProtocolVersion {
212    type Output = Self;
213    fn sub(self, rhs: u64) -> Self::Output {
214        Self::new(self.0 - rhs)
215    }
216}
217
218impl std::ops::Add<u64> for ProtocolVersion {
219    type Output = Self;
220    fn add(self, rhs: u64) -> Self::Output {
221        Self::new(self.0 + rhs)
222    }
223}
224
225#[derive(
226    Clone, Serialize, Deserialize, Debug, PartialEq, Copy, PartialOrd, Ord, Eq, ValueEnum, Default,
227)]
228pub enum Chain {
229    Mainnet,
230    Testnet,
231    #[default]
232    Unknown,
233}
234
235impl Chain {
236    pub fn as_str(self) -> &'static str {
237        match self {
238            Chain::Mainnet => "mainnet",
239            Chain::Testnet => "testnet",
240            Chain::Unknown => "unknown",
241        }
242    }
243}
244
245pub struct Error(pub String);
246
247// TODO: There are quite a few non boolean values in the feature flags. We
248// should move them out.
249/// Records on/off feature flags that may vary at each protocol version.
250#[derive(
251    Default,
252    Clone,
253    Serialize,
254    Deserialize,
255    Debug,
256    ProtocolConfigFeatureFlagsGetters,
257    ProtocolConfigOverride,
258)]
259struct FeatureFlags {
260    // Add feature flags here, e.g.:
261    // new_protocol_feature: bool,
262
263    // Disables unnecessary invariant check in the Move VM when swapping the value out of a local
264    // This flag is used to provide the correct MoveVM configuration for clients.
265    #[serde(skip_serializing_if = "is_true")]
266    disable_invariant_violation_check_in_swap_loc: bool,
267
268    // If true, checks no extra bytes in a compiled module
269    // This flag is used to provide the correct MoveVM configuration for clients.
270    #[serde(skip_serializing_if = "is_true")]
271    no_extraneous_module_bytes: bool,
272
273    // How we order transactions coming out of consensus before sending to execution.
274    #[serde(skip_serializing_if = "ConsensusTransactionOrdering::is_none")]
275    consensus_transaction_ordering: ConsensusTransactionOrdering,
276
277    // If true, use the hardened OTW check
278    // This flag is used to provide the correct MoveVM configuration for clients.
279    #[serde(skip_serializing_if = "is_true")]
280    hardened_otw_check: bool,
281
282    // Enable the poseidon hash function
283    #[serde(skip_serializing_if = "is_false")]
284    enable_poseidon: bool,
285
286    // Enable native function for msm.
287    #[serde(skip_serializing_if = "is_false")]
288    enable_group_ops_native_function_msm: bool,
289
290    // Controls the behavior of per object congestion control in consensus handler.
291    #[serde(skip_serializing_if = "PerObjectCongestionControlMode::is_none")]
292    per_object_congestion_control_mode: PerObjectCongestionControlMode,
293
294    // The consensus protocol to be used for the epoch.
295    #[serde(
296        default = "ConsensusChoice::mysticeti_deprecated",
297        skip_serializing_if = "ConsensusChoice::is_mysticeti_deprecated"
298    )]
299    consensus_choice: ConsensusChoice,
300
301    // Consensus network to use.
302    #[serde(skip_serializing_if = "ConsensusNetwork::is_tonic")]
303    consensus_network: ConsensusNetwork,
304
305    // Set the upper bound allowed for max_epoch in zklogin signature.
306    #[deprecated]
307    #[serde(skip_serializing_if = "Option::is_none")]
308    zklogin_max_epoch_upper_bound_delta: Option<u64>,
309
310    // Enable VDF
311    #[serde(skip_serializing_if = "is_false")]
312    enable_vdf: bool,
313
314    // Enable passkey auth (SIP-9)
315    #[serde(skip_serializing_if = "is_false")]
316    passkey_auth: bool,
317
318    // Rethrow type layout errors during serialization instead of trying to convert them.
319    // This flag is used to provide the correct MoveVM configuration for clients.
320    #[serde(skip_serializing_if = "is_true")]
321    rethrow_serialization_type_layout_errors: bool,
322
323    // Makes the event's sending module version-aware.
324    #[serde(skip_serializing_if = "is_false")]
325    relocate_event_module: bool,
326
327    // Enable a protocol-defined base gas price for all transactions.
328    #[serde(skip_serializing_if = "is_false")]
329    protocol_defined_base_fee: bool,
330
331    // Enable uncompressed group elements in BLS123-81 G1
332    #[serde(skip_serializing_if = "is_false")]
333    uncompressed_g1_group_elements: bool,
334
335    // Disallow adding new modules in `deps-only` packages.
336    #[serde(skip_serializing_if = "is_false")]
337    disallow_new_modules_in_deps_only_packages: bool,
338
339    // Enable v2 native charging for natives.
340    #[serde(skip_serializing_if = "is_false")]
341    native_charging_v2: bool,
342
343    // Properly convert certain type argument errors in the execution layer.
344    #[serde(skip_serializing_if = "is_false")]
345    convert_type_argument_error: bool,
346
347    // Probe rounds received by peers from every authority.
348    #[serde(skip_serializing_if = "is_false")]
349    consensus_round_prober: bool,
350
351    // Use distributed vote leader scoring strategy in consensus.
352    #[serde(skip_serializing_if = "is_false")]
353    consensus_distributed_vote_scoring_strategy: bool,
354
355    // Enables the new logic for collecting the subdag in the consensus linearizer. The new logic
356    // does not stop the recursion at the highest committed round for each authority, but
357    // allows to commit uncommitted blocks up to gc round (excluded) for that authority.
358    #[serde(skip_serializing_if = "is_false")]
359    consensus_linearize_subdag_v2: bool,
360
361    // Variants count as nodes
362    #[serde(skip_serializing_if = "is_false")]
363    variant_nodes: bool,
364
365    // Use smart ancestor selection in consensus.
366    #[serde(skip_serializing_if = "is_false")]
367    consensus_smart_ancestor_selection: bool,
368
369    // Probe accepted rounds in round prober.
370    #[serde(skip_serializing_if = "is_false")]
371    consensus_round_prober_probe_accepted_rounds: bool,
372
373    // If true, enable zstd compression for consensus tonic network.
374    #[serde(skip_serializing_if = "is_false")]
375    consensus_zstd_compression: bool,
376
377    // Use the minimum free execution slot to schedule execution of a transaction in the shared
378    // object congestion tracker.
379    #[serde(skip_serializing_if = "is_false")]
380    congestion_control_min_free_execution_slot: bool,
381
382    // If true, multisig containing passkey sig is accepted.
383    #[serde(skip_serializing_if = "is_false")]
384    accept_passkey_in_multisig: bool,
385
386    // If true, enabled batched block sync in consensus.
387    #[serde(skip_serializing_if = "is_false")]
388    consensus_batched_block_sync: bool,
389
390    // To enable/disable the gas price feedback mechanism used for transactions
391    // cancelled due to shared object congestion
392    #[serde(skip_serializing_if = "is_false")]
393    congestion_control_gas_price_feedback_mechanism: bool,
394
395    // Validate identifier inputs separately
396    #[serde(skip_serializing_if = "is_false")]
397    validate_identifier_inputs: bool,
398
399    // If true, enables the optimizations for child object mutations, removing unnecessary
400    // mutations
401    #[serde(skip_serializing_if = "is_false")]
402    minimize_child_object_mutations: bool,
403
404    // If true enable additional linkage checks.
405    #[serde(skip_serializing_if = "is_false")]
406    dependency_linkage_error: bool,
407
408    // If true enable additional multisig checks.
409    #[serde(skip_serializing_if = "is_false")]
410    additional_multisig_checks: bool,
411
412    // If true, enables the normalization of PTB arguments but does not yet enable splatting
413    // `Result`s of length not equal to 1
414    #[serde(skip_serializing_if = "is_false")]
415    normalize_ptb_arguments: bool,
416
417    // If true, use ChangeEpochV3 for epoch change to pass an additional eligible_active_validators
418    // parameter to IotaSystem's advance_epoch call. This should only be enabled when on-chain
419    // IotaSystem objects are updated as well.
420    #[serde(skip_serializing_if = "is_false")]
421    select_committee_from_eligible_validators: bool,
422
423    // If true, non-committee active validators will sign and send AuthorityCapabilitiesV1 to the
424    // committee. Once the committee reaches consensus over the AuthorityCapabilitiesV1, it is
425    // recorded and possible to use in the committee selection if
426    // select_validators_supporting_next_epoch_version is enabled. This flag does not change the
427    // way that eligible_validators vector is created - still all active validators are used for
428    // selecting the committee.
429    #[serde(skip_serializing_if = "is_false")]
430    track_non_committee_eligible_validators: bool,
431
432    // The committee be selected from active_validators who support the next protocol version AND
433    // have issued a correct AuthorityCapabilities notification. This flag should only be enabled
434    // if both select_committee_from_eligible_validators and
435    // track_non_committee_eligible_validators are enabled. If this is disabled, then all
436    // active validators are used for selecting the committee (default behavior).
437    #[serde(skip_serializing_if = "is_false")]
438    select_committee_supporting_next_epoch_version: bool,
439
440    // If true, then it (1) will not enforce monotonicity checks for a block's ancestors, (2)
441    // calculates the commit's timestamp based on the weighted by stake median timestamp of the
442    // leader's ancestors, and (3) enforces checkpoint timestamps are non-decreasing.
443    #[serde(skip_serializing_if = "is_false")]
444    consensus_median_timestamp_with_checkpoint_enforcement: bool,
445
446    // If true, then transactions are committed only for traversed headers
447    #[serde(skip_serializing_if = "is_false")]
448    consensus_commit_transactions_only_for_traversed_headers: bool,
449
450    // To enable/disable congestion limit overshoot in the gas price feedback mechanism.
451    #[serde(skip_serializing_if = "is_false")]
452    congestion_limit_overshoot_in_gas_price_feedback_mechanism: bool,
453
454    // To enable/disable a separate gas price feedback mechanism for transactions using
455    // randomness.
456    #[serde(skip_serializing_if = "is_false")]
457    separate_gas_price_feedback_mechanism_for_randomness: bool,
458
459    // If true, it allows metadata bytes indexed with a dedicated key in a compiled module.
460    // This flag is used to provide the correct MoveVM configuration for clients.
461    #[serde(skip_serializing_if = "is_false")]
462    metadata_in_module_bytes: bool,
463
464    // If true, enables publishing package metadata v1 along with the package.
465    #[serde(skip_serializing_if = "is_false")]
466    publish_package_metadata: bool,
467
468    // If true, enables the authentication of account using Move code.
469    #[serde(skip_serializing_if = "is_false")]
470    enable_move_authentication: bool,
471
472    // If true, enables the authentication of a sponsor account using Move code.
473    #[serde(skip_serializing_if = "is_false")]
474    enable_move_authentication_for_sponsor: bool,
475
476    // If true, the change epoch transaction will contain validator scores.
477    #[serde(skip_serializing_if = "is_false")]
478    pass_validator_scores_to_advance_epoch: bool,
479
480    // If true, enables calculation of validator scores.
481    #[serde(skip_serializing_if = "is_false")]
482    calculate_validator_scores: bool,
483
484    // If true, validators will use the committee's score to adjust rewards.
485    #[serde(skip_serializing_if = "is_false")]
486    adjust_rewards_by_score: bool,
487
488    // If true, the change epoch transaction will contain the locally calculated validator scores.
489    // If false, a default score (MAX_SCORE) is passed
490    #[serde(skip_serializing_if = "is_false")]
491    pass_calculated_validator_scores_to_advance_epoch: bool,
492
493    // If true, enables the fast commit syncer in Starfish consensus for faster recovery
494    // from large commit gaps. Also controls whether TransactionRef is used in commits
495    // instead of BlockRef, and enables the associated gRPC endpoints for fetching
496    // commits and transactions.
497    #[serde(skip_serializing_if = "is_false")]
498    consensus_fast_commit_sync: bool,
499
500    // If true, enables consensus block restrictions: bounds the block header size for
501    // a given committee size.
502    #[serde(skip_serializing_if = "is_false")]
503    consensus_block_restrictions: bool,
504
505    // If true, enable `TxContext` Move API to go native.
506    #[serde(skip_serializing_if = "is_false")]
507    move_native_tx_context: bool,
508
509    // If true, perform additional borrow checks
510    #[serde(skip_serializing_if = "is_false")]
511    additional_borrow_checks: bool,
512
513    // If true, only sponsor Move authentication is performed pre-consensus.
514    #[serde(skip_serializing_if = "is_false")]
515    pre_consensus_sponsor_only_move_authentication: bool,
516
517    // If true, enables the optimistic commit rule (StarfishSpeed) in Starfish consensus.
518    #[serde(skip_serializing_if = "is_false")]
519    consensus_starfish_speed: bool,
520
521    // If true, keep advancing the random beacon DKG state machine on every
522    // consensus commit while DKG is still pending, even when no new messages or
523    // confirmations were processed that commit. This lets a validator resolve
524    // DKG from already-persisted state (completing, or failing once the timeout
525    // round passes) with no fresh inbound traffic -- e.g. after a restart --
526    // instead of staying pending forever.
527    #[serde(skip_serializing_if = "is_false")]
528    always_advance_dkg_to_resolution: bool,
529
530    // If true, enables the P-COOL (post-consensus owned-object locking) flow:
531    // transactions bypass pre-consensus certification and owned-object locking,
532    // and conflicts are resolved deterministically post-consensus (white-flag
533    // conflict resolution) using persistent locks.
534    #[serde(skip_serializing_if = "is_false")]
535    enable_pcool_flow: bool,
536}
537
538fn is_true(b: &bool) -> bool {
539    *b
540}
541
542fn is_false(b: &bool) -> bool {
543    !b
544}
545
546/// Ordering mechanism for transactions in one consensus output.
547#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
548pub enum ConsensusTransactionOrdering {
549    /// No ordering. Transactions are processed in the order they appear in the
550    /// consensus output.
551    #[default]
552    None,
553    /// Order transactions by gas price, highest first.
554    ByGasPrice,
555}
556
557impl ConsensusTransactionOrdering {
558    pub fn is_none(&self) -> bool {
559        matches!(self, ConsensusTransactionOrdering::None)
560    }
561}
562
563// The config for per object congestion control in consensus handler.
564#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
565pub enum PerObjectCongestionControlMode {
566    #[default]
567    None, // No congestion control.
568    TotalGasBudget, // Use txn gas budget as execution cost.
569    TotalTxCount,   // Use total txn count as execution cost.
570}
571
572impl PerObjectCongestionControlMode {
573    pub fn is_none(&self) -> bool {
574        matches!(self, PerObjectCongestionControlMode::None)
575    }
576}
577
578// Configuration options for consensus algorithm.
579#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
580pub enum ConsensusChoice {
581    /// Kept only so protocol-config serialization of historical epochs stays
582    /// bit-for-bit identical; no runtime code branches on it.
583    #[deprecated(note = "Mysticeti was replaced by Starfish")]
584    MysticetiDeprecated,
585    #[default]
586    Starfish,
587}
588
589#[expect(deprecated)]
590impl ConsensusChoice {
591    /// serde deserialization default: an absent `consensus_choice` field in a
592    /// historical snapshot deserializes to `MysticetiDeprecated` so that
593    /// re-serialization stays byte-identical (the skip condition below also
594    /// triggers on that variant). Decoupled from the Rust `Default` impl,
595    /// which returns `Starfish` to reflect that Starfish is the current
596    /// consensus protocol.
597    fn mysticeti_deprecated() -> Self {
598        ConsensusChoice::MysticetiDeprecated
599    }
600
601    pub fn is_mysticeti_deprecated(&self) -> bool {
602        matches!(self, ConsensusChoice::MysticetiDeprecated)
603    }
604    pub fn is_starfish(&self) -> bool {
605        matches!(self, ConsensusChoice::Starfish)
606    }
607}
608
609// Configuration options for consensus network.
610#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
611pub enum ConsensusNetwork {
612    #[default]
613    Tonic,
614}
615
616impl ConsensusNetwork {
617    pub fn is_tonic(&self) -> bool {
618        matches!(self, ConsensusNetwork::Tonic)
619    }
620}
621
622/// Constants that change the behavior of the protocol.
623///
624/// The value of each constant here must be fixed for a given protocol version.
625/// To change the value of a constant, advance the protocol version, and add
626/// support for it in `get_for_version` under the new version number.
627/// (below).
628///
629/// To add a new field to this struct, use the following procedure:
630/// - Advance the protocol version.
631/// - Add the field as a private `Option<T>` to the struct.
632/// - Initialize the field to `None` in prior protocol versions.
633/// - Initialize the field to `Some(val)` for your new protocol version.
634/// - Add a public getter that simply unwraps the field.
635/// - Two public getters of the form `field(&self) -> field_type` and
636///   `field_as_option(&self) -> Option<field_type>` will be automatically
637///   generated for you.
638/// Example for a field: `new_constant: Option<u64>`
639/// ```rust,ignore
640///      pub fn new_constant(&self) -> u64 {
641///         self.new_constant.expect(Self::CONSTANT_ERR_MSG)
642///     }
643///      pub fn new_constant_as_option(&self) -> Option<u64> {
644///         self.new_constant.expect(Self::CONSTANT_ERR_MSG)
645///     }
646/// ```
647/// With `pub fn new_constant(&self) -> u64`, if the constant is accessed in a
648/// protocol version in which it is not defined, the validator will crash.
649/// (Crashing is necessary because this type of error would almost always result
650/// in forking if not prevented here). If you don't want the validator to crash,
651/// you can use the `pub fn new_constant_as_option(&self) -> Option<u64>`
652/// getter, which will return `None` if the field is not defined at that
653/// version.
654/// - If you want a customized getter, you can add a method in the impl.
655#[skip_serializing_none]
656#[derive(Clone, Serialize, Debug, ProtocolConfigAccessors, ProtocolConfigOverride)]
657pub struct ProtocolConfig {
658    pub version: ProtocolVersion,
659
660    feature_flags: FeatureFlags,
661
662    // ==== Transaction input limits ====
663
664    //
665    /// Maximum serialized size of a transaction (in bytes).
666    max_tx_size_bytes: Option<u64>,
667
668    /// Maximum number of input objects to a transaction. Enforced by the
669    /// transaction input checker
670    max_input_objects: Option<u64>,
671
672    /// Max size of objects a transaction can write to disk after completion.
673    /// Enforce by the IOTA adapter. This is the sum of the serialized size
674    /// of all objects written to disk. The max size of individual objects
675    /// on the other hand is `max_move_object_size`.
676    max_size_written_objects: Option<u64>,
677    /// Max size of objects a system transaction can write to disk after
678    /// completion. Enforce by the IOTA adapter. Similar to
679    /// `max_size_written_objects` but for system transactions.
680    max_size_written_objects_system_tx: Option<u64>,
681
682    /// Maximum size of serialized transaction effects.
683    max_serialized_tx_effects_size_bytes: Option<u64>,
684
685    /// Maximum size of serialized transaction effects for system transactions.
686    max_serialized_tx_effects_size_bytes_system_tx: Option<u64>,
687
688    /// Maximum number of gas payment objects for a transaction.
689    max_gas_payment_objects: Option<u32>,
690
691    /// Maximum number of modules in a Publish transaction.
692    max_modules_in_publish: Option<u32>,
693
694    /// Maximum number of transitive dependencies in a package when publishing.
695    max_package_dependencies: Option<u32>,
696
697    /// Maximum number of arguments in a move call or a
698    /// ProgrammableTransaction's TransferObjects command.
699    max_arguments: Option<u32>,
700
701    /// Maximum number of total type arguments, computed recursively.
702    max_type_arguments: Option<u32>,
703
704    /// Maximum depth of an individual type argument.
705    max_type_argument_depth: Option<u32>,
706
707    /// Maximum size of a Pure CallArg.
708    max_pure_argument_size: Option<u32>,
709
710    /// Maximum number of Commands in a ProgrammableTransaction.
711    max_programmable_tx_commands: Option<u32>,
712
713    // ==== Move VM, Move bytecode verifier, and execution limits ===
714
715    //
716    /// Maximum Move bytecode version the VM understands. All older versions are
717    /// accepted.
718    move_binary_format_version: Option<u32>,
719    min_move_binary_format_version: Option<u32>,
720
721    /// Configuration controlling binary tables size.
722    binary_module_handles: Option<u16>,
723    binary_struct_handles: Option<u16>,
724    binary_function_handles: Option<u16>,
725    binary_function_instantiations: Option<u16>,
726    binary_signatures: Option<u16>,
727    binary_constant_pool: Option<u16>,
728    binary_identifiers: Option<u16>,
729    binary_address_identifiers: Option<u16>,
730    binary_struct_defs: Option<u16>,
731    binary_struct_def_instantiations: Option<u16>,
732    binary_function_defs: Option<u16>,
733    binary_field_handles: Option<u16>,
734    binary_field_instantiations: Option<u16>,
735    binary_friend_decls: Option<u16>,
736    binary_enum_defs: Option<u16>,
737    binary_enum_def_instantiations: Option<u16>,
738    binary_variant_handles: Option<u16>,
739    binary_variant_instantiation_handles: Option<u16>,
740
741    /// Maximum size of the `contents` part of an object, in bytes. Enforced by
742    /// the IOTA adapter when effects are produced.
743    max_move_object_size: Option<u64>,
744
745    // TODO: Option<increase to 500 KB. currently, publishing a package > 500 KB exceeds the max
746    // computation gas cost
747    /// Maximum size of a Move package object, in bytes. Enforced by the IOTA
748    /// adapter at the end of a publish transaction.
749    max_move_package_size: Option<u64>,
750
751    /// Max number of publish or upgrade commands allowed in a programmable
752    /// transaction block.
753    max_publish_or_upgrade_per_ptb: Option<u64>,
754
755    /// Maximum gas budget in NANOS that a transaction can use.
756    max_tx_gas: Option<u64>,
757
758    /// Maximum gas budget in NANOS that a authentication transaction can use.
759    max_auth_gas: Option<u64>,
760
761    /// Maximum amount of the proposed gas price in NANOS (defined in the
762    /// transaction).
763    max_gas_price: Option<u64>,
764
765    /// The max computation bucket for gas. This is the max that can be charged
766    /// for computation.
767    max_gas_computation_bucket: Option<u64>,
768
769    // Define the value used to round up computation gas charges
770    gas_rounding_step: Option<u64>,
771
772    /// Maximum number of nested loops. Enforced by the Move bytecode verifier.
773    max_loop_depth: Option<u64>,
774
775    /// Maximum number of type arguments that can be bound to generic type
776    /// parameters. Enforced by the Move bytecode verifier.
777    max_generic_instantiation_length: Option<u64>,
778
779    /// Maximum number of parameters that a Move function can have. Enforced by
780    /// the Move bytecode verifier.
781    max_function_parameters: Option<u64>,
782
783    /// Maximum number of basic blocks that a Move function can have. Enforced
784    /// by the Move bytecode verifier.
785    max_basic_blocks: Option<u64>,
786
787    /// Maximum stack size value. Enforced by the Move bytecode verifier.
788    max_value_stack_size: Option<u64>,
789
790    /// Maximum number of "type nodes", a metric for how big a SignatureToken
791    /// will be when expanded into a fully qualified type. Enforced by the Move
792    /// bytecode verifier.
793    max_type_nodes: Option<u64>,
794
795    /// Maximum number of push instructions in one function. Enforced by the
796    /// Move bytecode verifier.
797    max_push_size: Option<u64>,
798
799    /// Maximum number of struct definitions in a module. Enforced by the Move
800    /// bytecode verifier.
801    max_struct_definitions: Option<u64>,
802
803    /// Maximum number of function definitions in a module. Enforced by the Move
804    /// bytecode verifier.
805    max_function_definitions: Option<u64>,
806
807    /// Maximum number of fields allowed in a struct definition. Enforced by the
808    /// Move bytecode verifier.
809    max_fields_in_struct: Option<u64>,
810
811    /// Maximum dependency depth. Enforced by the Move linker when loading
812    /// dependent modules.
813    max_dependency_depth: Option<u64>,
814
815    /// Maximum number of Move events that a single transaction can emit.
816    /// Enforced by the VM during execution.
817    max_num_event_emit: Option<u64>,
818
819    /// Maximum number of new IDs that a single transaction can create. Enforced
820    /// by the VM during execution.
821    max_num_new_move_object_ids: Option<u64>,
822
823    /// Maximum number of new IDs that a single system transaction can create.
824    /// Enforced by the VM during execution.
825    max_num_new_move_object_ids_system_tx: Option<u64>,
826
827    /// Maximum number of IDs that a single transaction can delete. Enforced by
828    /// the VM during execution.
829    max_num_deleted_move_object_ids: Option<u64>,
830
831    /// Maximum number of IDs that a single system transaction can delete.
832    /// Enforced by the VM during execution.
833    max_num_deleted_move_object_ids_system_tx: Option<u64>,
834
835    /// Maximum number of IDs that a single transaction can transfer. Enforced
836    /// by the VM during execution.
837    max_num_transferred_move_object_ids: Option<u64>,
838
839    /// Maximum number of IDs that a single system transaction can transfer.
840    /// Enforced by the VM during execution.
841    max_num_transferred_move_object_ids_system_tx: Option<u64>,
842
843    /// Maximum size of a Move user event. Enforced by the VM during execution.
844    max_event_emit_size: Option<u64>,
845
846    /// Maximum size of a Move user event. Enforced by the VM during execution.
847    max_event_emit_size_total: Option<u64>,
848
849    /// Maximum length of a vector in Move. Enforced by the VM during execution,
850    /// and for constants, by the verifier.
851    max_move_vector_len: Option<u64>,
852
853    /// Maximum length of an `Identifier` in Move. Enforced by the bytecode
854    /// verifier at signing.
855    max_move_identifier_len: Option<u64>,
856
857    /// Maximum depth of a Move value within the VM.
858    max_move_value_depth: Option<u64>,
859
860    /// Maximum number of variants in an enum. Enforced by the bytecode verifier
861    /// at signing.
862    max_move_enum_variants: Option<u64>,
863
864    /// Maximum number of back edges in Move function. Enforced by the bytecode
865    /// verifier at signing.
866    max_back_edges_per_function: Option<u64>,
867
868    /// Maximum number of back edges in Move module. Enforced by the bytecode
869    /// verifier at signing.
870    max_back_edges_per_module: Option<u64>,
871
872    /// Maximum number of meter `ticks` spent verifying a Move function.
873    /// Enforced by the bytecode verifier at signing.
874    max_verifier_meter_ticks_per_function: Option<u64>,
875
876    /// Maximum number of meter `ticks` spent verifying a Move function.
877    /// Enforced by the bytecode verifier at signing.
878    max_meter_ticks_per_module: Option<u64>,
879
880    /// Maximum number of meter `ticks` spent verifying a Move package. Enforced
881    /// by the bytecode verifier at signing.
882    max_meter_ticks_per_package: Option<u64>,
883
884    // === Object runtime internal operation limits ====
885    // These affect dynamic fields
886
887    //
888    /// Maximum number of cached objects in the object runtime ObjectStore.
889    /// Enforced by object runtime during execution
890    object_runtime_max_num_cached_objects: Option<u64>,
891
892    /// Maximum number of cached objects in the object runtime ObjectStore in
893    /// system transaction. Enforced by object runtime during execution
894    object_runtime_max_num_cached_objects_system_tx: Option<u64>,
895
896    /// Maximum number of stored objects accessed by object runtime ObjectStore.
897    /// Enforced by object runtime during execution
898    object_runtime_max_num_store_entries: Option<u64>,
899
900    /// Maximum number of stored objects accessed by object runtime ObjectStore
901    /// in system transaction. Enforced by object runtime during execution
902    object_runtime_max_num_store_entries_system_tx: Option<u64>,
903
904    // === Execution gas costs ====
905
906    //
907    /// Base cost for any IOTA transaction
908    base_tx_cost_fixed: Option<u64>,
909
910    /// Additional cost for a transaction that publishes a package
911    /// i.e., the base cost of such a transaction is base_tx_cost_fixed +
912    /// package_publish_cost_fixed
913    package_publish_cost_fixed: Option<u64>,
914
915    /// Cost per byte of a Move call transaction
916    /// i.e., the cost of such a transaction is base_cost +
917    /// (base_tx_cost_per_byte * size)
918    base_tx_cost_per_byte: Option<u64>,
919
920    /// Cost per byte for a transaction that publishes a package
921    package_publish_cost_per_byte: Option<u64>,
922
923    // Per-byte cost of reading an object during transaction execution
924    obj_access_cost_read_per_byte: Option<u64>,
925
926    // Per-byte cost of writing an object during transaction execution
927    obj_access_cost_mutate_per_byte: Option<u64>,
928
929    // Per-byte cost of deleting an object during transaction execution
930    obj_access_cost_delete_per_byte: Option<u64>,
931
932    /// Per-byte cost charged for each input object to a transaction.
933    /// Meant to approximate the cost of checking locks for each object
934    // TODO: Option<I'm not sure that this cost makes sense. Checking locks is "free"
935    // in the sense that an invalid tx that can never be committed/pay gas can
936    // force validators to check an arbitrary number of locks. If those checks are
937    // "free" for invalid transactions, why charge for them in valid transactions
938    // TODO: Option<if we keep this, I think we probably want it to be a fixed cost rather
939    // than a per-byte cost. checking an object lock should not require loading an
940    // entire object, just consulting an ID -> tx digest map
941    obj_access_cost_verify_per_byte: Option<u64>,
942
943    // Maximal nodes which are allowed when converting to a type layout.
944    max_type_to_layout_nodes: Option<u64>,
945
946    // Maximal size in bytes that a PTB value can be
947    max_ptb_value_size: Option<u64>,
948
949    // === Gas version. gas model ===
950
951    //
952    /// Gas model version, what code we are using to charge gas
953    gas_model_version: Option<u64>,
954
955    // === Storage gas costs ===
956
957    //
958    /// Per-byte cost of storing an object in the IOTA global object store. Some
959    /// of this cost may be refundable if the object is later freed
960    obj_data_cost_refundable: Option<u64>,
961
962    // Per-byte cost of storing an object in the IOTA transaction log (e.g., in
963    // CertifiedTransactionEffects) This depends on the size of various fields including the
964    // effects TODO: Option<I don't fully understand this^ and more details would be useful
965    obj_metadata_cost_non_refundable: Option<u64>,
966
967    // === Tokenomics ===
968
969    // TODO: Option<this should be changed to u64.
970    /// Sender of a txn that touches an object will get this percent of the
971    /// storage rebate back. In basis point.
972    storage_rebate_rate: Option<u64>,
973
974    /// The share of rewards that will be slashed and redistributed is 50%.
975    /// In basis point.
976    reward_slashing_rate: Option<u64>,
977
978    /// Unit storage gas price, Nanos per internal gas unit.
979    storage_gas_price: Option<u64>,
980
981    // Base gas price for computation gas, nanos per computation unit.
982    base_gas_price: Option<u64>,
983
984    /// The number of tokens minted as a validator subsidy per epoch.
985    validator_target_reward: Option<u64>,
986
987    // === Core Protocol ===
988
989    //
990    /// Max number of transactions per checkpoint.
991    /// Note that this is a protocol constant and not a config as validators
992    /// must have this set to the same value, otherwise they *will* fork.
993    max_transactions_per_checkpoint: Option<u64>,
994
995    /// Max size of a checkpoint in bytes.
996    /// Note that this is a protocol constant and not a config as validators
997    /// must have this set to the same value, otherwise they *will* fork.
998    max_checkpoint_size_bytes: Option<u64>,
999
1000    /// A protocol upgrade always requires 2f+1 stake to agree. We support a
1001    /// buffer of additional stake (as a fraction of f, expressed in basis
1002    /// points) that is required before an upgrade can happen automatically.
1003    /// 10000bps would indicate that complete unanimity is required (all
1004    /// 3f+1 must vote), while 0bps would indicate that 2f+1 is sufficient.
1005    buffer_stake_for_protocol_upgrade_bps: Option<u64>,
1006
1007    // === Native Function Costs ===
1008
1009    // `address` module
1010    // Cost params for the Move native function `address::from_bytes(bytes: vector<u8>)`
1011    address_from_bytes_cost_base: Option<u64>,
1012    // Cost params for the Move native function `address::to_u256(address): u256`
1013    address_to_u256_cost_base: Option<u64>,
1014    // Cost params for the Move native function `address::from_u256(u256): address`
1015    address_from_u256_cost_base: Option<u64>,
1016
1017    // `config` module
1018    // Cost params for the Move native function `read_setting_impl<Name: copy + drop + store,
1019    // SettingValue: key + store, SettingDataValue: store, Value: copy + drop + store,
1020    // >(config: address, name: address, current_epoch: u64): Option<Value>`
1021    config_read_setting_impl_cost_base: Option<u64>,
1022    config_read_setting_impl_cost_per_byte: Option<u64>,
1023
1024    // `dynamic_field` module
1025    // Cost params for the Move native function `hash_type_and_key<K: copy + drop + store>(parent:
1026    // address, k: K): address`
1027    dynamic_field_hash_type_and_key_cost_base: Option<u64>,
1028    dynamic_field_hash_type_and_key_type_cost_per_byte: Option<u64>,
1029    dynamic_field_hash_type_and_key_value_cost_per_byte: Option<u64>,
1030    dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Option<u64>,
1031    // Cost params for the Move native function `add_child_object<Child: key>(parent: address,
1032    // child: Child)`
1033    dynamic_field_add_child_object_cost_base: Option<u64>,
1034    dynamic_field_add_child_object_type_cost_per_byte: Option<u64>,
1035    dynamic_field_add_child_object_value_cost_per_byte: Option<u64>,
1036    dynamic_field_add_child_object_struct_tag_cost_per_byte: Option<u64>,
1037    // Cost params for the Move native function `borrow_child_object_mut<Child: key>(parent: &mut
1038    // UID, id: address): &mut Child`
1039    dynamic_field_borrow_child_object_cost_base: Option<u64>,
1040    dynamic_field_borrow_child_object_child_ref_cost_per_byte: Option<u64>,
1041    dynamic_field_borrow_child_object_type_cost_per_byte: Option<u64>,
1042    // Cost params for the Move native function `remove_child_object<Child: key>(parent: address,
1043    // id: address): Child`
1044    dynamic_field_remove_child_object_cost_base: Option<u64>,
1045    dynamic_field_remove_child_object_child_cost_per_byte: Option<u64>,
1046    dynamic_field_remove_child_object_type_cost_per_byte: Option<u64>,
1047    // Cost params for the Move native function `has_child_object(parent: address, id: address):
1048    // bool`
1049    dynamic_field_has_child_object_cost_base: Option<u64>,
1050    // Cost params for the Move native function `has_child_object_with_ty<Child: key>(parent:
1051    // address, id: address): bool`
1052    dynamic_field_has_child_object_with_ty_cost_base: Option<u64>,
1053    dynamic_field_has_child_object_with_ty_type_cost_per_byte: Option<u64>,
1054    dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Option<u64>,
1055
1056    // `event` module
1057    // Cost params for the Move native function `event::emit<T: copy + drop>(event: T)`
1058    event_emit_cost_base: Option<u64>,
1059    event_emit_value_size_derivation_cost_per_byte: Option<u64>,
1060    event_emit_tag_size_derivation_cost_per_byte: Option<u64>,
1061    event_emit_output_cost_per_byte: Option<u64>,
1062
1063    //  `object` module
1064    // Cost params for the Move native function `borrow_uid<T: key>(obj: &T): &UID`
1065    object_borrow_uid_cost_base: Option<u64>,
1066    // Cost params for the Move native function `delete_impl(id: address)`
1067    object_delete_impl_cost_base: Option<u64>,
1068    // Cost params for the Move native function `record_new_uid(id: address)`
1069    object_record_new_uid_cost_base: Option<u64>,
1070
1071    // Transfer
1072    // Cost params for the Move native function `transfer_impl<T: key>(obj: T, recipient: address)`
1073    transfer_transfer_internal_cost_base: Option<u64>,
1074    // Cost params for the Move native function `freeze_object<T: key>(obj: T)`
1075    transfer_freeze_object_cost_base: Option<u64>,
1076    // Cost params for the Move native function `share_object<T: key>(obj: T)`
1077    transfer_share_object_cost_base: Option<u64>,
1078    // Cost params for the Move native function
1079    // `receive_object<T: key>(p: &mut UID, recv: Receiving<T>T)`
1080    transfer_receive_object_cost_base: Option<u64>,
1081
1082    // TxContext
1083    // Cost params for the Move native function `transfer_impl<T: key>(obj: T, recipient: address)`
1084    tx_context_derive_id_cost_base: Option<u64>,
1085    tx_context_fresh_id_cost_base: Option<u64>,
1086    tx_context_sender_cost_base: Option<u64>,
1087    tx_context_digest_cost_base: Option<u64>,
1088    tx_context_epoch_cost_base: Option<u64>,
1089    tx_context_epoch_timestamp_ms_cost_base: Option<u64>,
1090    tx_context_sponsor_cost_base: Option<u64>,
1091    tx_context_rgp_cost_base: Option<u64>,
1092    tx_context_gas_price_cost_base: Option<u64>,
1093    tx_context_gas_budget_cost_base: Option<u64>,
1094    tx_context_ids_created_cost_base: Option<u64>,
1095    tx_context_replace_cost_base: Option<u64>,
1096
1097    // Types
1098    // Cost params for the Move native function `is_one_time_witness<T: drop>(_: &T): bool`
1099    types_is_one_time_witness_cost_base: Option<u64>,
1100    types_is_one_time_witness_type_tag_cost_per_byte: Option<u64>,
1101    types_is_one_time_witness_type_cost_per_byte: Option<u64>,
1102
1103    // Validator
1104    // Cost params for the Move native function `validate_metadata_bcs(metadata: vector<u8>)`
1105    validator_validate_metadata_cost_base: Option<u64>,
1106    validator_validate_metadata_data_cost_per_byte: Option<u64>,
1107
1108    // Crypto natives
1109    crypto_invalid_arguments_cost: Option<u64>,
1110    // bls12381::bls12381_min_sig_verify
1111    bls12381_bls12381_min_sig_verify_cost_base: Option<u64>,
1112    bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Option<u64>,
1113    bls12381_bls12381_min_sig_verify_msg_cost_per_block: Option<u64>,
1114
1115    // bls12381::bls12381_min_pk_verify
1116    bls12381_bls12381_min_pk_verify_cost_base: Option<u64>,
1117    bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Option<u64>,
1118    bls12381_bls12381_min_pk_verify_msg_cost_per_block: Option<u64>,
1119
1120    // ecdsa_k1::ecrecover
1121    ecdsa_k1_ecrecover_keccak256_cost_base: Option<u64>,
1122    ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Option<u64>,
1123    ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Option<u64>,
1124    ecdsa_k1_ecrecover_sha256_cost_base: Option<u64>,
1125    ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Option<u64>,
1126    ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Option<u64>,
1127
1128    // ecdsa_k1::decompress_pubkey
1129    ecdsa_k1_decompress_pubkey_cost_base: Option<u64>,
1130
1131    // ecdsa_k1::secp256k1_verify
1132    ecdsa_k1_secp256k1_verify_keccak256_cost_base: Option<u64>,
1133    ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Option<u64>,
1134    ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Option<u64>,
1135    ecdsa_k1_secp256k1_verify_sha256_cost_base: Option<u64>,
1136    ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Option<u64>,
1137    ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Option<u64>,
1138
1139    // ecdsa_r1::ecrecover
1140    ecdsa_r1_ecrecover_keccak256_cost_base: Option<u64>,
1141    ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Option<u64>,
1142    ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Option<u64>,
1143    ecdsa_r1_ecrecover_sha256_cost_base: Option<u64>,
1144    ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Option<u64>,
1145    ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Option<u64>,
1146
1147    // ecdsa_r1::secp256k1_verify
1148    ecdsa_r1_secp256r1_verify_keccak256_cost_base: Option<u64>,
1149    ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Option<u64>,
1150    ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Option<u64>,
1151    ecdsa_r1_secp256r1_verify_sha256_cost_base: Option<u64>,
1152    ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Option<u64>,
1153    ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Option<u64>,
1154
1155    // ecvrf::verify
1156    ecvrf_ecvrf_verify_cost_base: Option<u64>,
1157    ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Option<u64>,
1158    ecvrf_ecvrf_verify_alpha_string_cost_per_block: Option<u64>,
1159
1160    // ed25519
1161    ed25519_ed25519_verify_cost_base: Option<u64>,
1162    ed25519_ed25519_verify_msg_cost_per_byte: Option<u64>,
1163    ed25519_ed25519_verify_msg_cost_per_block: Option<u64>,
1164
1165    // groth16::prepare_verifying_key
1166    groth16_prepare_verifying_key_bls12381_cost_base: Option<u64>,
1167    groth16_prepare_verifying_key_bn254_cost_base: Option<u64>,
1168
1169    // groth16::verify_groth16_proof_internal
1170    groth16_verify_groth16_proof_internal_bls12381_cost_base: Option<u64>,
1171    groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Option<u64>,
1172    groth16_verify_groth16_proof_internal_bn254_cost_base: Option<u64>,
1173    groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Option<u64>,
1174    groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Option<u64>,
1175
1176    // hash::blake2b256
1177    hash_blake2b256_cost_base: Option<u64>,
1178    hash_blake2b256_data_cost_per_byte: Option<u64>,
1179    hash_blake2b256_data_cost_per_block: Option<u64>,
1180
1181    // hash::keccak256
1182    hash_keccak256_cost_base: Option<u64>,
1183    hash_keccak256_data_cost_per_byte: Option<u64>,
1184    hash_keccak256_data_cost_per_block: Option<u64>,
1185
1186    // poseidon::poseidon_bn254
1187    poseidon_bn254_cost_base: Option<u64>,
1188    poseidon_bn254_cost_per_block: Option<u64>,
1189
1190    // group_ops
1191    group_ops_bls12381_decode_scalar_cost: Option<u64>,
1192    group_ops_bls12381_decode_g1_cost: Option<u64>,
1193    group_ops_bls12381_decode_g2_cost: Option<u64>,
1194    group_ops_bls12381_decode_gt_cost: Option<u64>,
1195    group_ops_bls12381_scalar_add_cost: Option<u64>,
1196    group_ops_bls12381_g1_add_cost: Option<u64>,
1197    group_ops_bls12381_g2_add_cost: Option<u64>,
1198    group_ops_bls12381_gt_add_cost: Option<u64>,
1199    group_ops_bls12381_scalar_sub_cost: Option<u64>,
1200    group_ops_bls12381_g1_sub_cost: Option<u64>,
1201    group_ops_bls12381_g2_sub_cost: Option<u64>,
1202    group_ops_bls12381_gt_sub_cost: Option<u64>,
1203    group_ops_bls12381_scalar_mul_cost: Option<u64>,
1204    group_ops_bls12381_g1_mul_cost: Option<u64>,
1205    group_ops_bls12381_g2_mul_cost: Option<u64>,
1206    group_ops_bls12381_gt_mul_cost: Option<u64>,
1207    group_ops_bls12381_scalar_div_cost: Option<u64>,
1208    group_ops_bls12381_g1_div_cost: Option<u64>,
1209    group_ops_bls12381_g2_div_cost: Option<u64>,
1210    group_ops_bls12381_gt_div_cost: Option<u64>,
1211    group_ops_bls12381_g1_hash_to_base_cost: Option<u64>,
1212    group_ops_bls12381_g2_hash_to_base_cost: Option<u64>,
1213    group_ops_bls12381_g1_hash_to_cost_per_byte: Option<u64>,
1214    group_ops_bls12381_g2_hash_to_cost_per_byte: Option<u64>,
1215    group_ops_bls12381_g1_msm_base_cost: Option<u64>,
1216    group_ops_bls12381_g2_msm_base_cost: Option<u64>,
1217    group_ops_bls12381_g1_msm_base_cost_per_input: Option<u64>,
1218    group_ops_bls12381_g2_msm_base_cost_per_input: Option<u64>,
1219    group_ops_bls12381_msm_max_len: Option<u32>,
1220    group_ops_bls12381_pairing_cost: Option<u64>,
1221    group_ops_bls12381_g1_to_uncompressed_g1_cost: Option<u64>,
1222    group_ops_bls12381_uncompressed_g1_to_g1_cost: Option<u64>,
1223    group_ops_bls12381_uncompressed_g1_sum_base_cost: Option<u64>,
1224    group_ops_bls12381_uncompressed_g1_sum_cost_per_term: Option<u64>,
1225    group_ops_bls12381_uncompressed_g1_sum_max_terms: Option<u64>,
1226
1227    // hmac::hmac_sha3_256
1228    hmac_hmac_sha3_256_cost_base: Option<u64>,
1229    hmac_hmac_sha3_256_input_cost_per_byte: Option<u64>,
1230    hmac_hmac_sha3_256_input_cost_per_block: Option<u64>,
1231
1232    // zklogin::check_zklogin_id
1233    #[deprecated]
1234    check_zklogin_id_cost_base: Option<u64>,
1235    // zklogin::check_zklogin_issuer
1236    #[deprecated]
1237    check_zklogin_issuer_cost_base: Option<u64>,
1238
1239    vdf_verify_vdf_cost: Option<u64>,
1240    vdf_hash_to_input_cost: Option<u64>,
1241
1242    // Stdlib costs
1243    bcs_per_byte_serialized_cost: Option<u64>,
1244    bcs_legacy_min_output_size_cost: Option<u64>,
1245    bcs_failure_cost: Option<u64>,
1246
1247    hash_sha2_256_base_cost: Option<u64>,
1248    hash_sha2_256_per_byte_cost: Option<u64>,
1249    hash_sha2_256_legacy_min_input_len_cost: Option<u64>,
1250    hash_sha3_256_base_cost: Option<u64>,
1251    hash_sha3_256_per_byte_cost: Option<u64>,
1252    hash_sha3_256_legacy_min_input_len_cost: Option<u64>,
1253    type_name_get_base_cost: Option<u64>,
1254    type_name_get_per_byte_cost: Option<u64>,
1255
1256    string_check_utf8_base_cost: Option<u64>,
1257    string_check_utf8_per_byte_cost: Option<u64>,
1258    string_is_char_boundary_base_cost: Option<u64>,
1259    string_sub_string_base_cost: Option<u64>,
1260    string_sub_string_per_byte_cost: Option<u64>,
1261    string_index_of_base_cost: Option<u64>,
1262    string_index_of_per_byte_pattern_cost: Option<u64>,
1263    string_index_of_per_byte_searched_cost: Option<u64>,
1264
1265    vector_empty_base_cost: Option<u64>,
1266    vector_length_base_cost: Option<u64>,
1267    vector_push_back_base_cost: Option<u64>,
1268    vector_push_back_legacy_per_abstract_memory_unit_cost: Option<u64>,
1269    vector_borrow_base_cost: Option<u64>,
1270    vector_pop_back_base_cost: Option<u64>,
1271    vector_destroy_empty_base_cost: Option<u64>,
1272    vector_swap_base_cost: Option<u64>,
1273    debug_print_base_cost: Option<u64>,
1274    debug_print_stack_trace_base_cost: Option<u64>,
1275
1276    // === Execution Version ===
1277    execution_version: Option<u64>,
1278
1279    // Dictates the threshold (percentage of stake) that is used to calculate the "bad" nodes to be
1280    // swapped when creating the consensus schedule. The values should be of the range [0 - 33].
1281    // Anything above 33 (f) will not be allowed.
1282    consensus_bad_nodes_stake_threshold: Option<u64>,
1283
1284    #[deprecated]
1285    max_jwk_votes_per_validator_per_epoch: Option<u64>,
1286    // The maximum age of a JWK in epochs before it is removed from the AuthenticatorState object.
1287    // Applied at the end of an epoch as a delta from the new epoch value, so setting this to 1
1288    // will cause the new epoch to start with JWKs from the previous epoch still valid.
1289    #[deprecated]
1290    max_age_of_jwk_in_epochs: Option<u64>,
1291
1292    // === random beacon ===
1293    /// Maximum allowed precision loss when reducing voting weights for the
1294    /// random beacon protocol.
1295    random_beacon_reduction_allowed_delta: Option<u16>,
1296
1297    /// Minimum number of shares below which voting weights will not be reduced
1298    /// for the random beacon protocol.
1299    random_beacon_reduction_lower_bound: Option<u32>,
1300
1301    /// Consensus Round after which DKG should be aborted and randomness
1302    /// disabled for the epoch, if it hasn't already completed.
1303    random_beacon_dkg_timeout_round: Option<u32>,
1304
1305    /// Minimum interval between consecutive rounds of generated randomness.
1306    random_beacon_min_round_interval_ms: Option<u64>,
1307
1308    /// Version of the random beacon DKG protocol.
1309    /// 0 was deprecated (and currently not supported), 1 is the default
1310    /// version.
1311    random_beacon_dkg_version: Option<u64>,
1312
1313    /// The maximum serialized transaction size (in bytes) accepted by
1314    /// consensus. `consensus_max_transaction_size_bytes` should include
1315    /// space for additional metadata, on top of the `max_tx_size_bytes`
1316    /// value.
1317    consensus_max_transaction_size_bytes: Option<u64>,
1318    /// The maximum size of transactions included in a consensus block.
1319    consensus_max_transactions_in_block_bytes: Option<u64>,
1320    /// The maximum number of transactions included in a consensus block.
1321    consensus_max_num_transactions_in_block: Option<u64>,
1322
1323    /// The max number of consensus rounds a transaction can be deferred due to
1324    /// shared object congestion. Transactions will be cancelled after this
1325    /// many rounds.
1326    max_deferral_rounds_for_congestion_control: Option<u64>,
1327
1328    /// Minimum interval of commit timestamps between consecutive checkpoints.
1329    min_checkpoint_interval_ms: Option<u64>,
1330
1331    /// Version number to use for version_specific_data in `CheckpointSummary`.
1332    checkpoint_summary_version_specific_data: Option<u64>,
1333
1334    /// The max number of transactions that can be included in a single Soft
1335    /// Bundle.
1336    max_soft_bundle_size: Option<u64>,
1337
1338    /// Deprecated because of bridge removal.
1339    /// Whether to try to form bridge committee
1340    // Note: this is not a feature flag because we want to distinguish between
1341    // `None` and `Some(false)`, as committee was already finalized on Testnet.
1342    bridge_should_try_to_finalize_committee: Option<bool>,
1343
1344    /// The max accumulated txn execution cost per object in a mysticeti commit.
1345    /// Transactions in a commit will be deferred once their touch shared
1346    /// objects hit this limit. Note that if
1347    /// `max_congestion_limit_overshoot_per_commit` is set, this may be overshot
1348    /// within a single commit, but the limit will be enforced in the long run.
1349    max_accumulated_txn_cost_per_object_in_mysticeti_commit: Option<u64>,
1350
1351    /// Maximum number of committee (validators taking part in consensus)
1352    /// validators at any moment. We do not allow the number of committee
1353    /// validators in any epoch to go above this.
1354    max_committee_members_count: Option<u64>,
1355
1356    /// Configures the garbage collection depth for consensus. When is unset or
1357    /// `0` then the garbage collection is disabled.
1358    consensus_gc_depth: Option<u32>,
1359
1360    /// Configures the maximum number of acknowledgments to be included in a
1361    /// block. It must be reasonably larger than the number of validators
1362    /// because not all validators create their blocks at the same pace.
1363    /// Default value set to 400. (5 x expected committee size (80)).
1364    /// Applicable only to `starfish` consensus.
1365    consensus_max_acknowledgments_per_block: Option<u32>,
1366
1367    /// The maximum amount that is allowed to overshoot the congestion limit
1368    /// specified by 'max_accumulated_txn_cost_per_object_in_mysticeti_commit'
1369    /// for any single commit. Any overshoot is tracked as a debt that must
1370    /// be accounted for in subsequent commits.
1371    max_congestion_limit_overshoot_per_commit: Option<u64>,
1372
1373    /// Scorer version. When set to `None`, MisbehaviorReports are not sent nor
1374    /// considered valid. When set to `Some(version)`, scores are included in
1375    /// the MisbehaviorReports messages, where `version` determines the scoring
1376    /// formulas and metrics to be used. Even if set to None, the Scorer
1377    /// component is created, having access to metrics and being able to expose
1378    /// validator scores. Also gates the wire format of the
1379    /// `MisbehaviorReport` consensus transaction — scorer and report bump
1380    /// together.
1381    scorer_version: Option<u16>,
1382
1383    // `auth_context` module
1384    // Cost params for the Move native function `native_digest(): vector<u8>`
1385    auth_context_digest_cost_base: Option<u64>,
1386    // Cost params for the Move native function `native_tx_data_bytes(): &vector<u8>`
1387    auth_context_tx_data_bytes_cost_base: Option<u64>,
1388    auth_context_tx_data_bytes_cost_per_byte: Option<u64>,
1389    // Cost params for the Move native function `native_tx_commands<C>(): vector<C>`
1390    auth_context_tx_commands_cost_base: Option<u64>,
1391    auth_context_tx_commands_cost_per_byte: Option<u64>,
1392    // Cost params for the Move native function `native_tx_inputs<I>(): vector<I>`
1393    auth_context_tx_inputs_cost_base: Option<u64>,
1394    auth_context_tx_inputs_cost_per_byte: Option<u64>,
1395    // Cost params for the Move native function `fun native_replace<I, C>(auth_digest: vector<u8>,
1396    // tx_inputs: vector<I>, tx_commands: vector<C>, tx_data_bytes: vector<u8>)`
1397    auth_context_replace_cost_base: Option<u64>,
1398    auth_context_replace_cost_per_byte: Option<u64>,
1399    // Cost params for the Move native functions
1400    // `fun native_sender_authenticator_function_info_v1<F>(): &Option<F>`
1401    // `fun native_sponsor_authenticator_function_info_v1<F>(): &Option<F>`
1402    auth_context_authenticator_function_info_v1_cost_base: Option<u64>,
1403}
1404
1405// feature flags
1406impl ProtocolConfig {
1407    // Add checks for feature flag support here, e.g.:
1408    // pub fn check_new_protocol_feature_supported(&self) -> Result<(), Error> {
1409    //     if self.feature_flags.new_protocol_feature_supported {
1410    //         Ok(())
1411    //     } else {
1412    //         Err(Error(format!(
1413    //             "new_protocol_feature is not supported at {:?}",
1414    //             self.version
1415    //         )))
1416    //     }
1417    // }
1418
1419    pub fn disable_invariant_violation_check_in_swap_loc(&self) -> bool {
1420        self.feature_flags
1421            .disable_invariant_violation_check_in_swap_loc
1422    }
1423
1424    pub fn no_extraneous_module_bytes(&self) -> bool {
1425        self.feature_flags.no_extraneous_module_bytes
1426    }
1427
1428    pub fn consensus_transaction_ordering(&self) -> ConsensusTransactionOrdering {
1429        self.feature_flags.consensus_transaction_ordering
1430    }
1431
1432    pub fn dkg_version(&self) -> u64 {
1433        // Version 0 was deprecated and removed, the default is 1 if not set.
1434        self.random_beacon_dkg_version.unwrap_or(1)
1435    }
1436
1437    pub fn hardened_otw_check(&self) -> bool {
1438        self.feature_flags.hardened_otw_check
1439    }
1440
1441    pub fn enable_poseidon(&self) -> bool {
1442        self.feature_flags.enable_poseidon
1443    }
1444
1445    pub fn enable_group_ops_native_function_msm(&self) -> bool {
1446        self.feature_flags.enable_group_ops_native_function_msm
1447    }
1448
1449    pub fn per_object_congestion_control_mode(&self) -> PerObjectCongestionControlMode {
1450        self.feature_flags.per_object_congestion_control_mode
1451    }
1452
1453    pub fn consensus_choice(&self) -> ConsensusChoice {
1454        self.feature_flags.consensus_choice
1455    }
1456
1457    pub fn consensus_network(&self) -> ConsensusNetwork {
1458        self.feature_flags.consensus_network
1459    }
1460
1461    pub fn enable_vdf(&self) -> bool {
1462        self.feature_flags.enable_vdf
1463    }
1464
1465    pub fn passkey_auth(&self) -> bool {
1466        self.feature_flags.passkey_auth
1467    }
1468
1469    pub fn max_transaction_size_bytes(&self) -> u64 {
1470        // Provide a default value if protocol config version is too low.
1471        self.consensus_max_transaction_size_bytes
1472            .unwrap_or(256 * 1024)
1473    }
1474
1475    pub fn max_transactions_in_block_bytes(&self) -> u64 {
1476        if cfg!(msim) {
1477            256 * 1024
1478        } else {
1479            self.consensus_max_transactions_in_block_bytes
1480                .unwrap_or(512 * 1024)
1481        }
1482    }
1483
1484    pub fn max_num_transactions_in_block(&self) -> u64 {
1485        if cfg!(msim) {
1486            8
1487        } else {
1488            self.consensus_max_num_transactions_in_block.unwrap_or(512)
1489        }
1490    }
1491
1492    pub fn rethrow_serialization_type_layout_errors(&self) -> bool {
1493        self.feature_flags.rethrow_serialization_type_layout_errors
1494    }
1495
1496    pub fn relocate_event_module(&self) -> bool {
1497        self.feature_flags.relocate_event_module
1498    }
1499
1500    pub fn protocol_defined_base_fee(&self) -> bool {
1501        self.feature_flags.protocol_defined_base_fee
1502    }
1503
1504    pub fn uncompressed_g1_group_elements(&self) -> bool {
1505        self.feature_flags.uncompressed_g1_group_elements
1506    }
1507
1508    pub fn disallow_new_modules_in_deps_only_packages(&self) -> bool {
1509        self.feature_flags
1510            .disallow_new_modules_in_deps_only_packages
1511    }
1512
1513    pub fn native_charging_v2(&self) -> bool {
1514        self.feature_flags.native_charging_v2
1515    }
1516
1517    pub fn consensus_round_prober(&self) -> bool {
1518        self.feature_flags.consensus_round_prober
1519    }
1520
1521    pub fn consensus_distributed_vote_scoring_strategy(&self) -> bool {
1522        self.feature_flags
1523            .consensus_distributed_vote_scoring_strategy
1524    }
1525
1526    pub fn gc_depth(&self) -> u32 {
1527        if cfg!(msim) {
1528            // exercise a very low gc_depth
1529            min(5, self.consensus_gc_depth.unwrap_or(0))
1530        } else {
1531            self.consensus_gc_depth.unwrap_or(0)
1532        }
1533    }
1534
1535    pub fn consensus_linearize_subdag_v2(&self) -> bool {
1536        let res = self.feature_flags.consensus_linearize_subdag_v2;
1537        assert!(
1538            !res || self.gc_depth() > 0,
1539            "The consensus linearize sub dag V2 requires GC to be enabled"
1540        );
1541        res
1542    }
1543
1544    pub fn consensus_max_acknowledgments_per_block_or_default(&self) -> u32 {
1545        self.consensus_max_acknowledgments_per_block.unwrap_or(400)
1546    }
1547
1548    pub fn max_acknowledgments_per_block(&self, committee_size: usize) -> usize {
1549        if self.consensus_block_restrictions() {
1550            2 * committee_size
1551        } else {
1552            self.consensus_max_acknowledgments_per_block_or_default() as usize
1553        }
1554    }
1555
1556    pub fn max_commit_votes_per_block(&self, committee_size: usize) -> usize {
1557        if self.consensus_block_restrictions() {
1558            committee_size
1559        } else {
1560            100
1561        }
1562    }
1563
1564    pub fn variant_nodes(&self) -> bool {
1565        self.feature_flags.variant_nodes
1566    }
1567
1568    pub fn consensus_smart_ancestor_selection(&self) -> bool {
1569        self.feature_flags.consensus_smart_ancestor_selection
1570    }
1571
1572    pub fn consensus_round_prober_probe_accepted_rounds(&self) -> bool {
1573        self.feature_flags
1574            .consensus_round_prober_probe_accepted_rounds
1575    }
1576
1577    pub fn consensus_zstd_compression(&self) -> bool {
1578        self.feature_flags.consensus_zstd_compression
1579    }
1580
1581    pub fn congestion_control_min_free_execution_slot(&self) -> bool {
1582        self.feature_flags
1583            .congestion_control_min_free_execution_slot
1584    }
1585
1586    pub fn accept_passkey_in_multisig(&self) -> bool {
1587        self.feature_flags.accept_passkey_in_multisig
1588    }
1589
1590    pub fn consensus_batched_block_sync(&self) -> bool {
1591        self.feature_flags.consensus_batched_block_sync
1592    }
1593
1594    /// Check if the gas price feedback mechanism (which is used for
1595    /// transactions cancelled due to shared object congestion) is enabled
1596    pub fn congestion_control_gas_price_feedback_mechanism(&self) -> bool {
1597        self.feature_flags
1598            .congestion_control_gas_price_feedback_mechanism
1599    }
1600
1601    pub fn validate_identifier_inputs(&self) -> bool {
1602        self.feature_flags.validate_identifier_inputs
1603    }
1604
1605    pub fn minimize_child_object_mutations(&self) -> bool {
1606        self.feature_flags.minimize_child_object_mutations
1607    }
1608
1609    pub fn dependency_linkage_error(&self) -> bool {
1610        self.feature_flags.dependency_linkage_error
1611    }
1612
1613    pub fn additional_multisig_checks(&self) -> bool {
1614        self.feature_flags.additional_multisig_checks
1615    }
1616
1617    pub fn consensus_num_requested_prior_commits_at_startup(&self) -> u32 {
1618        // TODO: this will eventually be the max of some number of other
1619        // parameters.
1620        0
1621    }
1622
1623    pub fn normalize_ptb_arguments(&self) -> bool {
1624        self.feature_flags.normalize_ptb_arguments
1625    }
1626
1627    pub fn select_committee_from_eligible_validators(&self) -> bool {
1628        let res = self.feature_flags.select_committee_from_eligible_validators;
1629        assert!(
1630            !res || (self.protocol_defined_base_fee()
1631                && self.max_committee_members_count_as_option().is_some()),
1632            "select_committee_from_eligible_validators requires protocol_defined_base_fee and max_committee_members_count to be set"
1633        );
1634        res
1635    }
1636
1637    pub fn track_non_committee_eligible_validators(&self) -> bool {
1638        self.feature_flags.track_non_committee_eligible_validators
1639    }
1640
1641    pub fn select_committee_supporting_next_epoch_version(&self) -> bool {
1642        let res = self
1643            .feature_flags
1644            .select_committee_supporting_next_epoch_version;
1645        assert!(
1646            !res || (self.track_non_committee_eligible_validators()
1647                && self.select_committee_from_eligible_validators()),
1648            "select_committee_supporting_next_epoch_version requires select_committee_from_eligible_validators to be set"
1649        );
1650        res
1651    }
1652
1653    pub fn consensus_median_timestamp_with_checkpoint_enforcement(&self) -> bool {
1654        let res = self
1655            .feature_flags
1656            .consensus_median_timestamp_with_checkpoint_enforcement;
1657        assert!(
1658            !res || self.gc_depth() > 0,
1659            "The consensus median timestamp with checkpoint enforcement requires GC to be enabled"
1660        );
1661        res
1662    }
1663
1664    pub fn consensus_commit_transactions_only_for_traversed_headers(&self) -> bool {
1665        self.feature_flags
1666            .consensus_commit_transactions_only_for_traversed_headers
1667    }
1668
1669    /// Check whether congestion limit overshoot is enabled in the gas price
1670    /// feedback mechanism.
1671    pub fn congestion_limit_overshoot_in_gas_price_feedback_mechanism(&self) -> bool {
1672        self.feature_flags
1673            .congestion_limit_overshoot_in_gas_price_feedback_mechanism
1674    }
1675
1676    /// Check whether a separate gas price feedback mechanism is used for
1677    /// randomness transactions.
1678    pub fn separate_gas_price_feedback_mechanism_for_randomness(&self) -> bool {
1679        self.feature_flags
1680            .separate_gas_price_feedback_mechanism_for_randomness
1681    }
1682
1683    pub fn metadata_in_module_bytes(&self) -> bool {
1684        self.feature_flags.metadata_in_module_bytes
1685    }
1686
1687    pub fn publish_package_metadata(&self) -> bool {
1688        self.feature_flags.publish_package_metadata
1689    }
1690
1691    pub fn enable_move_authentication(&self) -> bool {
1692        self.feature_flags.enable_move_authentication
1693    }
1694
1695    pub fn additional_borrow_checks(&self) -> bool {
1696        self.feature_flags.additional_borrow_checks
1697    }
1698
1699    pub fn enable_move_authentication_for_sponsor(&self) -> bool {
1700        let enable_move_authentication_for_sponsor =
1701            self.feature_flags.enable_move_authentication_for_sponsor;
1702        assert!(
1703            !enable_move_authentication_for_sponsor || self.enable_move_authentication(),
1704            "enable_move_authentication_for_sponsor requires enable_move_authentication to be set"
1705        );
1706        enable_move_authentication_for_sponsor
1707    }
1708
1709    pub fn pass_validator_scores_to_advance_epoch(&self) -> bool {
1710        self.feature_flags.pass_validator_scores_to_advance_epoch
1711    }
1712
1713    pub fn calculate_validator_scores(&self) -> bool {
1714        let calculate_validator_scores = self.feature_flags.calculate_validator_scores;
1715        assert!(
1716            !calculate_validator_scores || self.scorer_version.is_some(),
1717            "calculate_validator_scores requires scorer_version to be set"
1718        );
1719        calculate_validator_scores
1720    }
1721
1722    pub fn adjust_rewards_by_score(&self) -> bool {
1723        let adjust = self.feature_flags.adjust_rewards_by_score;
1724        assert!(
1725            !adjust || (self.scorer_version.is_some() && self.calculate_validator_scores()),
1726            "adjust_rewards_by_score requires scorer_version to be set"
1727        );
1728        adjust
1729    }
1730
1731    pub fn pass_calculated_validator_scores_to_advance_epoch(&self) -> bool {
1732        let pass = self
1733            .feature_flags
1734            .pass_calculated_validator_scores_to_advance_epoch;
1735        assert!(
1736            !pass
1737                || (self.pass_validator_scores_to_advance_epoch()
1738                    && self.calculate_validator_scores()),
1739            "pass_calculated_validator_scores_to_advance_epoch requires pass_validator_scores_to_advance_epoch and calculate_validator_scores to be enabled"
1740        );
1741        pass
1742    }
1743    pub fn consensus_fast_commit_sync(&self) -> bool {
1744        let res = self.feature_flags.consensus_fast_commit_sync;
1745        assert!(
1746            !res || self.consensus_commit_transactions_only_for_traversed_headers(),
1747            "consensus_fast_commit_sync requires consensus_commit_transactions_only_for_traversed_headers to be enabled"
1748        );
1749        res
1750    }
1751
1752    pub fn consensus_block_restrictions(&self) -> bool {
1753        self.feature_flags.consensus_block_restrictions
1754    }
1755
1756    pub fn move_native_tx_context(&self) -> bool {
1757        self.feature_flags.move_native_tx_context
1758    }
1759
1760    pub fn pre_consensus_sponsor_only_move_authentication(&self) -> bool {
1761        let pre_consensus_sponsor_only_move_authentication = self
1762            .feature_flags
1763            .pre_consensus_sponsor_only_move_authentication;
1764        if pre_consensus_sponsor_only_move_authentication {
1765            assert!(
1766                self.enable_move_authentication(),
1767                "pre_consensus_sponsor_only_move_authentication requires enable_move_authentication to be set"
1768            );
1769            assert!(
1770                self.enable_move_authentication_for_sponsor(),
1771                "pre_consensus_sponsor_only_move_authentication requires enable_move_authentication_for_sponsor to be set"
1772            );
1773        }
1774        pre_consensus_sponsor_only_move_authentication
1775    }
1776
1777    pub fn consensus_starfish_speed(&self) -> bool {
1778        let res = self.feature_flags.consensus_starfish_speed;
1779        assert!(
1780            !res || self.consensus_fast_commit_sync(),
1781            "consensus_starfish_speed requires consensus_fast_commit_sync to be enabled"
1782        );
1783        res
1784    }
1785
1786    pub fn always_advance_dkg_to_resolution(&self) -> bool {
1787        self.feature_flags.always_advance_dkg_to_resolution
1788    }
1789
1790    pub fn enable_pcool_flow(&self) -> bool {
1791        self.feature_flags.enable_pcool_flow
1792    }
1793}
1794
1795#[cfg(not(msim))]
1796static POISON_VERSION_METHODS: AtomicBool = const { AtomicBool::new(false) };
1797
1798// Use a thread local in sim tests for test isolation.
1799#[cfg(msim)]
1800thread_local! {
1801    static POISON_VERSION_METHODS: AtomicBool = const { AtomicBool::new(false) };
1802}
1803
1804// Instantiations for each protocol version.
1805impl ProtocolConfig {
1806    /// Get the value ProtocolConfig that are in effect during the given
1807    /// protocol version.
1808    pub fn get_for_version(version: ProtocolVersion, chain: Chain) -> Self {
1809        // ProtocolVersion can be deserialized so we need to check it here as well.
1810        assert!(
1811            version >= ProtocolVersion::MIN,
1812            "Network protocol version is {:?}, but the minimum supported version by the binary is {:?}. Please upgrade the binary.",
1813            version,
1814            ProtocolVersion::MIN.0,
1815        );
1816        assert!(
1817            version <= ProtocolVersion::MAX_ALLOWED,
1818            "Network protocol version is {:?}, but the maximum supported version by the binary is {:?}. Please upgrade the binary.",
1819            version,
1820            ProtocolVersion::MAX_ALLOWED.0,
1821        );
1822
1823        let mut ret = Self::get_for_version_impl(version, chain);
1824        ret.version = version;
1825
1826        ret = CONFIG_OVERRIDE.with(|ovr| {
1827            if let Some(override_fn) = &*ovr.borrow() {
1828                warn!(
1829                    "overriding ProtocolConfig settings with custom settings (you should not see this log outside of tests)"
1830                );
1831                override_fn(version, ret)
1832            } else {
1833                ret
1834            }
1835        });
1836
1837        if std::env::var("IOTA_PROTOCOL_CONFIG_OVERRIDE_ENABLE").is_ok() {
1838            warn!(
1839                "overriding ProtocolConfig settings with custom settings; this may break non-local networks"
1840            );
1841
1842            // First, deserialize the top-level ProtocolConfig fields
1843            let overrides: ProtocolConfigOptional =
1844                serde_env::from_env_with_prefix("IOTA_PROTOCOL_CONFIG_OVERRIDE")
1845                    .expect("failed to parse ProtocolConfig override env variables");
1846            overrides.apply_to(&mut ret);
1847
1848            // Then, separately deserialize FeatureFlags fields
1849            let feature_flag_overrides: FeatureFlagsOptional =
1850                serde_env::from_env_with_prefix("IOTA_PROTOCOL_CONFIG_FEATURE_FLAGS_OVERRIDE")
1851                    .expect("failed to parse ProtocolConfig feature flags override env variables");
1852
1853            feature_flag_overrides.apply_to(&mut ret.feature_flags);
1854        }
1855
1856        ret
1857    }
1858
1859    /// Get the value ProtocolConfig that are in effect during the given
1860    /// protocol version. Or none if the version is not supported.
1861    pub fn get_for_version_if_supported(version: ProtocolVersion, chain: Chain) -> Option<Self> {
1862        if version.0 >= ProtocolVersion::MIN.0 && version.0 <= ProtocolVersion::MAX_ALLOWED.0 {
1863            let mut ret = Self::get_for_version_impl(version, chain);
1864            ret.version = version;
1865            Some(ret)
1866        } else {
1867            None
1868        }
1869    }
1870
1871    #[cfg(not(msim))]
1872    pub fn poison_get_for_min_version() {
1873        POISON_VERSION_METHODS.store(true, Ordering::Relaxed);
1874    }
1875
1876    #[cfg(not(msim))]
1877    fn load_poison_get_for_min_version() -> bool {
1878        POISON_VERSION_METHODS.load(Ordering::Relaxed)
1879    }
1880
1881    #[cfg(msim)]
1882    pub fn poison_get_for_min_version() {
1883        POISON_VERSION_METHODS.with(|p| p.store(true, Ordering::Relaxed));
1884    }
1885
1886    #[cfg(msim)]
1887    fn load_poison_get_for_min_version() -> bool {
1888        POISON_VERSION_METHODS.with(|p| p.load(Ordering::Relaxed))
1889    }
1890
1891    pub fn convert_type_argument_error(&self) -> bool {
1892        self.feature_flags.convert_type_argument_error
1893    }
1894
1895    /// Convenience to get the constants at the current minimum supported
1896    /// version. Mainly used by client code that may not yet be
1897    /// protocol-version aware.
1898    pub fn get_for_min_version() -> Self {
1899        if Self::load_poison_get_for_min_version() {
1900            panic!("get_for_min_version called on validator");
1901        }
1902        ProtocolConfig::get_for_version(ProtocolVersion::MIN, Chain::Unknown)
1903    }
1904
1905    /// CAREFUL! - You probably want to use `get_for_version` instead.
1906    ///
1907    /// Convenience to get the constants at the current maximum supported
1908    /// version. Mainly used by genesis. Note well that this function uses
1909    /// the max version supported locally by the node, which is not
1910    /// necessarily the current version of the network. ALSO, this function
1911    /// disregards chain specific config (by using Chain::Unknown), thereby
1912    /// potentially returning a protocol config that is incorrect for some
1913    /// feature flags. Definitely safe for testing and for protocol version
1914    /// 11 and prior.
1915    #[expect(non_snake_case)]
1916    pub fn get_for_max_version_UNSAFE() -> Self {
1917        if Self::load_poison_get_for_min_version() {
1918            panic!("get_for_max_version_UNSAFE called on validator");
1919        }
1920        ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown)
1921    }
1922
1923    fn get_for_version_impl(version: ProtocolVersion, chain: Chain) -> Self {
1924        #[cfg(msim)]
1925        {
1926            // populate the fake simulator version # with a different base tx cost.
1927            if version > ProtocolVersion::MAX {
1928                let mut config = Self::get_for_version_impl(ProtocolVersion::MAX, Chain::Unknown);
1929                config.base_tx_cost_fixed = Some(config.base_tx_cost_fixed() + 1000);
1930                return config;
1931            }
1932        }
1933
1934        // IMPORTANT: Never modify the value of any constant for a pre-existing protocol
1935        // version. To change the values here you must create a new protocol
1936        // version with the new values!
1937        let mut cfg = Self {
1938            version,
1939
1940            feature_flags: Default::default(),
1941
1942            max_tx_size_bytes: Some(128 * 1024),
1943            // We need this number to be at least 100x less than
1944            // `max_serialized_tx_effects_size_bytes`otherwise effects can be huge
1945            max_input_objects: Some(2048),
1946            max_serialized_tx_effects_size_bytes: Some(512 * 1024),
1947            max_serialized_tx_effects_size_bytes_system_tx: Some(512 * 1024 * 16),
1948            max_gas_payment_objects: Some(256),
1949            max_modules_in_publish: Some(64),
1950            max_package_dependencies: Some(32),
1951            max_arguments: Some(512),
1952            max_type_arguments: Some(16),
1953            max_type_argument_depth: Some(16),
1954            max_pure_argument_size: Some(16 * 1024),
1955            max_programmable_tx_commands: Some(1024),
1956            move_binary_format_version: Some(7),
1957            min_move_binary_format_version: Some(6),
1958            binary_module_handles: Some(100),
1959            binary_struct_handles: Some(300),
1960            binary_function_handles: Some(1500),
1961            binary_function_instantiations: Some(750),
1962            binary_signatures: Some(1000),
1963            binary_constant_pool: Some(4000),
1964            binary_identifiers: Some(10000),
1965            binary_address_identifiers: Some(100),
1966            binary_struct_defs: Some(200),
1967            binary_struct_def_instantiations: Some(100),
1968            binary_function_defs: Some(1000),
1969            binary_field_handles: Some(500),
1970            binary_field_instantiations: Some(250),
1971            binary_friend_decls: Some(100),
1972            binary_enum_defs: None,
1973            binary_enum_def_instantiations: None,
1974            binary_variant_handles: None,
1975            binary_variant_instantiation_handles: None,
1976            max_move_object_size: Some(250 * 1024),
1977            max_move_package_size: Some(100 * 1024),
1978            max_publish_or_upgrade_per_ptb: Some(5),
1979            // max gas budget for an authentication is in NANOS
1980            max_auth_gas: None,
1981            // max gas budget is in NANOS and an absolute value 50IOTA
1982            max_tx_gas: Some(50_000_000_000),
1983            max_gas_price: Some(100_000),
1984            max_gas_computation_bucket: Some(5_000_000),
1985            max_loop_depth: Some(5),
1986            max_generic_instantiation_length: Some(32),
1987            max_function_parameters: Some(128),
1988            max_basic_blocks: Some(1024),
1989            max_value_stack_size: Some(1024),
1990            max_type_nodes: Some(256),
1991            max_push_size: Some(10000),
1992            max_struct_definitions: Some(200),
1993            max_function_definitions: Some(1000),
1994            max_fields_in_struct: Some(32),
1995            max_dependency_depth: Some(100),
1996            max_num_event_emit: Some(1024),
1997            max_num_new_move_object_ids: Some(2048),
1998            max_num_new_move_object_ids_system_tx: Some(2048 * 16),
1999            max_num_deleted_move_object_ids: Some(2048),
2000            max_num_deleted_move_object_ids_system_tx: Some(2048 * 16),
2001            max_num_transferred_move_object_ids: Some(2048),
2002            max_num_transferred_move_object_ids_system_tx: Some(2048 * 16),
2003            max_event_emit_size: Some(250 * 1024),
2004            max_move_vector_len: Some(256 * 1024),
2005            max_type_to_layout_nodes: None,
2006            max_ptb_value_size: None,
2007
2008            max_back_edges_per_function: Some(10_000),
2009            max_back_edges_per_module: Some(10_000),
2010
2011            max_verifier_meter_ticks_per_function: Some(16_000_000),
2012
2013            max_meter_ticks_per_module: Some(16_000_000),
2014            max_meter_ticks_per_package: Some(16_000_000),
2015
2016            object_runtime_max_num_cached_objects: Some(1000),
2017            object_runtime_max_num_cached_objects_system_tx: Some(1000 * 16),
2018            object_runtime_max_num_store_entries: Some(1000),
2019            object_runtime_max_num_store_entries_system_tx: Some(1000 * 16),
2020            // min gas budget is in NANOS and an absolute value 1000 NANOS or 0.000001IOTA
2021            base_tx_cost_fixed: Some(1_000),
2022            package_publish_cost_fixed: Some(1_000),
2023            base_tx_cost_per_byte: Some(0),
2024            package_publish_cost_per_byte: Some(80),
2025            obj_access_cost_read_per_byte: Some(15),
2026            obj_access_cost_mutate_per_byte: Some(40),
2027            obj_access_cost_delete_per_byte: Some(40),
2028            obj_access_cost_verify_per_byte: Some(200),
2029            obj_data_cost_refundable: Some(100),
2030            obj_metadata_cost_non_refundable: Some(50),
2031            gas_model_version: Some(1),
2032            storage_rebate_rate: Some(10000),
2033            // Change reward slashing rate to 100%.
2034            reward_slashing_rate: Some(10000),
2035            storage_gas_price: Some(76),
2036            base_gas_price: None,
2037            // The initial subsidy (target reward) for validators per epoch.
2038            // Refer to the IOTA tokenomics for the origin of this value.
2039            validator_target_reward: Some(767_000 * 1_000_000_000),
2040            max_transactions_per_checkpoint: Some(10_000),
2041            max_checkpoint_size_bytes: Some(30 * 1024 * 1024),
2042
2043            // For now, perform upgrades with a bare quorum of validators.
2044            buffer_stake_for_protocol_upgrade_bps: Some(5000),
2045
2046            // === Native Function Costs ===
2047            // `address` module
2048            // Cost params for the Move native function `address::from_bytes(bytes: vector<u8>)`
2049            address_from_bytes_cost_base: Some(52),
2050            // Cost params for the Move native function `address::to_u256(address): u256`
2051            address_to_u256_cost_base: Some(52),
2052            // Cost params for the Move native function `address::from_u256(u256): address`
2053            address_from_u256_cost_base: Some(52),
2054
2055            // `config` module
2056            // Cost params for the Move native function `read_setting_impl``
2057            config_read_setting_impl_cost_base: Some(100),
2058            config_read_setting_impl_cost_per_byte: Some(40),
2059
2060            // `dynamic_field` module
2061            // Cost params for the Move native function `hash_type_and_key<K: copy + drop +
2062            // store>(parent: address, k: K): address`
2063            dynamic_field_hash_type_and_key_cost_base: Some(100),
2064            dynamic_field_hash_type_and_key_type_cost_per_byte: Some(2),
2065            dynamic_field_hash_type_and_key_value_cost_per_byte: Some(2),
2066            dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Some(2),
2067            // Cost params for the Move native function `add_child_object<Child: key>(parent:
2068            // address, child: Child)`
2069            dynamic_field_add_child_object_cost_base: Some(100),
2070            dynamic_field_add_child_object_type_cost_per_byte: Some(10),
2071            dynamic_field_add_child_object_value_cost_per_byte: Some(10),
2072            dynamic_field_add_child_object_struct_tag_cost_per_byte: Some(10),
2073            // Cost params for the Move native function `borrow_child_object_mut<Child: key>(parent:
2074            // &mut UID, id: address): &mut Child`
2075            dynamic_field_borrow_child_object_cost_base: Some(100),
2076            dynamic_field_borrow_child_object_child_ref_cost_per_byte: Some(10),
2077            dynamic_field_borrow_child_object_type_cost_per_byte: Some(10),
2078            // Cost params for the Move native function `remove_child_object<Child: key>(parent:
2079            // address, id: address): Child`
2080            dynamic_field_remove_child_object_cost_base: Some(100),
2081            dynamic_field_remove_child_object_child_cost_per_byte: Some(2),
2082            dynamic_field_remove_child_object_type_cost_per_byte: Some(2),
2083            // Cost params for the Move native function `has_child_object(parent: address, id:
2084            // address): bool`
2085            dynamic_field_has_child_object_cost_base: Some(100),
2086            // Cost params for the Move native function `has_child_object_with_ty<Child:
2087            // key>(parent: address, id: address): bool`
2088            dynamic_field_has_child_object_with_ty_cost_base: Some(100),
2089            dynamic_field_has_child_object_with_ty_type_cost_per_byte: Some(2),
2090            dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Some(2),
2091
2092            // `event` module
2093            // Cost params for the Move native function `event::emit<T: copy + drop>(event: T)`
2094            event_emit_cost_base: Some(52),
2095            event_emit_value_size_derivation_cost_per_byte: Some(2),
2096            event_emit_tag_size_derivation_cost_per_byte: Some(5),
2097            event_emit_output_cost_per_byte: Some(10),
2098
2099            //  `object` module
2100            // Cost params for the Move native function `borrow_uid<T: key>(obj: &T): &UID`
2101            object_borrow_uid_cost_base: Some(52),
2102            // Cost params for the Move native function `delete_impl(id: address)`
2103            object_delete_impl_cost_base: Some(52),
2104            // Cost params for the Move native function `record_new_uid(id: address)`
2105            object_record_new_uid_cost_base: Some(52),
2106
2107            // `transfer` module
2108            // Cost params for the Move native function `transfer_impl<T: key>(obj: T, recipient:
2109            // address)`
2110            transfer_transfer_internal_cost_base: Some(52),
2111            // Cost params for the Move native function `freeze_object<T: key>(obj: T)`
2112            transfer_freeze_object_cost_base: Some(52),
2113            // Cost params for the Move native function `share_object<T: key>(obj: T)`
2114            transfer_share_object_cost_base: Some(52),
2115            transfer_receive_object_cost_base: Some(52),
2116
2117            // `tx_context` module
2118            // Cost params for the Move native function `transfer_impl<T: key>(obj: T, recipient:
2119            // address)`
2120            tx_context_derive_id_cost_base: Some(52),
2121            tx_context_fresh_id_cost_base: None,
2122            tx_context_sender_cost_base: None,
2123            tx_context_digest_cost_base: None,
2124            tx_context_epoch_cost_base: None,
2125            tx_context_epoch_timestamp_ms_cost_base: None,
2126            tx_context_sponsor_cost_base: None,
2127            tx_context_rgp_cost_base: None,
2128            tx_context_gas_price_cost_base: None,
2129            tx_context_gas_budget_cost_base: None,
2130            tx_context_ids_created_cost_base: None,
2131            tx_context_replace_cost_base: None,
2132
2133            // `types` module
2134            // Cost params for the Move native function `is_one_time_witness<T: drop>(_: &T): bool`
2135            types_is_one_time_witness_cost_base: Some(52),
2136            types_is_one_time_witness_type_tag_cost_per_byte: Some(2),
2137            types_is_one_time_witness_type_cost_per_byte: Some(2),
2138
2139            // `validator` module
2140            // Cost params for the Move native function `validate_metadata_bcs(metadata:
2141            // vector<u8>)`
2142            validator_validate_metadata_cost_base: Some(52),
2143            validator_validate_metadata_data_cost_per_byte: Some(2),
2144
2145            // Crypto
2146            crypto_invalid_arguments_cost: Some(100),
2147            // bls12381::bls12381_min_pk_verify
2148            bls12381_bls12381_min_sig_verify_cost_base: Some(52),
2149            bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Some(2),
2150            bls12381_bls12381_min_sig_verify_msg_cost_per_block: Some(2),
2151
2152            // bls12381::bls12381_min_pk_verify
2153            bls12381_bls12381_min_pk_verify_cost_base: Some(52),
2154            bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Some(2),
2155            bls12381_bls12381_min_pk_verify_msg_cost_per_block: Some(2),
2156
2157            // ecdsa_k1::ecrecover
2158            ecdsa_k1_ecrecover_keccak256_cost_base: Some(52),
2159            ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Some(2),
2160            ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Some(2),
2161            ecdsa_k1_ecrecover_sha256_cost_base: Some(52),
2162            ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Some(2),
2163            ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Some(2),
2164
2165            // ecdsa_k1::decompress_pubkey
2166            ecdsa_k1_decompress_pubkey_cost_base: Some(52),
2167
2168            // ecdsa_k1::secp256k1_verify
2169            ecdsa_k1_secp256k1_verify_keccak256_cost_base: Some(52),
2170            ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Some(2),
2171            ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Some(2),
2172            ecdsa_k1_secp256k1_verify_sha256_cost_base: Some(52),
2173            ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Some(2),
2174            ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Some(2),
2175
2176            // ecdsa_r1::ecrecover
2177            ecdsa_r1_ecrecover_keccak256_cost_base: Some(52),
2178            ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Some(2),
2179            ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Some(2),
2180            ecdsa_r1_ecrecover_sha256_cost_base: Some(52),
2181            ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Some(2),
2182            ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Some(2),
2183
2184            // ecdsa_r1::secp256k1_verify
2185            ecdsa_r1_secp256r1_verify_keccak256_cost_base: Some(52),
2186            ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Some(2),
2187            ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Some(2),
2188            ecdsa_r1_secp256r1_verify_sha256_cost_base: Some(52),
2189            ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Some(2),
2190            ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Some(2),
2191
2192            // ecvrf::verify
2193            ecvrf_ecvrf_verify_cost_base: Some(52),
2194            ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Some(2),
2195            ecvrf_ecvrf_verify_alpha_string_cost_per_block: Some(2),
2196
2197            // ed25519
2198            ed25519_ed25519_verify_cost_base: Some(52),
2199            ed25519_ed25519_verify_msg_cost_per_byte: Some(2),
2200            ed25519_ed25519_verify_msg_cost_per_block: Some(2),
2201
2202            // groth16::prepare_verifying_key
2203            groth16_prepare_verifying_key_bls12381_cost_base: Some(52),
2204            groth16_prepare_verifying_key_bn254_cost_base: Some(52),
2205
2206            // groth16::verify_groth16_proof_internal
2207            groth16_verify_groth16_proof_internal_bls12381_cost_base: Some(52),
2208            groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Some(2),
2209            groth16_verify_groth16_proof_internal_bn254_cost_base: Some(52),
2210            groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Some(2),
2211            groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Some(2),
2212
2213            // hash::blake2b256
2214            hash_blake2b256_cost_base: Some(52),
2215            hash_blake2b256_data_cost_per_byte: Some(2),
2216            hash_blake2b256_data_cost_per_block: Some(2),
2217            // hash::keccak256
2218            hash_keccak256_cost_base: Some(52),
2219            hash_keccak256_data_cost_per_byte: Some(2),
2220            hash_keccak256_data_cost_per_block: Some(2),
2221
2222            poseidon_bn254_cost_base: None,
2223            poseidon_bn254_cost_per_block: None,
2224
2225            // hmac::hmac_sha3_256
2226            hmac_hmac_sha3_256_cost_base: Some(52),
2227            hmac_hmac_sha3_256_input_cost_per_byte: Some(2),
2228            hmac_hmac_sha3_256_input_cost_per_block: Some(2),
2229
2230            // group ops
2231            group_ops_bls12381_decode_scalar_cost: Some(52),
2232            group_ops_bls12381_decode_g1_cost: Some(52),
2233            group_ops_bls12381_decode_g2_cost: Some(52),
2234            group_ops_bls12381_decode_gt_cost: Some(52),
2235            group_ops_bls12381_scalar_add_cost: Some(52),
2236            group_ops_bls12381_g1_add_cost: Some(52),
2237            group_ops_bls12381_g2_add_cost: Some(52),
2238            group_ops_bls12381_gt_add_cost: Some(52),
2239            group_ops_bls12381_scalar_sub_cost: Some(52),
2240            group_ops_bls12381_g1_sub_cost: Some(52),
2241            group_ops_bls12381_g2_sub_cost: Some(52),
2242            group_ops_bls12381_gt_sub_cost: Some(52),
2243            group_ops_bls12381_scalar_mul_cost: Some(52),
2244            group_ops_bls12381_g1_mul_cost: Some(52),
2245            group_ops_bls12381_g2_mul_cost: Some(52),
2246            group_ops_bls12381_gt_mul_cost: Some(52),
2247            group_ops_bls12381_scalar_div_cost: Some(52),
2248            group_ops_bls12381_g1_div_cost: Some(52),
2249            group_ops_bls12381_g2_div_cost: Some(52),
2250            group_ops_bls12381_gt_div_cost: Some(52),
2251            group_ops_bls12381_g1_hash_to_base_cost: Some(52),
2252            group_ops_bls12381_g2_hash_to_base_cost: Some(52),
2253            group_ops_bls12381_g1_hash_to_cost_per_byte: Some(2),
2254            group_ops_bls12381_g2_hash_to_cost_per_byte: Some(2),
2255            group_ops_bls12381_g1_msm_base_cost: Some(52),
2256            group_ops_bls12381_g2_msm_base_cost: Some(52),
2257            group_ops_bls12381_g1_msm_base_cost_per_input: Some(52),
2258            group_ops_bls12381_g2_msm_base_cost_per_input: Some(52),
2259            group_ops_bls12381_msm_max_len: Some(32),
2260            group_ops_bls12381_pairing_cost: Some(52),
2261            group_ops_bls12381_g1_to_uncompressed_g1_cost: None,
2262            group_ops_bls12381_uncompressed_g1_to_g1_cost: None,
2263            group_ops_bls12381_uncompressed_g1_sum_base_cost: None,
2264            group_ops_bls12381_uncompressed_g1_sum_cost_per_term: None,
2265            group_ops_bls12381_uncompressed_g1_sum_max_terms: None,
2266
2267            // zklogin::check_zklogin_id
2268            #[allow(deprecated)]
2269            check_zklogin_id_cost_base: Some(200),
2270            #[allow(deprecated)]
2271            // zklogin::check_zklogin_issuer
2272            check_zklogin_issuer_cost_base: Some(200),
2273
2274            vdf_verify_vdf_cost: None,
2275            vdf_hash_to_input_cost: None,
2276
2277            bcs_per_byte_serialized_cost: Some(2),
2278            bcs_legacy_min_output_size_cost: Some(1),
2279            bcs_failure_cost: Some(52),
2280            hash_sha2_256_base_cost: Some(52),
2281            hash_sha2_256_per_byte_cost: Some(2),
2282            hash_sha2_256_legacy_min_input_len_cost: Some(1),
2283            hash_sha3_256_base_cost: Some(52),
2284            hash_sha3_256_per_byte_cost: Some(2),
2285            hash_sha3_256_legacy_min_input_len_cost: Some(1),
2286            type_name_get_base_cost: Some(52),
2287            type_name_get_per_byte_cost: Some(2),
2288            string_check_utf8_base_cost: Some(52),
2289            string_check_utf8_per_byte_cost: Some(2),
2290            string_is_char_boundary_base_cost: Some(52),
2291            string_sub_string_base_cost: Some(52),
2292            string_sub_string_per_byte_cost: Some(2),
2293            string_index_of_base_cost: Some(52),
2294            string_index_of_per_byte_pattern_cost: Some(2),
2295            string_index_of_per_byte_searched_cost: Some(2),
2296            vector_empty_base_cost: Some(52),
2297            vector_length_base_cost: Some(52),
2298            vector_push_back_base_cost: Some(52),
2299            vector_push_back_legacy_per_abstract_memory_unit_cost: Some(2),
2300            vector_borrow_base_cost: Some(52),
2301            vector_pop_back_base_cost: Some(52),
2302            vector_destroy_empty_base_cost: Some(52),
2303            vector_swap_base_cost: Some(52),
2304            debug_print_base_cost: Some(52),
2305            debug_print_stack_trace_base_cost: Some(52),
2306
2307            max_size_written_objects: Some(5 * 1000 * 1000),
2308            // max size of written objects during a system TXn to allow for larger writes
2309            // akin to `max_size_written_objects` but for system TXns
2310            max_size_written_objects_system_tx: Some(50 * 1000 * 1000),
2311
2312            // Limits the length of a Move identifier
2313            max_move_identifier_len: Some(128),
2314            max_move_value_depth: Some(128),
2315            max_move_enum_variants: None,
2316
2317            gas_rounding_step: Some(1_000),
2318
2319            execution_version: Some(1),
2320
2321            // We maintain the same total size limit for events, but increase the number of
2322            // events that can be emitted.
2323            max_event_emit_size_total: Some(
2324                256 /* former event count limit */ * 250 * 1024, // size limit per event
2325            ),
2326
2327            // Taking a baby step approach, we consider only 20% by stake as bad nodes so we
2328            // have a 80% by stake of nodes participating in the leader committee. That
2329            // allow us for more redundancy in case we have validators
2330            // under performing - since the responsibility is shared
2331            // amongst more nodes. We can increase that once we do have
2332            // higher confidence.
2333            consensus_bad_nodes_stake_threshold: Some(20),
2334
2335            // Max of 10 votes per hour.
2336            #[allow(deprecated)]
2337            max_jwk_votes_per_validator_per_epoch: Some(240),
2338
2339            #[allow(deprecated)]
2340            max_age_of_jwk_in_epochs: Some(1),
2341
2342            consensus_max_transaction_size_bytes: Some(256 * 1024), // 256KB
2343
2344            // Assume 1KB per transaction and 500 transactions per block.
2345            consensus_max_transactions_in_block_bytes: Some(512 * 1024),
2346
2347            random_beacon_reduction_allowed_delta: Some(800),
2348
2349            random_beacon_reduction_lower_bound: Some(1000),
2350            random_beacon_dkg_timeout_round: Some(3000),
2351            random_beacon_min_round_interval_ms: Some(500),
2352
2353            random_beacon_dkg_version: Some(1),
2354
2355            // Assume 20_000 TPS * 5% max stake per validator / (minimum) 4 blocks per round
2356            // = 250 transactions per block maximum Using a higher limit
2357            // that is 512, to account for bursty traffic and system transactions.
2358            consensus_max_num_transactions_in_block: Some(512),
2359
2360            max_deferral_rounds_for_congestion_control: Some(10),
2361
2362            min_checkpoint_interval_ms: Some(200),
2363
2364            checkpoint_summary_version_specific_data: Some(1),
2365
2366            max_soft_bundle_size: Some(5),
2367
2368            bridge_should_try_to_finalize_committee: None,
2369
2370            max_accumulated_txn_cost_per_object_in_mysticeti_commit: Some(10),
2371
2372            max_committee_members_count: None,
2373
2374            consensus_gc_depth: None,
2375
2376            consensus_max_acknowledgments_per_block: None,
2377
2378            max_congestion_limit_overshoot_per_commit: None,
2379
2380            scorer_version: None,
2381
2382            // `auth_context` module
2383            auth_context_digest_cost_base: None,
2384            auth_context_tx_data_bytes_cost_base: None,
2385            auth_context_tx_data_bytes_cost_per_byte: None,
2386            auth_context_tx_commands_cost_base: None,
2387            auth_context_tx_commands_cost_per_byte: None,
2388            auth_context_tx_inputs_cost_base: None,
2389            auth_context_tx_inputs_cost_per_byte: None,
2390            auth_context_replace_cost_base: None,
2391            auth_context_replace_cost_per_byte: None,
2392            auth_context_authenticator_function_info_v1_cost_base: None,
2393            // When adding a new constant, set it to None in the earliest version, like this:
2394            // new_constant: None,
2395        };
2396
2397        cfg.feature_flags.consensus_transaction_ordering = ConsensusTransactionOrdering::ByGasPrice;
2398
2399        // MoveVM related flags
2400        {
2401            cfg.feature_flags
2402                .disable_invariant_violation_check_in_swap_loc = true;
2403            cfg.feature_flags.no_extraneous_module_bytes = true;
2404            cfg.feature_flags.hardened_otw_check = true;
2405            cfg.feature_flags.rethrow_serialization_type_layout_errors = true;
2406        }
2407
2408        // zkLogin related flags
2409        {
2410            #[allow(deprecated)]
2411            {
2412                cfg.feature_flags.zklogin_max_epoch_upper_bound_delta = Some(30);
2413            }
2414        }
2415
2416        // Historical default: Mysticeti. Kept explicitly to match the
2417        // serialized form of pre-v14/v19/v24 configs. No runtime behavior
2418        // depends on this — Starfish is the only consensus protocol.
2419        #[expect(deprecated)]
2420        {
2421            cfg.feature_flags.consensus_choice = ConsensusChoice::MysticetiDeprecated;
2422        }
2423        // Use tonic networking for consensus.
2424        cfg.feature_flags.consensus_network = ConsensusNetwork::Tonic;
2425
2426        cfg.feature_flags.per_object_congestion_control_mode =
2427            PerObjectCongestionControlMode::TotalTxCount;
2428
2429        // Do not allow bridge committee to finalize on mainnet.
2430        cfg.bridge_should_try_to_finalize_committee = Some(chain != Chain::Mainnet);
2431
2432        // Devnet
2433        if chain != Chain::Mainnet && chain != Chain::Testnet {
2434            cfg.feature_flags.enable_poseidon = true;
2435            cfg.poseidon_bn254_cost_base = Some(260);
2436            cfg.poseidon_bn254_cost_per_block = Some(10);
2437
2438            cfg.feature_flags.enable_group_ops_native_function_msm = true;
2439
2440            cfg.feature_flags.enable_vdf = true;
2441            // Set to 30x and 2x the cost of a signature verification for now. This
2442            // should be updated along with other native crypto functions.
2443            cfg.vdf_verify_vdf_cost = Some(1500);
2444            cfg.vdf_hash_to_input_cost = Some(100);
2445
2446            cfg.feature_flags.passkey_auth = true;
2447        }
2448
2449        for cur in 2..=version.0 {
2450            match cur {
2451                1 => unreachable!(),
2452                // version 2 is a new framework version but with no config changes
2453                2 => {}
2454                3 => {
2455                    cfg.feature_flags.relocate_event_module = true;
2456                }
2457                4 => {
2458                    cfg.max_type_to_layout_nodes = Some(512);
2459                }
2460                5 => {
2461                    cfg.feature_flags.protocol_defined_base_fee = true;
2462                    cfg.base_gas_price = Some(1000);
2463
2464                    cfg.feature_flags.disallow_new_modules_in_deps_only_packages = true;
2465                    cfg.feature_flags.convert_type_argument_error = true;
2466                    cfg.feature_flags.native_charging_v2 = true;
2467
2468                    if chain != Chain::Mainnet && chain != Chain::Testnet {
2469                        cfg.feature_flags.uncompressed_g1_group_elements = true;
2470                    }
2471
2472                    cfg.gas_model_version = Some(2);
2473
2474                    cfg.poseidon_bn254_cost_per_block = Some(388);
2475
2476                    cfg.bls12381_bls12381_min_sig_verify_cost_base = Some(44064);
2477                    cfg.bls12381_bls12381_min_pk_verify_cost_base = Some(49282);
2478                    cfg.ecdsa_k1_secp256k1_verify_keccak256_cost_base = Some(1470);
2479                    cfg.ecdsa_k1_secp256k1_verify_sha256_cost_base = Some(1470);
2480                    cfg.ecdsa_r1_secp256r1_verify_sha256_cost_base = Some(4225);
2481                    cfg.ecdsa_r1_secp256r1_verify_keccak256_cost_base = Some(4225);
2482                    cfg.ecvrf_ecvrf_verify_cost_base = Some(4848);
2483                    cfg.ed25519_ed25519_verify_cost_base = Some(1802);
2484
2485                    // Manually changed to be "under cost"
2486                    cfg.ecdsa_r1_ecrecover_keccak256_cost_base = Some(1173);
2487                    cfg.ecdsa_r1_ecrecover_sha256_cost_base = Some(1173);
2488                    cfg.ecdsa_k1_ecrecover_keccak256_cost_base = Some(500);
2489                    cfg.ecdsa_k1_ecrecover_sha256_cost_base = Some(500);
2490
2491                    cfg.groth16_prepare_verifying_key_bls12381_cost_base = Some(53838);
2492                    cfg.groth16_prepare_verifying_key_bn254_cost_base = Some(82010);
2493                    cfg.groth16_verify_groth16_proof_internal_bls12381_cost_base = Some(72090);
2494                    cfg.groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input =
2495                        Some(8213);
2496                    cfg.groth16_verify_groth16_proof_internal_bn254_cost_base = Some(115502);
2497                    cfg.groth16_verify_groth16_proof_internal_bn254_cost_per_public_input =
2498                        Some(9484);
2499
2500                    cfg.hash_keccak256_cost_base = Some(10);
2501                    cfg.hash_blake2b256_cost_base = Some(10);
2502
2503                    // group ops
2504                    cfg.group_ops_bls12381_decode_scalar_cost = Some(7);
2505                    cfg.group_ops_bls12381_decode_g1_cost = Some(2848);
2506                    cfg.group_ops_bls12381_decode_g2_cost = Some(3770);
2507                    cfg.group_ops_bls12381_decode_gt_cost = Some(3068);
2508
2509                    cfg.group_ops_bls12381_scalar_add_cost = Some(10);
2510                    cfg.group_ops_bls12381_g1_add_cost = Some(1556);
2511                    cfg.group_ops_bls12381_g2_add_cost = Some(3048);
2512                    cfg.group_ops_bls12381_gt_add_cost = Some(188);
2513
2514                    cfg.group_ops_bls12381_scalar_sub_cost = Some(10);
2515                    cfg.group_ops_bls12381_g1_sub_cost = Some(1550);
2516                    cfg.group_ops_bls12381_g2_sub_cost = Some(3019);
2517                    cfg.group_ops_bls12381_gt_sub_cost = Some(497);
2518
2519                    cfg.group_ops_bls12381_scalar_mul_cost = Some(11);
2520                    cfg.group_ops_bls12381_g1_mul_cost = Some(4842);
2521                    cfg.group_ops_bls12381_g2_mul_cost = Some(9108);
2522                    cfg.group_ops_bls12381_gt_mul_cost = Some(27490);
2523
2524                    cfg.group_ops_bls12381_scalar_div_cost = Some(91);
2525                    cfg.group_ops_bls12381_g1_div_cost = Some(5091);
2526                    cfg.group_ops_bls12381_g2_div_cost = Some(9206);
2527                    cfg.group_ops_bls12381_gt_div_cost = Some(27804);
2528
2529                    cfg.group_ops_bls12381_g1_hash_to_base_cost = Some(2962);
2530                    cfg.group_ops_bls12381_g2_hash_to_base_cost = Some(8688);
2531
2532                    cfg.group_ops_bls12381_g1_msm_base_cost = Some(62648);
2533                    cfg.group_ops_bls12381_g2_msm_base_cost = Some(131192);
2534                    cfg.group_ops_bls12381_g1_msm_base_cost_per_input = Some(1333);
2535                    cfg.group_ops_bls12381_g2_msm_base_cost_per_input = Some(3216);
2536
2537                    cfg.group_ops_bls12381_uncompressed_g1_to_g1_cost = Some(677);
2538                    cfg.group_ops_bls12381_g1_to_uncompressed_g1_cost = Some(2099);
2539                    cfg.group_ops_bls12381_uncompressed_g1_sum_base_cost = Some(77);
2540                    cfg.group_ops_bls12381_uncompressed_g1_sum_cost_per_term = Some(26);
2541                    cfg.group_ops_bls12381_uncompressed_g1_sum_max_terms = Some(1200);
2542
2543                    cfg.group_ops_bls12381_pairing_cost = Some(26897);
2544
2545                    cfg.validator_validate_metadata_cost_base = Some(20000);
2546
2547                    cfg.max_committee_members_count = Some(50);
2548                }
2549                6 => {
2550                    cfg.max_ptb_value_size = Some(1024 * 1024);
2551                }
2552                7 => {
2553                    // version 7 is a new framework version but with no config
2554                    // changes
2555                }
2556                8 => {
2557                    cfg.feature_flags.variant_nodes = true;
2558
2559                    if chain != Chain::Mainnet {
2560                        // Enable round prober in consensus.
2561                        cfg.feature_flags.consensus_round_prober = true;
2562                        // Enable distributed vote scoring.
2563                        cfg.feature_flags
2564                            .consensus_distributed_vote_scoring_strategy = true;
2565                        cfg.feature_flags.consensus_linearize_subdag_v2 = true;
2566                        // Enable smart ancestor selection for testnet
2567                        cfg.feature_flags.consensus_smart_ancestor_selection = true;
2568                        // Enable probing for accepted rounds in round prober for testnet
2569                        cfg.feature_flags
2570                            .consensus_round_prober_probe_accepted_rounds = true;
2571                        // Enable zstd compression for consensus in testnet
2572                        cfg.feature_flags.consensus_zstd_compression = true;
2573                        // Assuming a round rate of max 15/sec, then using a gc depth of 60 allow
2574                        // blocks within a window of ~4 seconds
2575                        // to be included before be considered garbage collected.
2576                        cfg.consensus_gc_depth = Some(60);
2577                    }
2578
2579                    // Enable min_free_execution_slot for the shared object congestion tracker in
2580                    // devnet.
2581                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2582                        cfg.feature_flags.congestion_control_min_free_execution_slot = true;
2583                    }
2584                }
2585                9 => {
2586                    if chain != Chain::Mainnet {
2587                        // Disable smart ancestor selection in the testnet and devnet.
2588                        cfg.feature_flags.consensus_smart_ancestor_selection = false;
2589                    }
2590
2591                    // Enable zstd compression for consensus
2592                    cfg.feature_flags.consensus_zstd_compression = true;
2593
2594                    // Enable passkey in multisig in devnet.
2595                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2596                        cfg.feature_flags.accept_passkey_in_multisig = true;
2597                    }
2598
2599                    // this flag is now deprecated because of the bridge removal.
2600                    cfg.bridge_should_try_to_finalize_committee = None;
2601                }
2602                10 => {
2603                    // Enable min_free_execution_slot for the shared object congestion tracker in
2604                    // all networks.
2605                    cfg.feature_flags.congestion_control_min_free_execution_slot = true;
2606
2607                    // Increase the committee size to 80 on all networks.
2608                    cfg.max_committee_members_count = Some(80);
2609
2610                    // Enable round prober in consensus.
2611                    cfg.feature_flags.consensus_round_prober = true;
2612                    // Enable probing for accepted rounds in round.
2613                    cfg.feature_flags
2614                        .consensus_round_prober_probe_accepted_rounds = true;
2615                    // Enable distributed vote scoring.
2616                    cfg.feature_flags
2617                        .consensus_distributed_vote_scoring_strategy = true;
2618                    // Enable the new consensus commit rule.
2619                    cfg.feature_flags.consensus_linearize_subdag_v2 = true;
2620
2621                    // Enable consensus garbage collection
2622                    // Assuming a round rate of max 15/sec, then using a gc depth of 60 allow
2623                    // blocks within a window of ~4 seconds
2624                    // to be included before be considered garbage collected.
2625                    cfg.consensus_gc_depth = Some(60);
2626
2627                    // Enable minimized child object mutation counting.
2628                    cfg.feature_flags.minimize_child_object_mutations = true;
2629
2630                    if chain != Chain::Mainnet {
2631                        // Enable batched block sync in devnet and testnet.
2632                        cfg.feature_flags.consensus_batched_block_sync = true;
2633                    }
2634
2635                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2636                        // Enable the gas price feedback mechanism (which is used for
2637                        // transactions cancelled due to shared object congestion) in devnet
2638                        cfg.feature_flags
2639                            .congestion_control_gas_price_feedback_mechanism = true;
2640                    }
2641
2642                    cfg.feature_flags.validate_identifier_inputs = true;
2643                    cfg.feature_flags.dependency_linkage_error = true;
2644                    cfg.feature_flags.additional_multisig_checks = true;
2645                }
2646                11 => {
2647                    // version 11 is a new framework version but with no config
2648                    // changes
2649                }
2650                12 => {
2651                    // Enable the gas price feedback mechanism for transactions
2652                    // cancelled due to congestion in all networks
2653                    cfg.feature_flags
2654                        .congestion_control_gas_price_feedback_mechanism = true;
2655
2656                    // Enable normalization of PTB arguments in all networks.
2657                    cfg.feature_flags.normalize_ptb_arguments = true;
2658                }
2659                13 => {
2660                    // Enable selecting committee based on eligible active validators on all
2661                    // networks.
2662                    cfg.feature_flags.select_committee_from_eligible_validators = true;
2663                    // Enable tracking non-committee eligible active
2664                    // validators on all networks.
2665                    cfg.feature_flags.track_non_committee_eligible_validators = true;
2666
2667                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2668                        // Enable selecting committee only from active validators that next epoch
2669                        // version and issued valid AuthorityCapabilities notification in devnet.
2670                        cfg.feature_flags
2671                            .select_committee_supporting_next_epoch_version = true;
2672                    }
2673                }
2674                14 => {
2675                    // Enable batched block sync for mainnet.
2676                    cfg.feature_flags.consensus_batched_block_sync = true;
2677
2678                    if chain != Chain::Mainnet {
2679                        // Enable median-based commit timestamp calculation in consensus and
2680                        // enforce checkpoint timestamp monotonicity for testnet.
2681                        cfg.feature_flags
2682                            .consensus_median_timestamp_with_checkpoint_enforcement = true;
2683                        // Enable selecting committee only from active validators that support the
2684                        // next epoch's version and issued valid AuthorityCapabilities notification
2685                        // in testnet.
2686                        cfg.feature_flags
2687                            .select_committee_supporting_next_epoch_version = true;
2688                    }
2689                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2690                        // Switch consensus protocol to Starfish in devnet
2691                        cfg.feature_flags.consensus_choice = ConsensusChoice::Starfish;
2692                    }
2693                }
2694                15 => {
2695                    if chain != Chain::Mainnet && chain != Chain::Testnet {
2696                        // Enable overshoot of 100 in congestion control. This allows bursts of
2697                        // shared object transactions up to 10 times the average allowable
2698                        // load set by `max_accumulated_txn_cost_per_object_in_mysticeti_commit`.
2699                        cfg.max_congestion_limit_overshoot_per_commit = Some(100);
2700                    }
2701                }
2702                16 => {
2703                    // Enable selecting committee only from active validators that support the
2704                    // next epoch's version and issued valid AuthorityCapabilities notification.
2705                    cfg.feature_flags
2706                        .select_committee_supporting_next_epoch_version = true;
2707                    // Enable committing transactions only for traversed headers in Starfish
2708                    cfg.feature_flags
2709                        .consensus_commit_transactions_only_for_traversed_headers = true;
2710                }
2711                17 => {
2712                    // Increase the committee size to 100 on all networks.
2713                    cfg.max_committee_members_count = Some(100);
2714                }
2715                18 => {
2716                    if chain != Chain::Mainnet {
2717                        // Enable passkey authentication support in testnet.
2718                        cfg.feature_flags.passkey_auth = true;
2719                    }
2720                }
2721                19 => {
2722                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2723                        // Enable congestion limit overshoot in the gas price feedback
2724                        // mechanism on devnet.
2725                        cfg.feature_flags
2726                            .congestion_limit_overshoot_in_gas_price_feedback_mechanism = true;
2727                        // Enable a separate gas price feedback mechanism for transactions using
2728                        // randomness on devnet.
2729                        cfg.feature_flags
2730                            .separate_gas_price_feedback_mechanism_for_randomness = true;
2731                        // Enable storing metadata in module bytes and then
2732                        // publishing package metadata in devnet
2733                        cfg.feature_flags.metadata_in_module_bytes = true;
2734                        cfg.feature_flags.publish_package_metadata = true;
2735                        // Enable Move authentication in devnet
2736                        cfg.feature_flags.enable_move_authentication = true;
2737                        // Max auth gas budget is in NANOS and an absolute value 0.25 IOTA
2738                        cfg.max_auth_gas = Some(250_000_000);
2739                        // Increase the base cost for transfer receive object in devnet, since the
2740                        // implementation now does check if parent is not an account.
2741                        cfg.transfer_receive_object_cost_base = Some(100);
2742                        // Enable adjustment of validator rewards based on score in devnet.
2743                        cfg.feature_flags.adjust_rewards_by_score = true;
2744                    }
2745
2746                    if chain != Chain::Mainnet {
2747                        // Switch consensus protocol to Starfish in testnet.
2748                        cfg.feature_flags.consensus_choice = ConsensusChoice::Starfish;
2749
2750                        // Enable validator score calculation on testnet
2751                        cfg.feature_flags.calculate_validator_scores = true;
2752                        cfg.scorer_version = Some(1);
2753                    }
2754
2755                    // Change epoch transaction will contain validator scores
2756                    cfg.feature_flags.pass_validator_scores_to_advance_epoch = true;
2757
2758                    // Enable passkey authentication support in mainnet
2759                    cfg.feature_flags.passkey_auth = true;
2760                }
2761                20 => {
2762                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2763                        // Passes the calculated validator scores to advance epoch only on Devnet
2764                        cfg.feature_flags
2765                            .pass_calculated_validator_scores_to_advance_epoch = true;
2766                    }
2767                }
2768                21 => {
2769                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2770                        // Enable fast commit syncer for faster recovery in devnet.
2771                        cfg.feature_flags.consensus_fast_commit_sync = true;
2772                    }
2773                    if chain != Chain::Mainnet {
2774                        // Enable overshoot of 100 in congestion control on testnet.
2775                        // This allows bursts of shared-object transactions
2776                        // up to 10 times the average allowable load set by
2777                        // `max_accumulated_txn_cost_per_object_in_mysticeti_commit`.
2778                        cfg.max_congestion_limit_overshoot_per_commit = Some(100);
2779                        // Enable congestion limit overshoot in the gas price feedback
2780                        // mechanism on testnet.
2781                        cfg.feature_flags
2782                            .congestion_limit_overshoot_in_gas_price_feedback_mechanism = true;
2783                        // Enable a separate gas price feedback mechanism for transactions using
2784                        // randomness on testnet.
2785                        cfg.feature_flags
2786                            .separate_gas_price_feedback_mechanism_for_randomness = true;
2787                    }
2788
2789                    cfg.auth_context_digest_cost_base = Some(30);
2790                    cfg.auth_context_tx_commands_cost_base = Some(30);
2791                    cfg.auth_context_tx_commands_cost_per_byte = Some(2);
2792                    cfg.auth_context_tx_inputs_cost_base = Some(30);
2793                    cfg.auth_context_tx_inputs_cost_per_byte = Some(2);
2794                    cfg.auth_context_replace_cost_base = Some(30);
2795                    cfg.auth_context_replace_cost_per_byte = Some(2);
2796
2797                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2798                        // Decrease max_auth_gas to 0.00025 IOTA
2799                        cfg.max_auth_gas = Some(250_000);
2800                    }
2801                }
2802                22 => {
2803                    // Enable overshoot of 100 in congestion control on all networks.
2804                    // This allows bursts of shared-object transactions
2805                    // up to 10 times the average allowable load set by
2806                    // `max_accumulated_txn_cost_per_object_in_mysticeti_commit`.
2807                    cfg.max_congestion_limit_overshoot_per_commit = Some(100);
2808                    // Enable congestion limit overshoot in the gas price feedback
2809                    // mechanism on all networks.
2810                    cfg.feature_flags
2811                        .congestion_limit_overshoot_in_gas_price_feedback_mechanism = true;
2812                    // Enable a separate gas price feedback mechanism for transactions using
2813                    // randomness on all networks.
2814                    cfg.feature_flags
2815                        .separate_gas_price_feedback_mechanism_for_randomness = true;
2816
2817                    if chain != Chain::Mainnet {
2818                        // Enable storing metadata in module bytes and then
2819                        // publishing package metadata in testnet
2820                        cfg.feature_flags.metadata_in_module_bytes = true;
2821                        cfg.feature_flags.publish_package_metadata = true;
2822                        // Enable Move authentication in testnet
2823                        cfg.feature_flags.enable_move_authentication = true;
2824                        // Max_auth_gas is 0.00025 IOTA
2825                        cfg.max_auth_gas = Some(250_000);
2826                        // Increase the base cost for transfer receive object in testnet, since the
2827                        // implementation now does check if parent is not an account.
2828                        cfg.transfer_receive_object_cost_base = Some(100);
2829                    }
2830
2831                    if chain != Chain::Mainnet {
2832                        // Enable fast commit syncer for faster recovery on testnet.
2833                        cfg.feature_flags.consensus_fast_commit_sync = true;
2834                    }
2835                }
2836                23 => {
2837                    // Enable Move native context (TxContext via native functions) in all networks.
2838                    cfg.feature_flags.move_native_tx_context = true;
2839                    cfg.tx_context_fresh_id_cost_base = Some(52);
2840                    cfg.tx_context_sender_cost_base = Some(30);
2841                    cfg.tx_context_digest_cost_base = Some(30);
2842                    cfg.tx_context_epoch_cost_base = Some(30);
2843                    cfg.tx_context_epoch_timestamp_ms_cost_base = Some(30);
2844                    cfg.tx_context_sponsor_cost_base = Some(30);
2845                    cfg.tx_context_rgp_cost_base = Some(30);
2846                    cfg.tx_context_gas_price_cost_base = Some(30);
2847                    cfg.tx_context_gas_budget_cost_base = Some(30);
2848                    cfg.tx_context_ids_created_cost_base = Some(30);
2849                    cfg.tx_context_replace_cost_base = Some(30);
2850                }
2851                24 => {
2852                    // Switch consensus protocol to Starfish in all networks.
2853                    cfg.feature_flags.consensus_choice = ConsensusChoice::Starfish;
2854
2855                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2856                        // Enable Move-based sponsor account authentication in devnet.
2857                        cfg.feature_flags.enable_move_authentication_for_sponsor = true;
2858                    }
2859
2860                    // Add tx_data_bytes to AuthContext for intent-based signature
2861                    // verification in account abstraction.
2862                    cfg.auth_context_tx_data_bytes_cost_base = Some(30);
2863                    cfg.auth_context_tx_data_bytes_cost_per_byte = Some(2);
2864
2865                    // Enable additional borrow checks.
2866                    cfg.feature_flags.additional_borrow_checks = true;
2867                }
2868                #[allow(deprecated)]
2869                25 => {
2870                    // Deprecate zkLogin related parameters since zkLogin is deprecated and was
2871                    // never enabled on IOTA.
2872                    cfg.feature_flags.zklogin_max_epoch_upper_bound_delta = None;
2873                    cfg.check_zklogin_id_cost_base = None;
2874                    cfg.check_zklogin_issuer_cost_base = None;
2875                    cfg.max_jwk_votes_per_validator_per_epoch = None;
2876                    cfg.max_age_of_jwk_in_epochs = None;
2877                }
2878                26 => {
2879                    // Introduce a module to allow Move code to query protocol
2880                    // feature flags at runtime.
2881                }
2882                27 => {
2883                    if chain != Chain::Mainnet {
2884                        // Enable consensus block restrictions on testnet/devnet to bound
2885                        // header size by committee size.
2886                        cfg.feature_flags.consensus_block_restrictions = true;
2887                    }
2888
2889                    if chain != Chain::Testnet && chain != Chain::Mainnet {
2890                        // Only sponsor Move authentication is performed pre-consensus in devnet.
2891                        cfg.feature_flags
2892                            .pre_consensus_sponsor_only_move_authentication = true;
2893                    }
2894                }
2895                28 => {
2896                    // AuthenticatorFunctionInfoV1 max BCS size:
2897                    // package (32) + module_name (128) + function_name (128) = 288 bytes = 9 ×
2898                    // digest. auth_context_digest_cost_base = 30 for 32 bytes →
2899                    // 9 × 30 = 270.
2900                    cfg.auth_context_authenticator_function_info_v1_cost_base = Some(270);
2901
2902                    // Enable storing metadata in module bytes and then
2903                    // publishing package metadata in mainnet.
2904                    cfg.feature_flags.metadata_in_module_bytes = true;
2905                    cfg.feature_flags.publish_package_metadata = true;
2906                    // Enable Move authentication in mainnet.
2907                    cfg.feature_flags.enable_move_authentication = true;
2908                    // Increase the base cost for transfer receive object in mainnet, since the
2909                    // implementation now does check if parent is not an account.
2910                    cfg.transfer_receive_object_cost_base = Some(100);
2911
2912                    if chain != Chain::Unknown {
2913                        // max_auth_gas is 0.00002 IOTA in testnet and mainnet.
2914                        cfg.max_auth_gas = Some(20_000);
2915                    }
2916
2917                    if chain != Chain::Mainnet {
2918                        // Enable Move-based sponsor account authentication in testnet.
2919                        cfg.feature_flags.enable_move_authentication_for_sponsor = true;
2920                        // Only sponsor Move authentication is performed pre-consensus in testnet.
2921                        cfg.feature_flags
2922                            .pre_consensus_sponsor_only_move_authentication = true;
2923                    }
2924                }
2925                29 => {
2926                    // Keep advancing the random beacon DKG state machine on every commit
2927                    // while it is still pending so DKG resolves from persisted state
2928                    // (completing, or failing once the timeout round passes) even with no
2929                    // fresh inbound traffic -- e.g. after a validator restart -- instead of
2930                    // staying pending forever and blocking epoch close.
2931                    cfg.feature_flags.always_advance_dkg_to_resolution = true;
2932
2933                    // Enable median-based commit timestamp calculation in consensus and
2934                    // enforce checkpoint timestamp monotonicity for mainnet.
2935                    cfg.feature_flags
2936                        .consensus_median_timestamp_with_checkpoint_enforcement = true;
2937
2938                    // Enable fast commit syncer for faster recovery on all networks.
2939                    cfg.feature_flags.consensus_fast_commit_sync = true;
2940                    // Enable consensus block restrictions on all networks to bound
2941                    // header size by committee size and garbage-collect the block
2942                    // manager.
2943                    cfg.feature_flags.consensus_block_restrictions = true;
2944                }
2945                // Use this template when making changes:
2946                //
2947                //     // modify an existing constant.
2948                //     move_binary_format_version: Some(7),
2949                //
2950                //     // Add a new constant (which is set to None in prior versions).
2951                //     new_constant: Some(new_value),
2952                //
2953                //     // Remove a constant (ensure that it is never accessed during this version).
2954                //     max_move_object_size: None,
2955                _ => panic!("unsupported version {version:?}"),
2956            }
2957        }
2958        cfg
2959    }
2960
2961    // Extract the bytecode verifier config from this protocol config.
2962    // If used during signing, `signing_limits` should be set.
2963    // The third limit configures`sanity_check_with_regex_reference_safety`,
2964    // which runs the new regex-based reference safety check to check that it is
2965    // strictly more permissive than the current implementation.
2966    pub fn verifier_config(&self, signing_limits: Option<(usize, usize, usize)>) -> VerifierConfig {
2967        let (
2968            max_back_edges_per_function,
2969            max_back_edges_per_module,
2970            sanity_check_with_regex_reference_safety,
2971        ) = if let Some((
2972            max_back_edges_per_function,
2973            max_back_edges_per_module,
2974            sanity_check_with_regex_reference_safety,
2975        )) = signing_limits
2976        {
2977            (
2978                Some(max_back_edges_per_function),
2979                Some(max_back_edges_per_module),
2980                Some(sanity_check_with_regex_reference_safety),
2981            )
2982        } else {
2983            (None, None, None)
2984        };
2985
2986        let additional_borrow_checks = if signing_limits.is_some() {
2987            // Always apply additional borrow checks during signing regardless of
2988            // protocol version, to prevent accepting potentially unsafe bytecode.
2989            true
2990        } else {
2991            self.additional_borrow_checks()
2992        };
2993
2994        VerifierConfig {
2995            max_loop_depth: Some(self.max_loop_depth() as usize),
2996            max_generic_instantiation_length: Some(self.max_generic_instantiation_length() as usize),
2997            max_function_parameters: Some(self.max_function_parameters() as usize),
2998            max_basic_blocks: Some(self.max_basic_blocks() as usize),
2999            max_value_stack_size: self.max_value_stack_size() as usize,
3000            max_type_nodes: Some(self.max_type_nodes() as usize),
3001            max_push_size: Some(self.max_push_size() as usize),
3002            max_dependency_depth: Some(self.max_dependency_depth() as usize),
3003            max_fields_in_struct: Some(self.max_fields_in_struct() as usize),
3004            max_function_definitions: Some(self.max_function_definitions() as usize),
3005            max_data_definitions: Some(self.max_struct_definitions() as usize),
3006            max_constant_vector_len: Some(self.max_move_vector_len()),
3007            max_back_edges_per_function,
3008            max_back_edges_per_module,
3009            max_basic_blocks_in_script: None,
3010            max_identifier_len: self.max_move_identifier_len_as_option(), /* Before protocol
3011                                                                           * version 9, there was
3012                                                                           * no limit */
3013            bytecode_version: self.move_binary_format_version(),
3014            max_variants_in_enum: self.max_move_enum_variants_as_option(),
3015            additional_borrow_checks,
3016            sanity_check_with_regex_reference_safety: sanity_check_with_regex_reference_safety
3017                .map(|limit| limit as u128),
3018        }
3019    }
3020
3021    /// Override one or more settings in the config, for testing.
3022    /// This must be called at the beginning of the test, before
3023    /// get_for_(min|max)_version is called, since those functions cache
3024    /// their return value.
3025    pub fn apply_overrides_for_testing(
3026        override_fn: impl Fn(ProtocolVersion, Self) -> Self + Send + Sync + 'static,
3027    ) -> OverrideGuard {
3028        CONFIG_OVERRIDE.with(|ovr| {
3029            let mut cur = ovr.borrow_mut();
3030            assert!(cur.is_none(), "config override already present");
3031            *cur = Some(Box::new(override_fn));
3032            OverrideGuard
3033        })
3034    }
3035}
3036
3037// Setters for tests.
3038// This is only needed for feature_flags. Please suffix each setter with
3039// `_for_testing`. Non-feature_flags should already have test setters defined
3040// through macros.
3041impl ProtocolConfig {
3042    pub fn set_per_object_congestion_control_mode_for_testing(
3043        &mut self,
3044        val: PerObjectCongestionControlMode,
3045    ) {
3046        self.feature_flags.per_object_congestion_control_mode = val;
3047    }
3048
3049    pub fn set_consensus_choice_for_testing(&mut self, val: ConsensusChoice) {
3050        self.feature_flags.consensus_choice = val;
3051    }
3052
3053    pub fn set_consensus_network_for_testing(&mut self, val: ConsensusNetwork) {
3054        self.feature_flags.consensus_network = val;
3055    }
3056
3057    pub fn set_passkey_auth_for_testing(&mut self, val: bool) {
3058        self.feature_flags.passkey_auth = val
3059    }
3060
3061    pub fn set_disallow_new_modules_in_deps_only_packages_for_testing(&mut self, val: bool) {
3062        self.feature_flags
3063            .disallow_new_modules_in_deps_only_packages = val;
3064    }
3065
3066    pub fn set_consensus_round_prober_for_testing(&mut self, val: bool) {
3067        self.feature_flags.consensus_round_prober = val;
3068    }
3069
3070    pub fn set_consensus_distributed_vote_scoring_strategy_for_testing(&mut self, val: bool) {
3071        self.feature_flags
3072            .consensus_distributed_vote_scoring_strategy = val;
3073    }
3074
3075    pub fn set_gc_depth_for_testing(&mut self, val: u32) {
3076        self.consensus_gc_depth = Some(val);
3077    }
3078
3079    pub fn set_consensus_linearize_subdag_v2_for_testing(&mut self, val: bool) {
3080        self.feature_flags.consensus_linearize_subdag_v2 = val;
3081    }
3082
3083    pub fn set_consensus_round_prober_probe_accepted_rounds(&mut self, val: bool) {
3084        self.feature_flags
3085            .consensus_round_prober_probe_accepted_rounds = val;
3086    }
3087
3088    pub fn set_accept_passkey_in_multisig_for_testing(&mut self, val: bool) {
3089        self.feature_flags.accept_passkey_in_multisig = val;
3090    }
3091
3092    pub fn set_consensus_smart_ancestor_selection_for_testing(&mut self, val: bool) {
3093        self.feature_flags.consensus_smart_ancestor_selection = val;
3094    }
3095
3096    pub fn set_consensus_batched_block_sync_for_testing(&mut self, val: bool) {
3097        self.feature_flags.consensus_batched_block_sync = val;
3098    }
3099
3100    pub fn set_congestion_control_min_free_execution_slot_for_testing(&mut self, val: bool) {
3101        self.feature_flags
3102            .congestion_control_min_free_execution_slot = val;
3103    }
3104
3105    pub fn set_congestion_control_gas_price_feedback_mechanism_for_testing(&mut self, val: bool) {
3106        self.feature_flags
3107            .congestion_control_gas_price_feedback_mechanism = val;
3108    }
3109
3110    pub fn set_select_committee_from_eligible_validators_for_testing(&mut self, val: bool) {
3111        self.feature_flags.select_committee_from_eligible_validators = val;
3112    }
3113
3114    pub fn set_track_non_committee_eligible_validators_for_testing(&mut self, val: bool) {
3115        self.feature_flags.track_non_committee_eligible_validators = val;
3116    }
3117
3118    pub fn set_select_committee_supporting_next_epoch_version(&mut self, val: bool) {
3119        self.feature_flags
3120            .select_committee_supporting_next_epoch_version = val;
3121    }
3122
3123    pub fn set_consensus_median_timestamp_with_checkpoint_enforcement_for_testing(
3124        &mut self,
3125        val: bool,
3126    ) {
3127        self.feature_flags
3128            .consensus_median_timestamp_with_checkpoint_enforcement = val;
3129    }
3130
3131    pub fn set_consensus_commit_transactions_only_for_traversed_headers_for_testing(
3132        &mut self,
3133        val: bool,
3134    ) {
3135        self.feature_flags
3136            .consensus_commit_transactions_only_for_traversed_headers = val;
3137    }
3138
3139    pub fn set_congestion_limit_overshoot_in_gas_price_feedback_mechanism_for_testing(
3140        &mut self,
3141        val: bool,
3142    ) {
3143        self.feature_flags
3144            .congestion_limit_overshoot_in_gas_price_feedback_mechanism = val;
3145    }
3146
3147    pub fn set_separate_gas_price_feedback_mechanism_for_randomness_for_testing(
3148        &mut self,
3149        val: bool,
3150    ) {
3151        self.feature_flags
3152            .separate_gas_price_feedback_mechanism_for_randomness = val;
3153    }
3154
3155    pub fn set_metadata_in_module_bytes_for_testing(&mut self, val: bool) {
3156        self.feature_flags.metadata_in_module_bytes = val;
3157    }
3158
3159    pub fn set_publish_package_metadata_for_testing(&mut self, val: bool) {
3160        self.feature_flags.publish_package_metadata = val;
3161    }
3162
3163    pub fn set_enable_move_authentication_for_testing(&mut self, val: bool) {
3164        self.feature_flags.enable_move_authentication = val;
3165    }
3166
3167    pub fn set_enable_move_authentication_for_sponsor_for_testing(&mut self, val: bool) {
3168        self.feature_flags.enable_move_authentication_for_sponsor = val;
3169    }
3170
3171    pub fn set_consensus_fast_commit_sync_for_testing(&mut self, val: bool) {
3172        self.feature_flags.consensus_fast_commit_sync = val;
3173    }
3174
3175    pub fn set_consensus_block_restrictions_for_testing(&mut self, val: bool) {
3176        self.feature_flags.consensus_block_restrictions = val;
3177    }
3178
3179    pub fn set_pre_consensus_sponsor_only_move_authentication_for_testing(&mut self, val: bool) {
3180        self.feature_flags
3181            .pre_consensus_sponsor_only_move_authentication = val;
3182    }
3183
3184    pub fn set_consensus_starfish_speed_for_testing(&mut self, val: bool) {
3185        self.feature_flags.consensus_starfish_speed = val;
3186    }
3187
3188    pub fn set_always_advance_dkg_to_resolution_for_testing(&mut self, val: bool) {
3189        self.feature_flags.always_advance_dkg_to_resolution = val;
3190    }
3191
3192    pub fn set_enable_pcool_flow_for_testing(&mut self, val: bool) {
3193        self.feature_flags.enable_pcool_flow = val;
3194    }
3195}
3196
3197type OverrideFn = dyn Fn(ProtocolVersion, ProtocolConfig) -> ProtocolConfig + Send + Sync;
3198
3199thread_local! {
3200    static CONFIG_OVERRIDE: RefCell<Option<Box<OverrideFn>>> = const { RefCell::new(None) };
3201}
3202
3203#[must_use]
3204pub struct OverrideGuard;
3205
3206impl Drop for OverrideGuard {
3207    fn drop(&mut self) {
3208        info!("restoring override fn");
3209        CONFIG_OVERRIDE.with(|ovr| {
3210            *ovr.borrow_mut() = None;
3211        });
3212    }
3213}
3214
3215/// Defines which limit got crossed.
3216/// The value which crossed the limit and value of the limit crossed are
3217/// embedded
3218#[derive(PartialEq, Eq)]
3219pub enum LimitThresholdCrossed {
3220    None,
3221    Soft(u128, u128),
3222    Hard(u128, u128),
3223}
3224
3225/// Convenience function for comparing limit ranges
3226/// V::MAX must be at >= U::MAX and T::MAX
3227pub fn check_limit_in_range<T: Into<V>, U: Into<V>, V: PartialOrd + Into<u128>>(
3228    x: T,
3229    soft_limit: U,
3230    hard_limit: V,
3231) -> LimitThresholdCrossed {
3232    let x: V = x.into();
3233    let soft_limit: V = soft_limit.into();
3234
3235    debug_assert!(soft_limit <= hard_limit);
3236
3237    // It is important to preserve this comparison order because if soft_limit ==
3238    // hard_limit we want LimitThresholdCrossed::Hard
3239    if x >= hard_limit {
3240        LimitThresholdCrossed::Hard(x.into(), hard_limit.into())
3241    } else if x < soft_limit {
3242        LimitThresholdCrossed::None
3243    } else {
3244        LimitThresholdCrossed::Soft(x.into(), soft_limit.into())
3245    }
3246}
3247
3248#[macro_export]
3249macro_rules! check_limit {
3250    ($x:expr, $hard:expr) => {
3251        check_limit!($x, $hard, $hard)
3252    };
3253    ($x:expr, $soft:expr, $hard:expr) => {
3254        check_limit_in_range($x as u64, $soft, $hard)
3255    };
3256}
3257
3258/// Used to check which limits were crossed if the TX is metered (not system tx)
3259/// Args are: is_metered, value_to_check, metered_limit, unmetered_limit
3260/// metered_limit is always less than or equal to unmetered_hard_limit
3261#[macro_export]
3262macro_rules! check_limit_by_meter {
3263    ($is_metered:expr, $x:expr, $metered_limit:expr, $unmetered_hard_limit:expr, $metric:expr) => {{
3264        // If this is metered, we use the metered_limit limit as the upper bound
3265        let (h, metered_str) = if $is_metered {
3266            ($metered_limit, "metered")
3267        } else {
3268            // Unmetered gets more headroom
3269            ($unmetered_hard_limit, "unmetered")
3270        };
3271        use iota_protocol_config::check_limit_in_range;
3272        let result = check_limit_in_range($x as u64, $metered_limit, h);
3273        match result {
3274            LimitThresholdCrossed::None => {}
3275            LimitThresholdCrossed::Soft(_, _) => {
3276                $metric.with_label_values(&[metered_str, "soft"]).inc();
3277            }
3278            LimitThresholdCrossed::Hard(_, _) => {
3279                $metric.with_label_values(&[metered_str, "hard"]).inc();
3280            }
3281        };
3282        result
3283    }};
3284}
3285
3286#[cfg(all(test, not(msim)))]
3287mod test {
3288    use insta::assert_yaml_snapshot;
3289
3290    use super::*;
3291
3292    #[test]
3293    fn snapshot_tests() {
3294        println!("\n============================================================================");
3295        println!("!                                                                          !");
3296        println!("! IMPORTANT: never update snapshots from this test. only add new versions! !");
3297        println!("!                                                                          !");
3298        println!("============================================================================\n");
3299        for chain_id in &[Chain::Unknown, Chain::Mainnet, Chain::Testnet] {
3300            // make Chain::Unknown snapshots compatible with pre-chain-id snapshots so that
3301            // we don't break the release-time compatibility tests. Once Chain
3302            // Id configs have been released everywhere, we can remove this and
3303            // only test Mainnet and Testnet
3304            let chain_str = match chain_id {
3305                Chain::Unknown => "".to_string(),
3306                _ => format!("{chain_id:?}_"),
3307            };
3308            for i in MIN_PROTOCOL_VERSION..=MAX_PROTOCOL_VERSION {
3309                let cur = ProtocolVersion::new(i);
3310                assert_yaml_snapshot!(
3311                    format!("{}version_{}", chain_str, cur.as_u64()),
3312                    ProtocolConfig::get_for_version(cur, *chain_id)
3313                );
3314            }
3315        }
3316    }
3317
3318    #[test]
3319    fn test_getters() {
3320        let prot: ProtocolConfig =
3321            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown);
3322        assert_eq!(
3323            prot.max_arguments(),
3324            prot.max_arguments_as_option().unwrap()
3325        );
3326    }
3327
3328    #[test]
3329    fn test_setters() {
3330        let mut prot: ProtocolConfig =
3331            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown);
3332        prot.set_max_arguments_for_testing(123);
3333        assert_eq!(prot.max_arguments(), 123);
3334
3335        prot.set_max_arguments_from_str_for_testing("321".to_string());
3336        assert_eq!(prot.max_arguments(), 321);
3337
3338        prot.disable_max_arguments_for_testing();
3339        assert_eq!(prot.max_arguments_as_option(), None);
3340
3341        prot.set_attr_for_testing("max_arguments".to_string(), "456".to_string());
3342        assert_eq!(prot.max_arguments(), 456);
3343    }
3344
3345    #[test]
3346    #[should_panic(expected = "unsupported version")]
3347    fn max_version_test() {
3348        // When this does not panic, version higher than MAX_PROTOCOL_VERSION exists.
3349        // To fix, bump MAX_PROTOCOL_VERSION or disable this check for the version.
3350        let _ = ProtocolConfig::get_for_version_impl(
3351            ProtocolVersion::new(MAX_PROTOCOL_VERSION + 1),
3352            Chain::Unknown,
3353        );
3354    }
3355
3356    #[test]
3357    fn lookup_by_string_test() {
3358        let prot: ProtocolConfig =
3359            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Mainnet);
3360        // Does not exist
3361        assert!(prot.lookup_attr("some random string".to_string()).is_none());
3362
3363        assert!(
3364            prot.lookup_attr("max_arguments".to_string())
3365                == Some(ProtocolConfigValue::u32(prot.max_arguments())),
3366        );
3367
3368        // We didnt have this in version 1 on Mainnet
3369        assert!(
3370            prot.lookup_attr("poseidon_bn254_cost_base".to_string())
3371                .is_none()
3372        );
3373        assert!(
3374            prot.attr_map()
3375                .get("poseidon_bn254_cost_base")
3376                .unwrap()
3377                .is_none()
3378        );
3379
3380        // But we did in version 1 on Devnet
3381        let prot: ProtocolConfig =
3382            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown);
3383
3384        assert!(
3385            prot.lookup_attr("poseidon_bn254_cost_base".to_string())
3386                == Some(ProtocolConfigValue::u64(prot.poseidon_bn254_cost_base()))
3387        );
3388        assert!(
3389            prot.attr_map().get("poseidon_bn254_cost_base").unwrap()
3390                == &Some(ProtocolConfigValue::u64(prot.poseidon_bn254_cost_base()))
3391        );
3392
3393        // Check feature flags
3394        let prot: ProtocolConfig =
3395            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Mainnet);
3396        // Does not exist
3397        assert!(
3398            prot.feature_flags
3399                .lookup_attr("some random string".to_owned())
3400                .is_none()
3401        );
3402        assert!(
3403            !prot
3404                .feature_flags
3405                .attr_map()
3406                .contains_key("some random string")
3407        );
3408
3409        // Was false in v1 on Mainnet
3410        assert!(prot.feature_flags.lookup_attr("enable_poseidon".to_owned()) == Some(false));
3411        assert!(
3412            prot.feature_flags
3413                .attr_map()
3414                .get("enable_poseidon")
3415                .unwrap()
3416                == &false
3417        );
3418        let prot: ProtocolConfig =
3419            ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown);
3420        // Was true from v1 and up on Devnet
3421        assert!(prot.feature_flags.lookup_attr("enable_poseidon".to_owned()) == Some(true));
3422        assert!(
3423            prot.feature_flags
3424                .attr_map()
3425                .get("enable_poseidon")
3426                .unwrap()
3427                == &true
3428        );
3429    }
3430
3431    #[test]
3432    fn limit_range_fn_test() {
3433        let low = 100u32;
3434        let high = 10000u64;
3435
3436        assert!(check_limit!(1u8, low, high) == LimitThresholdCrossed::None);
3437        assert!(matches!(
3438            check_limit!(255u16, low, high),
3439            LimitThresholdCrossed::Soft(255u128, 100)
3440        ));
3441        // This wont compile because lossy
3442        // assert!(check_limit!(100000000u128, low, high) ==
3443        // LimitThresholdCrossed::None); This wont compile because lossy
3444        // assert!(check_limit!(100000000usize, low, high) ==
3445        // LimitThresholdCrossed::None);
3446
3447        assert!(matches!(
3448            check_limit!(2550000u64, low, high),
3449            LimitThresholdCrossed::Hard(2550000, 10000)
3450        ));
3451
3452        assert!(matches!(
3453            check_limit!(2550000u64, high, high),
3454            LimitThresholdCrossed::Hard(2550000, 10000)
3455        ));
3456
3457        assert!(matches!(
3458            check_limit!(1u8, high),
3459            LimitThresholdCrossed::None
3460        ));
3461
3462        assert!(check_limit!(255u16, high) == LimitThresholdCrossed::None);
3463
3464        assert!(matches!(
3465            check_limit!(2550000u64, high),
3466            LimitThresholdCrossed::Hard(2550000, 10000)
3467        ));
3468    }
3469}