mina_core/constants.rs
1use std::sync::OnceLock;
2
3use binprot_derive::BinProtWrite;
4use mina_curves::pasta::Fp;
5use mina_p2p_messages::{bigint, number, v2};
6
7pub const GENESIS_PRODUCER_SK: &str = "EKFKgDtU3rcuFTVSEpmpXSkukjmX4cKefYREi6Sdsk7E7wsT7KRw";
8
9pub const PROTOCOL_VERSION: v2::ProtocolVersionStableV2 = v2::ProtocolVersionStableV2 {
10 transaction: number::Number(3),
11 network: number::Number(0),
12 patch: number::Number(0),
13};
14
15pub fn constraint_constants() -> &'static ConstraintConstants {
16 CONSTRAINT_CONSTANTS_OVERRIDE
17 .get()
18 .unwrap_or(NetworkConfig::global().constraint_constants)
19}
20
21static CONSTRAINT_CONSTANTS_OVERRIDE: OnceLock<ConstraintConstants> = OnceLock::new();
22
23/// Override the fork constants used during genesis computation. (interop testing)
24pub fn set_fork_override(fork: ForkConstants) {
25 let mut cc = NetworkConfig::global().constraint_constants.clone();
26 cc.fork = Some(fork);
27 let _ = CONSTRAINT_CONSTANTS_OVERRIDE.set(cc);
28}
29
30/// Constants that define fork-specific blockchain state.
31///
32/// Fork constants specify the blockchain state at which a protocol upgrade or fork occurred.
33/// These are used to handle protocol changes and ensure compatibility across network upgrades.
34#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
35pub struct ForkConstants {
36 /// Hash of the blockchain state at the fork point
37 #[serde(with = "fp_state_hash_serde")]
38 pub state_hash: Fp,
39
40 /// Blockchain length (number of blocks) at the fork point
41 pub blockchain_length: u32,
42
43 /// Global slot number since genesis at the fork point
44 pub global_slot_since_genesis: u32,
45}
46
47mod fp_state_hash_serde {
48 use super::*;
49
50 pub fn serialize<S: serde::Serializer>(fp: &Fp, serializer: S) -> Result<S::Ok, S::Error> {
51 let state_hash = v2::StateHash::from_fp(*fp);
52 serializer.serialize_str(&state_hash.to_string())
53 }
54
55 pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Fp, D::Error> {
56 let s: String = serde::Deserialize::deserialize(deserializer)?;
57 let state_hash: v2::StateHash = s.parse().map_err(serde::de::Error::custom)?;
58 state_hash
59 .inner()
60 .0
61 .to_field()
62 .map_err(|e| serde::de::Error::custom(format!("invalid state hash: {e}")))
63 }
64}
65
66/// Protocol constraint constants that define core blockchain behavior.
67///
68/// These constants configure fundamental aspects of the Mina protocol including consensus,
69/// transaction processing, economic parameters, and ledger structure. They are compile-time
70/// parameters that must be consistent across all nodes in a network.
71///
72/// ## Consensus and Timing Parameters
73///
74/// The consensus mechanism relies on slot-based timing where blocks are
75/// produced in discrete time slots. The timing hierarchy is:
76/// - **Slots**: Basic time units for block production
77/// - **Sub-windows**: Groups of slots within an epoch
78/// - **Windows**: Collections of sub-windows that define epoch structure
79/// - **Epochs**: Complete consensus periods
80///
81/// ## Economic Parameters
82///
83/// The protocol defines economic incentives through fees and rewards:
84/// - **Coinbase rewards**: Paid to block producers for successful blocks
85/// - **Account creation fees**: Required to create new accounts on the ledger
86/// - **Supercharged rewards**: Multiplier for enhanced block producer rewards
87///
88/// ## Ledger and Transaction Structure
89///
90/// The ledger uses a Merkle tree structure for efficient verification:
91/// - **Ledger depth**: Determines the maximum number of accounts (2^depth)
92/// - **Transaction capacity**: Limits transactions per block for performance
93/// - **Pending coinbase**: Manages delayed coinbase payouts
94///
95/// ## Usage Example
96///
97/// ```rust
98/// use mina_core::constants::constraint_constants;
99///
100/// // Access global constraint constants
101/// let constants = constraint_constants();
102///
103/// // Calculate slots per window
104/// let slots_per_window = constants.sub_windows_per_window;
105/// println!("Sub-windows per window: {}", slots_per_window);
106///
107/// // Get block timing
108/// let block_time_ms = constants.block_window_duration_ms;
109/// println!("Block time: {}ms", block_time_ms);
110///
111/// // Check economic parameters
112/// let coinbase_reward = constants.coinbase_amount;
113/// let creation_fee = constants.account_creation_fee;
114/// println!("Coinbase: {} nanomina, Account fee: {} nanomina",
115/// coinbase_reward, creation_fee);
116/// ```
117///
118/// ## Network Differences
119///
120/// While most constraint constants are identical across networks, some parameters
121/// may differ between mainnet and testnets for development purposes.
122///
123/// OCaml: <https://github.com/MinaProtocol/mina/tree/compatible/src/config>
124/// Protocol specification: <https://github.com/MinaProtocol/mina/blob/compatible/docs/specs/types_and_structures/serialized_key.md>
125#[derive(Clone, Debug)]
126pub struct ConstraintConstants {
127 /// Number of sub-windows that make up a complete window.
128 ///
129 /// Used in the consensus mechanism to structure epoch timing. Combined with
130 /// `slots_per_sub_window` from protocol constants, this determines the total
131 /// slots per window: `slots_per_window = slots_per_sub_window × sub_windows_per_window`.
132 ///
133 /// **Value**: 11 (both mainnet and devnet)
134 pub sub_windows_per_window: u64,
135
136 /// Depth of the account ledger Merkle tree.
137 ///
138 /// This determines the maximum number of accounts that can be stored in the ledger:
139 /// `max_accounts = 2^ledger_depth`. The depth affects proof sizes and verification time.
140 /// A larger depth allows more accounts but increases computational overhead.
141 ///
142 /// **Value**: 35 (supports ~34 billion accounts)
143 /// **Usage**: Account addressing, sparse ledger proofs, zkSNARK constraints
144 pub ledger_depth: u64,
145
146 /// Number of blocks to delay before SNARK work becomes available.
147 ///
148 /// This creates a buffer period between when a block is produced and when
149 /// the associated SNARK work can be included in subsequent blocks. This delay
150 /// helps ensure fair distribution of SNARK work opportunities.
151 ///
152 /// **Value**: 2 blocks
153 /// **Usage**: SNARK work scheduling, proof marketplace timing
154 pub work_delay: u64,
155
156 /// Duration of each block production slot in milliseconds.
157 ///
158 /// This is the fundamental time unit for the consensus protocol. Block producers
159 /// attempt to create blocks during their assigned slots. The duration affects
160 /// network synchronization requirements and transaction confirmation times.
161 ///
162 /// **Value**: 180,000ms (3 minutes)
163 /// **Usage**: Consensus timing, slot calculations, network synchronization
164 pub block_window_duration_ms: u64,
165
166 /// Log₂ of the maximum number of transactions per block.
167 ///
168 /// The actual transaction capacity is `2^transaction_capacity_log_2`. This logarithmic
169 /// representation is used because the value directly affects zkSNARK circuit constraints.
170 /// Higher capacity allows more transactions but increases block processing time.
171 ///
172 /// Corresponds to `transaction_capacity` in the protocol specification, which defines
173 /// the maximum transactions per block (represented as `two_to_the`).
174 ///
175 /// **Value**: 7 (supports 2^7 = 128 transactions per block)
176 /// **Usage**: Transaction pool management, block construction, circuit constraints
177 pub transaction_capacity_log_2: u64,
178
179 /// Number of confirmations before coinbase reward is spendable.
180 ///
181 /// Coinbase rewards are not immediately spendable and require a certain number
182 /// of block confirmations before they can be used. This parameter defines the
183 /// depth of the pending coinbase Merkle tree structure used to track these
184 /// delayed rewards until they mature.
185 ///
186 /// **Value**: 5 (coinbase rewards require 5 block confirmations)
187 /// **Usage**: Coinbase reward management, staged ledger operations, reward maturity
188 pub pending_coinbase_depth: usize,
189
190 /// Block reward amount in nanomina (10⁻⁹ MINA).
191 ///
192 /// This is the base reward paid to block producers for successfully creating a block.
193 /// The amount is specified in nanomina, where 1 MINA = 10⁹ nanomina. Block producers
194 /// may receive additional rewards through the supercharged coinbase mechanism.
195 ///
196 /// **Value**: 720,000,000,000 nanomina (720 MINA)
197 /// **Usage**: Block producer rewards, economic incentives, reward calculations
198 pub coinbase_amount: u64,
199
200 /// Multiplier for supercharged coinbase rewards.
201 ///
202 /// Supercharged rewards were designed to provide double block rewards (factor of 2)
203 /// to block producers staking with unlocked tokens during the early mainnet period
204 /// following the 2021 launch. This mechanism incentivized participation and orderly
205 /// markets after mainnet launch.
206 ///
207 /// **Historical values**:
208 /// - Original mainnet: 2 (double rewards for unlocked tokens)
209 /// - Berkeley hardfork (June 2024): 1 (supercharged rewards removed via MIP1)
210 ///
211 /// The removal was decided by community vote on January 1, 2023, as proposed by
212 /// community member Gareth Davies. This change ensures uniform rewards for all
213 /// tokens and reduces inflation, promoting a sustainable economic model.
214 ///
215 /// **References**:
216 /// - Berkeley Upgrade: <https://minaprotocol.com/blog/minas-berkeley-upgrade-what-to-expect>
217 /// - Supercharged Rewards Removal: <https://minaprotocol.com/blog/update-on-minas-supercharged-rewards-schedule>
218 /// - Original Proposal: <https://github.com/MinaProtocol/mina/issues/5753>
219 ///
220 /// **Usage**: Enhanced reward calculations, incentive mechanisms
221 pub supercharged_coinbase_factor: u64,
222
223 /// Fee required to create a new account in nanomina.
224 ///
225 /// When a transaction creates a new account that doesn't exist on the ledger,
226 /// this fee is charged in addition to the transaction fee. This prevents
227 /// spam account creation and manages ledger growth.
228 ///
229 /// **Value**: 1,000,000,000 nanomina (1 MINA)
230 /// **Usage**: Account creation, transaction validation, fee calculations
231 pub account_creation_fee: u64,
232
233 /// Optional fork constants defining a protocol upgrade point.
234 ///
235 /// When present, these constants specify the blockchain state at which a protocol
236 /// fork or upgrade occurred. This allows the protocol to handle transitions between
237 /// different versions while maintaining consensus.
238 ///
239 /// **Usage**: Protocol upgrades, compatibility handling, genesis configuration
240 pub fork: Option<ForkConstants>,
241}
242#[derive(Clone, Debug, BinProtWrite)]
243pub struct ForkConstantsUnversioned {
244 previous_state_hash: bigint::BigInt,
245 previous_length: number::Int32,
246 genesis_slot: number::Int32,
247}
248
249impl From<&ForkConstants> for ForkConstantsUnversioned {
250 fn from(fork_constants: &ForkConstants) -> Self {
251 Self {
252 previous_state_hash: fork_constants.state_hash.into(),
253 previous_length: fork_constants.blockchain_length.into(),
254 genesis_slot: fork_constants.global_slot_since_genesis.into(),
255 }
256 }
257}
258
259#[derive(Clone, Debug, BinProtWrite)]
260pub struct ConstraintConstantsUnversioned {
261 pub sub_windows_per_window: number::Int64,
262 pub ledger_depth: number::Int64,
263 pub work_delay: number::Int64,
264 pub block_window_duration_ms: number::Int64,
265 pub transaction_capacity_log_2: number::Int64,
266 pub pending_coinbase_depth: number::Int64,
267 pub coinbase_amount: number::UInt64,
268 pub supercharged_coinbase_factor: number::Int64,
269 pub account_creation_fee: number::UInt64,
270 pub fork: Option<ForkConstantsUnversioned>,
271}
272
273impl From<&ConstraintConstants> for ConstraintConstantsUnversioned {
274 fn from(constraints: &ConstraintConstants) -> Self {
275 Self {
276 sub_windows_per_window: constraints.sub_windows_per_window.into(),
277 ledger_depth: constraints.ledger_depth.into(),
278 work_delay: constraints.work_delay.into(),
279 block_window_duration_ms: constraints.block_window_duration_ms.into(),
280 transaction_capacity_log_2: constraints.transaction_capacity_log_2.into(),
281 pending_coinbase_depth: (constraints.pending_coinbase_depth as u64).into(),
282 coinbase_amount: constraints.coinbase_amount.into(),
283 supercharged_coinbase_factor: constraints.supercharged_coinbase_factor.into(),
284 account_creation_fee: constraints.account_creation_fee.into(),
285 fork: constraints.fork.as_ref().map(|fork| fork.into()),
286 }
287 }
288}
289
290impl binprot::BinProtWrite for ConstraintConstants {
291 fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
292 let constraints: ConstraintConstantsUnversioned = self.into();
293 constraints.binprot_write(w)
294 }
295}
296
297pub fn slots_per_window(constants: &v2::MinaBaseProtocolConstantsCheckedValueStableV1) -> u32 {
298 constants.slots_per_sub_window.as_u32() * (constraint_constants().sub_windows_per_window as u32)
299}
300
301const fn days_to_ms(days: u64) -> u64 {
302 days * 24 * 60 * 60 * 1000
303}
304
305pub const CHECKPOINTS_PER_YEAR: u64 = 12;
306
307pub fn checkpoint_window_size_in_slots() -> u32 {
308 let one_year_ms = days_to_ms(365);
309 let slots_per_year = one_year_ms / constraint_constants().block_window_duration_ms;
310 let size_in_slots = slots_per_year / CHECKPOINTS_PER_YEAR;
311 assert_eq!(slots_per_year % CHECKPOINTS_PER_YEAR, 0);
312 size_in_slots as u32
313}
314
315pub const DEFAULT_GENESIS_TIMESTAMP_MILLISECONDS: u64 = 1707157200000;
316
317pub const PROTOCOL_TRANSACTION_VERSION: u8 = 3;
318pub const PROTOCOL_NETWORK_VERSION: u8 = 3;
319pub const TX_POOL_MAX_SIZE: u32 = 3000;
320
321pub use v2::PROTOCOL_CONSTANTS;
322
323use crate::NetworkConfig;