clementine_core/config/
protocol.rs

1use crate::config::env::read_string_from_env_then_parse;
2use crate::constants::{MIN_TAPROOT_AMOUNT, NON_EPHEMERAL_ANCHOR_AMOUNT};
3use crate::errors::BridgeError;
4use bitcoin::{Amount, Network};
5use bridge_circuit_host::utils::is_dev_mode;
6use circuits_lib::bridge_circuit::constants::{
7    DEVNET_LC_IMAGE_ID, MAINNET_LC_IMAGE_ID, REGTEST_LC_IMAGE_ID, TESTNET4_LC_IMAGE_ID,
8};
9use eyre::Context;
10use serde::{Deserialize, Serialize};
11use std::fmt::Display;
12use std::fs;
13use std::path::Path;
14use std::str::FromStr;
15
16pub const BLOCKS_PER_HOUR: u16 = 6;
17
18pub const BLOCKS_PER_DAY: u16 = BLOCKS_PER_HOUR * 24;
19
20pub const BLOCKS_PER_WEEK: u16 = BLOCKS_PER_DAY * 7;
21
22/// This is the log_d used across the codebase.
23///
24/// All protocol paramsets should use this value since it's used in the BitVM static.
25pub const WINTERNITZ_LOG_D: u32 = 4;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
28#[serde(rename_all = "lowercase")]
29/// A pre-defined paramset name that can be converted into a
30/// [`ProtocolParamset`] reference.
31///
32/// See: [`REGTEST_PARAMSET`]
33pub enum ProtocolParamsetName {
34    // Pre-defined paramsets
35    Regtest,
36}
37
38impl FromStr for ProtocolParamsetName {
39    type Err = BridgeError;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        match s {
43            "regtest" => Ok(ProtocolParamsetName::Regtest),
44            _ => Err(BridgeError::ConfigError(format!(
45                "Unknown paramset name: {s}"
46            ))),
47        }
48    }
49}
50
51impl Display for ProtocolParamsetName {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        match self {
54            ProtocolParamsetName::Regtest => write!(f, "regtest"),
55        }
56    }
57}
58
59impl From<ProtocolParamsetName> for &'static ProtocolParamset {
60    fn from(name: ProtocolParamsetName) -> Self {
61        match name {
62            ProtocolParamsetName::Regtest => &REGTEST_PARAMSET,
63        }
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
68/// Protocol parameters that affect the transactions in the contract (which also
69/// change the pre-calculated txids and sighashes).
70///
71/// These parameters are used when generating the transactions and changing them
72/// will break compatibility between actors, making deposits impossible.  A
73/// paramset is chosen by the actor by choosing a ParamsetName inside the
74/// [`crate::config::BridgeConfig`].
75pub struct ProtocolParamset {
76    /// Bitcoin network to work on (mainnet, testnet, regtest).
77    pub network: Network,
78    /// Number of round transactions that the operator will create.
79    pub num_round_txs: usize,
80    /// Number of kickoff UTXOs per round transaction.
81    pub num_kickoffs_per_round: usize,
82    /// Number of kickoffs that are signed per round and deposit.
83    /// There are num_kickoffs_per_round utxo's, but only num_signed_kickoffs are signed.
84    pub num_signed_kickoffs: usize,
85    /// Bridge deposit amount that users can deposit.
86    pub bridge_amount: Amount,
87    /// Amount allocated for each kickoff UTXO.
88    pub kickoff_amount: Amount,
89    /// Amount allocated for operator challenge transactions.
90    pub operator_challenge_amount: Amount,
91    /// Collateral funding amount for operators used to fund the round transaction chain.
92    pub collateral_funding_amount: Amount,
93    /// Length of the blockhash commitment in kickoff transactions.
94    pub kickoff_blockhash_commit_length: u32,
95    /// Total number of bytes of a watchtower challenge.
96    pub watchtower_challenge_bytes: usize,
97    /// Winternitz derivation log_d (shared for all WOTS commitments)
98    /// Currently used in statics and thus cannot be different from [`WINTERNITZ_LOG_D`].
99    pub winternitz_log_d: u32,
100    /// Number of blocks after which user can take deposit back if deposit request fails.
101    pub user_takes_after: u16,
102    /// Number of blocks for operator challenge timeout timelock (currently BLOCKS_PER_WEEK)
103    pub operator_challenge_timeout_timelock: u16,
104    /// Number of blocks for operator challenge NACK timelock (currently BLOCKS_PER_WEEK * 3)
105    pub operator_challenge_nack_timelock: u16,
106    /// Number of blocks for disprove timeout timelock (currently BLOCKS_PER_WEEK * 5)
107    pub disprove_timeout_timelock: u16,
108    /// Number of blocks for assert timeout timelock (currently BLOCKS_PER_WEEK * 4)
109    pub assert_timeout_timelock: u16,
110    /// Number of blocks for latest blockhash timeout timelock (currently BLOCKS_PER_WEEK * 2.5)
111    pub latest_blockhash_timeout_timelock: u16,
112    /// Number of blocks for operator reimburse timelock (currently BLOCKS_PER_DAY * 2)
113    /// Timelocks operator from sending the next Round Tx after the Ready to Reimburse Tx.
114    pub operator_reimburse_timelock: u16,
115    /// Number of blocks for watchtower challenge timeout timelock (currently BLOCKS_PER_WEEK * 2)
116    pub watchtower_challenge_timeout_timelock: u16,
117    /// Amount of depth a block should have from the current head to be considered finalized
118    /// Also means finality_confirmations, how many confirmations are needed for a block to be considered finalized
119    /// The chain tip has 1 confirmation. Minimum value should be 1.
120    pub finality_depth: u32,
121    /// start height to sync the chain from, i.e. the height bridge was deployed
122    pub start_height: u32,
123    /// Genesis height to sync the header chain proofs from
124    pub genesis_height: u32,
125    /// Genesis chain state hash
126    pub genesis_chain_state_hash: [u8; 32],
127    /// Denotes if the bridge is non-standard, i.e. uses 0 sat outputs for round tx (except collateral) and kickoff outputs
128    pub bridge_nonstandard: bool,
129}
130
131impl ProtocolParamset {
132    pub fn from_toml_file(path: &Path) -> Result<Self, BridgeError> {
133        let contents = fs::read_to_string(path).wrap_err("Failed to read config file")?;
134
135        let paramset: Self = toml::from_str(&contents).wrap_err("Failed to parse TOML")?;
136        if paramset.finality_depth < 1 {
137            return Err(BridgeError::ConfigError(
138                "Finality depth must be at least 1".to_string(),
139            ));
140        }
141
142        Ok(paramset)
143    }
144    pub fn from_env() -> Result<Self, BridgeError> {
145        let config = ProtocolParamset {
146            network: read_string_from_env_then_parse::<Network>("NETWORK")?,
147            num_round_txs: read_string_from_env_then_parse::<usize>("NUM_ROUND_TXS")?,
148            num_kickoffs_per_round: read_string_from_env_then_parse::<usize>(
149                "NUM_KICKOFFS_PER_ROUND",
150            )?,
151            num_signed_kickoffs: read_string_from_env_then_parse::<usize>("NUM_SIGNED_KICKOFFS")?,
152            bridge_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
153                "BRIDGE_AMOUNT",
154            )?),
155            kickoff_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
156                "KICKOFF_AMOUNT",
157            )?),
158            operator_challenge_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
159                "OPERATOR_CHALLENGE_AMOUNT",
160            )?),
161            collateral_funding_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
162                "COLLATERAL_FUNDING_AMOUNT",
163            )?),
164            kickoff_blockhash_commit_length: read_string_from_env_then_parse::<u32>(
165                "KICKOFF_BLOCKHASH_COMMIT_LENGTH",
166            )?,
167            watchtower_challenge_bytes: read_string_from_env_then_parse::<usize>(
168                "WATCHTOWER_CHALLENGE_BYTES",
169            )?,
170            winternitz_log_d: read_string_from_env_then_parse::<u32>("WINTERNITZ_LOG_D")?,
171            user_takes_after: read_string_from_env_then_parse::<u16>("USER_TAKES_AFTER")?,
172            operator_challenge_timeout_timelock: read_string_from_env_then_parse::<u16>(
173                "OPERATOR_CHALLENGE_TIMEOUT_TIMELOCK",
174            )?,
175            operator_challenge_nack_timelock: read_string_from_env_then_parse::<u16>(
176                "OPERATOR_CHALLENGE_NACK_TIMELOCK",
177            )?,
178            disprove_timeout_timelock: read_string_from_env_then_parse::<u16>(
179                "DISPROVE_TIMEOUT_TIMELOCK",
180            )?,
181            assert_timeout_timelock: read_string_from_env_then_parse::<u16>(
182                "ASSERT_TIMEOUT_TIMELOCK",
183            )?,
184            operator_reimburse_timelock: read_string_from_env_then_parse::<u16>(
185                "OPERATOR_REIMBURSE_TIMELOCK",
186            )?,
187            watchtower_challenge_timeout_timelock: read_string_from_env_then_parse::<u16>(
188                "WATCHTOWER_CHALLENGE_TIMEOUT_TIMELOCK",
189            )?,
190            finality_depth: read_string_from_env_then_parse::<u32>("FINALITY_DEPTH")?,
191            start_height: read_string_from_env_then_parse::<u32>("START_HEIGHT")?,
192            genesis_height: read_string_from_env_then_parse::<u32>("GENESIS_HEIGHT")?,
193            genesis_chain_state_hash: convert_hex_string_to_bytes(
194                &read_string_from_env_then_parse::<String>("GENESIS_CHAIN_STATE_HASH")?,
195            )?,
196            latest_blockhash_timeout_timelock: read_string_from_env_then_parse::<u16>(
197                "LATEST_BLOCKHASH_TIMEOUT_TIMELOCK",
198            )?,
199            bridge_nonstandard: read_string_from_env_then_parse::<bool>("BRIDGE_NONSTANDARD")?,
200        };
201
202        if config.finality_depth < 1 {
203            return Err(BridgeError::ConfigError(
204                "Finality depth must be at least 1".to_string(),
205            ));
206        }
207
208        Ok(config)
209    }
210
211    pub fn default_utxo_amount(&self) -> Amount {
212        if self.bridge_nonstandard {
213            Amount::from_sat(0)
214        } else {
215            MIN_TAPROOT_AMOUNT
216        }
217    }
218
219    pub fn anchor_amount(&self) -> Amount {
220        if self.bridge_nonstandard {
221            Amount::from_sat(0)
222        } else {
223            NON_EPHEMERAL_ANCHOR_AMOUNT
224        }
225    }
226
227    /// Checks if a block is finalized. In clementine and citrea, finality depth means the amount of confirmations needed for a block to be considered finalized.
228    /// The chain tip has 1 confirmation.
229    pub fn is_block_finalized(&self, block_height: u32, chain_tip_height: u32) -> bool {
230        if block_height > chain_tip_height {
231            return false;
232        }
233
234        chain_tip_height - block_height + 1 >= self.finality_depth
235    }
236
237    pub fn bridge_circuit_constant(&self) -> Result<&[u8; 32], BridgeError> {
238        match self.network {
239            Network::Regtest => {
240                if is_dev_mode() {
241                    Ok(&REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT)
242                } else {
243                    Ok(&REGTEST_BRIDGE_CIRCUIT_CONSTANT)
244                }
245            }
246            Network::Bitcoin => Ok(&MAINNET_BRIDGE_CIRCUIT_CONSTANT),
247            Network::Testnet4 => {
248                if is_dev_mode() {
249                    Ok(&TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT)
250                } else {
251                    Ok(&TESTNET4_BRIDGE_CIRCUIT_CONSTANT)
252                }
253            }
254            Network::Signet => {
255                if is_dev_mode() {
256                    Ok(&SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT)
257                } else {
258                    Ok(&SIGNET_BRIDGE_CIRCUIT_CONSTANT)
259                }
260            }
261            _ => Err(BridgeError::UnsupportedNetwork),
262        }
263    }
264
265    /// Get the light client proof image id for the network.
266    pub fn get_lcp_image_id(&self) -> Result<[u8; 32], BridgeError> {
267        Ok(match self.network {
268            bitcoin::Network::Bitcoin => MAINNET_LC_IMAGE_ID,
269            bitcoin::Network::Testnet4 => TESTNET4_LC_IMAGE_ID,
270            bitcoin::Network::Signet => DEVNET_LC_IMAGE_ID,
271            bitcoin::Network::Regtest => REGTEST_LC_IMAGE_ID,
272            _ => return Err(eyre::eyre!("Unsupported Bitcoin network").into()),
273        })
274    }
275
276    pub fn is_regtest(&self) -> bool {
277        self.network == Network::Regtest
278    }
279}
280
281fn convert_hex_string_to_bytes(hex: &str) -> Result<[u8; 32], BridgeError> {
282    let hex_decode = hex::decode(hex).wrap_err("Failed to decode hex string")?;
283    let hex_bytes: [u8; 32] = hex_decode
284        .as_slice()
285        .try_into()
286        .wrap_err("Hex string is not 32 bytes")?;
287    Ok(hex_bytes)
288}
289
290impl Default for ProtocolParamset {
291    fn default() -> Self {
292        REGTEST_PARAMSET
293    }
294}
295impl Default for &'static ProtocolParamset {
296    fn default() -> Self {
297        &REGTEST_PARAMSET
298    }
299}
300
301pub const REGTEST_PARAMSET: ProtocolParamset = ProtocolParamset {
302    network: Network::Regtest,
303    num_round_txs: 2,
304    num_kickoffs_per_round: 10,
305    num_signed_kickoffs: 2,
306    bridge_amount: Amount::from_sat(1_000_000_000),
307    kickoff_amount: Amount::from_sat(0),
308    operator_challenge_amount: Amount::from_sat(200_000_000),
309    collateral_funding_amount: Amount::from_sat(99_000_000),
310    watchtower_challenge_bytes: 144,
311    kickoff_blockhash_commit_length: 40,
312    winternitz_log_d: WINTERNITZ_LOG_D,
313    user_takes_after: 200,
314    operator_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR,
315    operator_challenge_nack_timelock: 4 * BLOCKS_PER_HOUR * 3,
316    disprove_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5,
317    assert_timeout_timelock: 4 * BLOCKS_PER_HOUR * 4,
318    operator_reimburse_timelock: 2,
319    watchtower_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR * 2,
320    latest_blockhash_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5 / 2,
321    finality_depth: 5, // citrea e2e finality depth
322    start_height: 190,
323    genesis_height: 0,
324    genesis_chain_state_hash: [
325        95, 115, 2, 173, 22, 200, 189, 158, 242, 243, 190, 0, 200, 25, 154, 134, 249, 224, 186,
326        134, 20, 132, 171, 180, 175, 95, 126, 69, 127, 140, 34, 22,
327    ],
328    bridge_nonstandard: true,
329};
330
331pub const TESTNET4_TEST_PARAMSET: ProtocolParamset = ProtocolParamset {
332    network: Network::Testnet4,
333    num_round_txs: 2,
334    num_kickoffs_per_round: 10,
335    num_signed_kickoffs: 2,
336    bridge_amount: Amount::from_sat(1_000_000),
337    kickoff_amount: Amount::from_sat(0),
338    operator_challenge_amount: Amount::from_sat(200_000),
339    collateral_funding_amount: Amount::from_sat(99_000),
340    watchtower_challenge_bytes: 144,
341    kickoff_blockhash_commit_length: 40,
342    winternitz_log_d: WINTERNITZ_LOG_D,
343    user_takes_after: 200,
344    operator_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR,
345    operator_challenge_nack_timelock: 4 * BLOCKS_PER_HOUR * 3,
346    disprove_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5,
347    assert_timeout_timelock: 4 * BLOCKS_PER_HOUR * 4,
348    operator_reimburse_timelock: 2,
349    watchtower_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR * 2,
350    latest_blockhash_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5 / 2,
351    finality_depth: 1,
352    start_height: 92700,
353    genesis_height: 92700,
354    genesis_chain_state_hash: [
355        0xe4, 0xe1, 0x28, 0xa8, 0x99, 0xaf, 0xee, 0xb1, 0x85, 0x5b, 0x4a, 0xb7, 0x2e, 0x4d, 0x88,
356        0x50, 0xab, 0x35, 0x1b, 0xde, 0xf9, 0x4f, 0xc2, 0x78, 0xe8, 0x5c, 0x13, 0x11, 0xe2, 0x72,
357        0xfe, 0x6a,
358    ],
359    bridge_nonstandard: true,
360};
361
362pub const REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
363    114, 212, 219, 106, 251, 50, 248, 9, 2, 194, 84, 239, 229, 92, 195, 40, 218, 21, 55, 242, 230,
364    201, 145, 209, 251, 25, 77, 124, 129, 131, 194, 20,
365];
366
367pub const REGTEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
368    233, 84, 200, 234, 120, 196, 185, 119, 174, 126, 140, 238, 189, 210, 149, 97, 161, 4, 229, 219,
369    47, 124, 117, 197, 89, 165, 120, 138, 221, 74, 157, 71,
370];
371
372pub const SIGNET_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
373    73, 219, 48, 6, 223, 104, 179, 207, 180, 104, 112, 231, 210, 2, 0, 47, 87, 166, 183, 168, 211,
374    250, 76, 145, 200, 214, 169, 135, 151, 47, 202, 184,
375];
376
377pub const SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
378    234, 217, 1, 13, 50, 162, 237, 187, 139, 172, 117, 214, 39, 142, 252, 26, 47, 173, 67, 109, 98,
379    47, 59, 121, 185, 133, 184, 164, 241, 44, 113, 58,
380];
381
382pub const MAINNET_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
383    154, 254, 2, 67, 66, 37, 230, 195, 3, 247, 101, 4, 196, 126, 226, 135, 163, 6, 165, 124, 119,
384    3, 143, 171, 85, 55, 9, 250, 45, 12, 140, 64,
385];
386
387pub const TESTNET4_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
388    123, 6, 8, 84, 79, 122, 249, 123, 48, 241, 129, 10, 215, 65, 243, 68, 174, 66, 239, 146, 1, 75,
389    168, 108, 46, 59, 223, 127, 125, 127, 97, 90,
390];
391
392pub const TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
393    83, 191, 166, 41, 241, 95, 11, 84, 148, 1, 21, 128, 190, 167, 207, 165, 143, 209, 232, 169,
394    211, 120, 188, 115, 219, 48, 108, 224, 129, 254, 54, 214,
395];
396
397#[cfg(test)]
398mod tests {
399    use bridge_circuit_host::{
400        bridge_circuit_host::{
401            MAINNET_BRIDGE_CIRCUIT_ELF, REGTEST_BRIDGE_CIRCUIT_ELF, SIGNET_BRIDGE_CIRCUIT_ELF,
402            SIGNET_BRIDGE_CIRCUIT_ELF_TEST, TESTNET4_BRIDGE_CIRCUIT_ELF,
403            TESTNET4_BRIDGE_CIRCUIT_ELF_TEST,
404        },
405        utils::calculate_succinct_output_prefix,
406    };
407    use circuits_lib::{
408        bridge_circuit::constants::{
409            MAINNET_WORK_ONLY_METHOD_ID, REGTEST_WORK_ONLY_METHOD_ID, SIGNET_WORK_ONLY_METHOD_ID,
410            TESTNET4_WORK_ONLY_METHOD_ID,
411        },
412        common::constants::{
413            MAINNET_HEADER_CHAIN_METHOD_ID, REGTEST_HEADER_CHAIN_METHOD_ID,
414            SIGNET_HEADER_CHAIN_METHOD_ID, TESTNET4_HEADER_CHAIN_METHOD_ID,
415        },
416    };
417    use risc0_zkvm::compute_image_id;
418
419    use bridge_circuit_host::bridge_circuit_host::{
420        MAINNET_HEADER_CHAIN_ELF, MAINNET_WORK_ONLY_ELF, REGTEST_HEADER_CHAIN_ELF,
421        REGTEST_WORK_ONLY_ELF, SIGNET_HEADER_CHAIN_ELF, SIGNET_WORK_ONLY_ELF,
422        TESTNET4_HEADER_CHAIN_ELF, TESTNET4_WORK_ONLY_ELF,
423    };
424
425    use super::*;
426
427    #[test]
428    fn test_regtest_test_bridge_circuit_constant() {
429        let regtest_bridge_elf =
430            include_bytes!("../../../risc0-circuits/elfs/test-regtest-bridge-circuit-guest.bin");
431        let regtest_bridge_circuit_method_id =
432            compute_image_id(regtest_bridge_elf).expect("should compute image id");
433        let calculated_regtest_bridge_circuit_constant =
434            calculate_succinct_output_prefix(regtest_bridge_circuit_method_id.as_bytes());
435
436        let regtest_bridge_circuit_constant = REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT;
437        assert_eq!(
438            calculated_regtest_bridge_circuit_constant,
439            regtest_bridge_circuit_constant,
440            "You forgot to update regtest-(test) bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
441            calculated_regtest_bridge_circuit_constant,
442            hex::encode(calculated_regtest_bridge_circuit_constant)
443        );
444    }
445
446    #[test]
447    fn test_regtest_bridge_circuit_constant() {
448        let regtest_bridge_elf = REGTEST_BRIDGE_CIRCUIT_ELF;
449        let regtest_bridge_circuit_method_id =
450            compute_image_id(regtest_bridge_elf).expect("should compute image id");
451        let calculated_regtest_bridge_circuit_constant =
452            calculate_succinct_output_prefix(regtest_bridge_circuit_method_id.as_bytes());
453
454        let regtest_bridge_circuit_constant = REGTEST_BRIDGE_CIRCUIT_CONSTANT;
455        assert_eq!(
456            calculated_regtest_bridge_circuit_constant,
457            regtest_bridge_circuit_constant,
458            "You forgot to update regtest bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
459            calculated_regtest_bridge_circuit_constant,
460            hex::encode(calculated_regtest_bridge_circuit_constant)
461        );
462    }
463
464    #[test]
465    fn test_mainnet_bridge_circuit_constant() {
466        let mainnet_bridge_elf = MAINNET_BRIDGE_CIRCUIT_ELF;
467        let mainnet_bridge_circuit_method_id =
468            compute_image_id(mainnet_bridge_elf).expect("should compute image id");
469        let calculated_mainnet_bridge_circuit_constant =
470            calculate_succinct_output_prefix(mainnet_bridge_circuit_method_id.as_bytes());
471
472        let mainnet_bridge_circuit_constant = MAINNET_BRIDGE_CIRCUIT_CONSTANT;
473        assert_eq!(
474            calculated_mainnet_bridge_circuit_constant,
475            mainnet_bridge_circuit_constant,
476            "You forgot to update mainnet bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
477            calculated_mainnet_bridge_circuit_constant,
478            hex::encode(calculated_mainnet_bridge_circuit_constant)
479        );
480    }
481
482    #[test]
483    fn test_testnet4_bridge_circuit_constant() {
484        let testnet4_bridge_elf = TESTNET4_BRIDGE_CIRCUIT_ELF;
485        let testnet4_bridge_circuit_method_id =
486            compute_image_id(testnet4_bridge_elf).expect("should compute image id");
487        let calculated_testnet4_bridge_circuit_constant =
488            calculate_succinct_output_prefix(testnet4_bridge_circuit_method_id.as_bytes());
489
490        let testnet4_bridge_circuit_constant = TESTNET4_BRIDGE_CIRCUIT_CONSTANT;
491        assert_eq!(
492            calculated_testnet4_bridge_circuit_constant,
493            testnet4_bridge_circuit_constant,
494            "You forgot to update testnet4 bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
495            calculated_testnet4_bridge_circuit_constant,
496            hex::encode(calculated_testnet4_bridge_circuit_constant)
497        );
498    }
499
500    #[test]
501    fn test_testnet4_test_bridge_circuit_constant() {
502        let testnet4_bridge_elf = TESTNET4_BRIDGE_CIRCUIT_ELF_TEST;
503        let testnet4_bridge_circuit_method_id =
504            compute_image_id(testnet4_bridge_elf).expect("should compute image id");
505        let calculated_testnet4_bridge_circuit_constant =
506            calculate_succinct_output_prefix(testnet4_bridge_circuit_method_id.as_bytes());
507
508        let testnet4_bridge_circuit_constant = TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT;
509        assert_eq!(
510            calculated_testnet4_bridge_circuit_constant,
511            testnet4_bridge_circuit_constant,
512            "You forgot to update testnet4-test bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
513            calculated_testnet4_bridge_circuit_constant,
514            hex::encode(calculated_testnet4_bridge_circuit_constant)
515        );
516    }
517
518    #[test]
519    fn test_signet_bridge_circuit_constant() {
520        let signet_bridge_elf = SIGNET_BRIDGE_CIRCUIT_ELF;
521        let signet_bridge_circuit_method_id =
522            compute_image_id(signet_bridge_elf).expect("should compute image id");
523        let calculated_signet_bridge_circuit_constant =
524            calculate_succinct_output_prefix(signet_bridge_circuit_method_id.as_bytes());
525
526        let signet_bridge_circuit_constant = SIGNET_BRIDGE_CIRCUIT_CONSTANT;
527        assert_eq!(
528            calculated_signet_bridge_circuit_constant,
529            signet_bridge_circuit_constant,
530            "You forgot to update signet bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
531            calculated_signet_bridge_circuit_constant,
532            hex::encode(calculated_signet_bridge_circuit_constant)
533        );
534    }
535
536    #[test]
537    fn test_signet_test_bridge_circuit_constant() {
538        let signet_bridge_elf = SIGNET_BRIDGE_CIRCUIT_ELF_TEST;
539        let signet_bridge_circuit_method_id =
540            compute_image_id(signet_bridge_elf).expect("should compute image id");
541        let calculated_signet_bridge_circuit_constant =
542            calculate_succinct_output_prefix(signet_bridge_circuit_method_id.as_bytes());
543
544        let signet_bridge_circuit_constant = SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT;
545        assert_eq!(
546            calculated_signet_bridge_circuit_constant,
547            signet_bridge_circuit_constant,
548            "You forgot to update signet-test bridge_circuit_constant with the new method id. Please change it in these places: core/src/config/protocol.rs. The expected value is: {:?}, hex format: {:?}",
549            calculated_signet_bridge_circuit_constant,
550            hex::encode(calculated_signet_bridge_circuit_constant)
551        );
552    }
553
554    #[test]
555    fn test_header_chain_method_ids() {
556        let networks = [
557            (
558                MAINNET_HEADER_CHAIN_ELF,
559                MAINNET_HEADER_CHAIN_METHOD_ID,
560                "mainnet",
561            ),
562            (
563                TESTNET4_HEADER_CHAIN_ELF,
564                TESTNET4_HEADER_CHAIN_METHOD_ID,
565                "testnet4",
566            ),
567            (
568                SIGNET_HEADER_CHAIN_ELF,
569                SIGNET_HEADER_CHAIN_METHOD_ID,
570                "signet",
571            ),
572            (
573                REGTEST_HEADER_CHAIN_ELF,
574                REGTEST_HEADER_CHAIN_METHOD_ID,
575                "regtest",
576            ),
577        ];
578
579        for (elf, method_id, network) in networks.into_iter() {
580            let header_chain_circuit_method_id = compute_image_id(elf);
581            assert_eq!(
582                header_chain_circuit_method_id.expect("should compute image id").as_words(),
583                method_id,
584                "Header chain method ID mismatch for {network}, please update the constant here: circuits-lib/src/common/constants.rs",
585            );
586        }
587    }
588
589    #[test]
590    fn test_work_only_method_ids() {
591        let networks = [
592            (
593                MAINNET_WORK_ONLY_ELF,
594                MAINNET_WORK_ONLY_METHOD_ID,
595                "mainnet",
596            ),
597            (
598                TESTNET4_WORK_ONLY_ELF,
599                TESTNET4_WORK_ONLY_METHOD_ID,
600                "testnet4",
601            ),
602            (SIGNET_WORK_ONLY_ELF, SIGNET_WORK_ONLY_METHOD_ID, "signet"),
603            (
604                REGTEST_WORK_ONLY_ELF,
605                REGTEST_WORK_ONLY_METHOD_ID,
606                "regtest",
607            ),
608        ];
609
610        for (elf, method_id, network) in networks.into_iter() {
611            let work_only_circuit_method_id =
612                compute_image_id(elf).expect("should compute image id");
613            let current_method_id = work_only_circuit_method_id.as_bytes();
614            assert_eq!(
615                current_method_id,
616                method_id,
617                "Work only method ID mismatch for {network}, please update the constant here: circuits-lib/src/bridge_circuit/constants.rs. Hex format of correct value: {:?}",
618                hex::encode(current_method_id)
619            );
620        }
621    }
622}