clementine_core/config/
protocol.rs

1use crate::config::env::read_string_from_env_then_parse;
2use bitcoin::{Amount, Network};
3use bridge_circuit_host::utils::is_dev_mode;
4use circuits_lib::bridge_circuit::constants::{
5    DEVNET_LC_IMAGE_ID, MAINNET_LC_IMAGE_ID, REGTEST_LC_IMAGE_ID, TESTNET4_LC_IMAGE_ID,
6};
7pub use clementine_config::{
8    ProtocolParamset, ProtocolParamsetName, BLOCKS_PER_HOUR, REGTEST_PARAMSET, WINTERNITZ_LOG_D,
9};
10use clementine_errors::BridgeError;
11use eyre::Context;
12
13pub const BLOCKS_PER_DAY: u16 = BLOCKS_PER_HOUR * 24;
14pub const BLOCKS_PER_WEEK: u16 = BLOCKS_PER_DAY * 7;
15
16pub trait ProtocolParamsetExt {
17    fn bridge_circuit_constant(&self) -> Result<&'static [u8; 32], BridgeError>;
18    fn get_lcp_image_id(&self) -> Result<[u8; 32], BridgeError>;
19    fn from_env() -> Result<ProtocolParamset, BridgeError>;
20}
21
22impl ProtocolParamsetExt for ProtocolParamset {
23    fn bridge_circuit_constant(&self) -> Result<&'static [u8; 32], BridgeError> {
24        match self.network {
25            Network::Regtest => {
26                if is_dev_mode() {
27                    Ok(&REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT)
28                } else {
29                    Ok(&REGTEST_BRIDGE_CIRCUIT_CONSTANT)
30                }
31            }
32            Network::Bitcoin => Ok(&MAINNET_BRIDGE_CIRCUIT_CONSTANT),
33            Network::Testnet4 => {
34                if is_dev_mode() {
35                    Ok(&TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT)
36                } else {
37                    Ok(&TESTNET4_BRIDGE_CIRCUIT_CONSTANT)
38                }
39            }
40            Network::Signet => {
41                if is_dev_mode() {
42                    Ok(&SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT)
43                } else {
44                    Ok(&SIGNET_BRIDGE_CIRCUIT_CONSTANT)
45                }
46            }
47            _ => Err(BridgeError::UnsupportedNetwork),
48        }
49    }
50
51    /// Get the light client proof image id for the network.
52    fn get_lcp_image_id(&self) -> Result<[u8; 32], BridgeError> {
53        Ok(match self.network {
54            bitcoin::Network::Bitcoin => MAINNET_LC_IMAGE_ID,
55            bitcoin::Network::Testnet4 => TESTNET4_LC_IMAGE_ID,
56            bitcoin::Network::Signet => DEVNET_LC_IMAGE_ID,
57            bitcoin::Network::Regtest => REGTEST_LC_IMAGE_ID,
58            _ => return Err(eyre::eyre!("Unsupported Bitcoin network").into()),
59        })
60    }
61
62    fn from_env() -> Result<Self, BridgeError> {
63        let config = ProtocolParamset {
64            network: read_string_from_env_then_parse::<Network>("NETWORK")?,
65            num_round_txs: read_string_from_env_then_parse::<usize>("NUM_ROUND_TXS")?,
66            num_kickoffs_per_round: read_string_from_env_then_parse::<usize>(
67                "NUM_KICKOFFS_PER_ROUND",
68            )?,
69            num_signed_kickoffs: read_string_from_env_then_parse::<usize>("NUM_SIGNED_KICKOFFS")?,
70            bridge_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
71                "BRIDGE_AMOUNT",
72            )?),
73            kickoff_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
74                "KICKOFF_AMOUNT",
75            )?),
76            operator_challenge_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
77                "OPERATOR_CHALLENGE_AMOUNT",
78            )?),
79            collateral_funding_amount: Amount::from_sat(read_string_from_env_then_parse::<u64>(
80                "COLLATERAL_FUNDING_AMOUNT",
81            )?),
82            kickoff_blockhash_commit_length: read_string_from_env_then_parse::<u32>(
83                "KICKOFF_BLOCKHASH_COMMIT_LENGTH",
84            )?,
85            watchtower_challenge_bytes: read_string_from_env_then_parse::<usize>(
86                "WATCHTOWER_CHALLENGE_BYTES",
87            )?,
88            winternitz_log_d: read_string_from_env_then_parse::<u32>("WINTERNITZ_LOG_D")?,
89            user_takes_after: read_string_from_env_then_parse::<u16>("USER_TAKES_AFTER")?,
90            operator_challenge_timeout_timelock: read_string_from_env_then_parse::<u16>(
91                "OPERATOR_CHALLENGE_TIMEOUT_TIMELOCK",
92            )?,
93            operator_challenge_nack_timelock: read_string_from_env_then_parse::<u16>(
94                "OPERATOR_CHALLENGE_NACK_TIMELOCK",
95            )?,
96            disprove_timeout_timelock: read_string_from_env_then_parse::<u16>(
97                "DISPROVE_TIMEOUT_TIMELOCK",
98            )?,
99            assert_timeout_timelock: read_string_from_env_then_parse::<u16>(
100                "ASSERT_TIMEOUT_TIMELOCK",
101            )?,
102            operator_reimburse_timelock: read_string_from_env_then_parse::<u16>(
103                "OPERATOR_REIMBURSE_TIMELOCK",
104            )?,
105            watchtower_challenge_timeout_timelock: read_string_from_env_then_parse::<u16>(
106                "WATCHTOWER_CHALLENGE_TIMEOUT_TIMELOCK",
107            )?,
108            finality_depth: read_string_from_env_then_parse::<u32>("FINALITY_DEPTH")?,
109            start_height: read_string_from_env_then_parse::<u32>("START_HEIGHT")?,
110            genesis_height: read_string_from_env_then_parse::<u32>("GENESIS_HEIGHT")?,
111            genesis_chain_state_hash: convert_hex_string_to_bytes(
112                &read_string_from_env_then_parse::<String>("GENESIS_CHAIN_STATE_HASH")?,
113            )?,
114            latest_blockhash_timeout_timelock: read_string_from_env_then_parse::<u16>(
115                "LATEST_BLOCKHASH_TIMEOUT_TIMELOCK",
116            )?,
117            bridge_nonstandard: read_string_from_env_then_parse::<bool>("BRIDGE_NONSTANDARD")?,
118        };
119
120        if config.finality_depth < 1 {
121            return Err(BridgeError::ConfigError(
122                "Finality depth must be at least 1".to_string(),
123            ));
124        }
125
126        Ok(config)
127    }
128}
129
130fn convert_hex_string_to_bytes(hex: &str) -> Result<[u8; 32], BridgeError> {
131    let hex_decode = hex::decode(hex).wrap_err("Failed to decode hex string")?;
132    let hex_bytes: [u8; 32] = hex_decode
133        .as_slice()
134        .try_into()
135        .wrap_err("Hex string is not 32 bytes")?;
136    Ok(hex_bytes)
137}
138
139#[cfg(test)]
140pub const TESTNET4_TEST_PARAMSET: ProtocolParamset = ProtocolParamset {
141    network: Network::Testnet4,
142    num_round_txs: 2,
143    num_kickoffs_per_round: 10,
144    num_signed_kickoffs: 2,
145    bridge_amount: Amount::from_sat(1_000_000),
146    kickoff_amount: Amount::from_sat(0),
147    operator_challenge_amount: Amount::from_sat(200_000),
148    collateral_funding_amount: Amount::from_sat(99_000),
149    watchtower_challenge_bytes: 144,
150    kickoff_blockhash_commit_length: 40,
151    winternitz_log_d: WINTERNITZ_LOG_D,
152    user_takes_after: 200,
153    operator_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR,
154    operator_challenge_nack_timelock: 4 * BLOCKS_PER_HOUR * 3,
155    disprove_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5,
156    assert_timeout_timelock: 4 * BLOCKS_PER_HOUR * 4,
157    operator_reimburse_timelock: 2,
158    watchtower_challenge_timeout_timelock: 4 * BLOCKS_PER_HOUR * 2,
159    latest_blockhash_timeout_timelock: 4 * BLOCKS_PER_HOUR * 5 / 2,
160    finality_depth: 1,
161    start_height: 92700,
162    genesis_height: 92700,
163    genesis_chain_state_hash: [
164        0xe4, 0xe1, 0x28, 0xa8, 0x99, 0xaf, 0xee, 0xb1, 0x85, 0x5b, 0x4a, 0xb7, 0x2e, 0x4d, 0x88,
165        0x50, 0xab, 0x35, 0x1b, 0xde, 0xf9, 0x4f, 0xc2, 0x78, 0xe8, 0x5c, 0x13, 0x11, 0xe2, 0x72,
166        0xfe, 0x6a,
167    ],
168    bridge_nonstandard: true,
169};
170
171pub const REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
172    114, 212, 219, 106, 251, 50, 248, 9, 2, 194, 84, 239, 229, 92, 195, 40, 218, 21, 55, 242, 230,
173    201, 145, 209, 251, 25, 77, 124, 129, 131, 194, 20,
174];
175
176pub const REGTEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
177    233, 84, 200, 234, 120, 196, 185, 119, 174, 126, 140, 238, 189, 210, 149, 97, 161, 4, 229, 219,
178    47, 124, 117, 197, 89, 165, 120, 138, 221, 74, 157, 71,
179];
180
181pub const SIGNET_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
182    73, 219, 48, 6, 223, 104, 179, 207, 180, 104, 112, 231, 210, 2, 0, 47, 87, 166, 183, 168, 211,
183    250, 76, 145, 200, 214, 169, 135, 151, 47, 202, 184,
184];
185
186pub const SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
187    234, 217, 1, 13, 50, 162, 237, 187, 139, 172, 117, 214, 39, 142, 252, 26, 47, 173, 67, 109, 98,
188    47, 59, 121, 185, 133, 184, 164, 241, 44, 113, 58,
189];
190
191pub const MAINNET_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
192    129, 78, 18, 124, 221, 80, 148, 108, 252, 53, 139, 39, 96, 60, 162, 140, 241, 131, 111, 46, 52,
193    145, 169, 103, 131, 115, 17, 113, 68, 193, 151, 45,
194];
195
196pub const TESTNET4_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
197    123, 6, 8, 84, 79, 122, 249, 123, 48, 241, 129, 10, 215, 65, 243, 68, 174, 66, 239, 146, 1, 75,
198    168, 108, 46, 59, 223, 127, 125, 127, 97, 90,
199];
200
201pub const TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT: [u8; 32] = [
202    83, 191, 166, 41, 241, 95, 11, 84, 148, 1, 21, 128, 190, 167, 207, 165, 143, 209, 232, 169,
203    211, 120, 188, 115, 219, 48, 108, 224, 129, 254, 54, 214,
204];
205
206#[cfg(test)]
207mod tests {
208    use bridge_circuit_host::{
209        bridge_circuit_host::{
210            MAINNET_BRIDGE_CIRCUIT_ELF, REGTEST_BRIDGE_CIRCUIT_ELF, SIGNET_BRIDGE_CIRCUIT_ELF,
211            SIGNET_BRIDGE_CIRCUIT_ELF_TEST, TESTNET4_BRIDGE_CIRCUIT_ELF,
212            TESTNET4_BRIDGE_CIRCUIT_ELF_TEST,
213        },
214        utils::calculate_succinct_output_prefix,
215    };
216    use circuits_lib::{
217        bridge_circuit::constants::{
218            MAINNET_WORK_ONLY_METHOD_ID, REGTEST_WORK_ONLY_METHOD_ID, SIGNET_WORK_ONLY_METHOD_ID,
219            TESTNET4_WORK_ONLY_METHOD_ID,
220        },
221        common::constants::{
222            MAINNET_HEADER_CHAIN_METHOD_ID, REGTEST_HEADER_CHAIN_METHOD_ID,
223            SIGNET_HEADER_CHAIN_METHOD_ID, TESTNET4_HEADER_CHAIN_METHOD_ID,
224        },
225    };
226    use risc0_zkvm::compute_image_id;
227
228    use bridge_circuit_host::bridge_circuit_host::{
229        MAINNET_HEADER_CHAIN_ELF, MAINNET_WORK_ONLY_ELF, REGTEST_HEADER_CHAIN_ELF,
230        REGTEST_WORK_ONLY_ELF, SIGNET_HEADER_CHAIN_ELF, SIGNET_WORK_ONLY_ELF,
231        TESTNET4_HEADER_CHAIN_ELF, TESTNET4_WORK_ONLY_ELF,
232    };
233
234    use super::*;
235
236    #[test]
237    fn test_regtest_test_bridge_circuit_constant() {
238        let regtest_bridge_elf =
239            include_bytes!("../../../risc0-circuits/elfs/test-regtest-bridge-circuit-guest.bin");
240        let regtest_bridge_circuit_method_id =
241            compute_image_id(regtest_bridge_elf).expect("should compute image id");
242        let calculated_regtest_bridge_circuit_constant =
243            calculate_succinct_output_prefix(regtest_bridge_circuit_method_id.as_bytes());
244
245        let regtest_bridge_circuit_constant = REGTEST_TEST_BRIDGE_CIRCUIT_CONSTANT;
246        assert_eq!(
247            calculated_regtest_bridge_circuit_constant,
248            regtest_bridge_circuit_constant,
249            "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: {:?}",
250            calculated_regtest_bridge_circuit_constant,
251            hex::encode(calculated_regtest_bridge_circuit_constant)
252        );
253    }
254
255    #[test]
256    fn test_regtest_bridge_circuit_constant() {
257        let regtest_bridge_elf = REGTEST_BRIDGE_CIRCUIT_ELF;
258        let regtest_bridge_circuit_method_id =
259            compute_image_id(regtest_bridge_elf).expect("should compute image id");
260        let calculated_regtest_bridge_circuit_constant =
261            calculate_succinct_output_prefix(regtest_bridge_circuit_method_id.as_bytes());
262
263        let regtest_bridge_circuit_constant = REGTEST_BRIDGE_CIRCUIT_CONSTANT;
264        assert_eq!(
265            calculated_regtest_bridge_circuit_constant,
266            regtest_bridge_circuit_constant,
267            "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: {:?}",
268            calculated_regtest_bridge_circuit_constant,
269            hex::encode(calculated_regtest_bridge_circuit_constant)
270        );
271    }
272
273    #[test]
274    fn test_mainnet_bridge_circuit_constant() {
275        let mainnet_bridge_elf = MAINNET_BRIDGE_CIRCUIT_ELF;
276        let mainnet_bridge_circuit_method_id =
277            compute_image_id(mainnet_bridge_elf).expect("should compute image id");
278        let calculated_mainnet_bridge_circuit_constant =
279            calculate_succinct_output_prefix(mainnet_bridge_circuit_method_id.as_bytes());
280
281        let mainnet_bridge_circuit_constant = MAINNET_BRIDGE_CIRCUIT_CONSTANT;
282        assert_eq!(
283            calculated_mainnet_bridge_circuit_constant,
284            mainnet_bridge_circuit_constant,
285            "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: {:?}",
286            calculated_mainnet_bridge_circuit_constant,
287            hex::encode(calculated_mainnet_bridge_circuit_constant)
288        );
289    }
290
291    #[test]
292    fn test_testnet4_bridge_circuit_constant() {
293        let testnet4_bridge_elf = TESTNET4_BRIDGE_CIRCUIT_ELF;
294        let testnet4_bridge_circuit_method_id =
295            compute_image_id(testnet4_bridge_elf).expect("should compute image id");
296        let calculated_testnet4_bridge_circuit_constant =
297            calculate_succinct_output_prefix(testnet4_bridge_circuit_method_id.as_bytes());
298
299        let testnet4_bridge_circuit_constant = TESTNET4_BRIDGE_CIRCUIT_CONSTANT;
300        assert_eq!(
301            calculated_testnet4_bridge_circuit_constant,
302            testnet4_bridge_circuit_constant,
303            "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: {:?}",
304            calculated_testnet4_bridge_circuit_constant,
305            hex::encode(calculated_testnet4_bridge_circuit_constant)
306        );
307    }
308
309    #[test]
310    fn test_testnet4_test_bridge_circuit_constant() {
311        let testnet4_bridge_elf = TESTNET4_BRIDGE_CIRCUIT_ELF_TEST;
312        let testnet4_bridge_circuit_method_id =
313            compute_image_id(testnet4_bridge_elf).expect("should compute image id");
314        let calculated_testnet4_bridge_circuit_constant =
315            calculate_succinct_output_prefix(testnet4_bridge_circuit_method_id.as_bytes());
316
317        let testnet4_bridge_circuit_constant = TESTNET4_TEST_BRIDGE_CIRCUIT_CONSTANT;
318        assert_eq!(
319            calculated_testnet4_bridge_circuit_constant,
320            testnet4_bridge_circuit_constant,
321            "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: {:?}",
322            calculated_testnet4_bridge_circuit_constant,
323            hex::encode(calculated_testnet4_bridge_circuit_constant)
324        );
325    }
326
327    #[test]
328    fn test_signet_bridge_circuit_constant() {
329        let signet_bridge_elf = SIGNET_BRIDGE_CIRCUIT_ELF;
330        let signet_bridge_circuit_method_id =
331            compute_image_id(signet_bridge_elf).expect("should compute image id");
332        let calculated_signet_bridge_circuit_constant =
333            calculate_succinct_output_prefix(signet_bridge_circuit_method_id.as_bytes());
334
335        let signet_bridge_circuit_constant = SIGNET_BRIDGE_CIRCUIT_CONSTANT;
336        assert_eq!(
337            calculated_signet_bridge_circuit_constant,
338            signet_bridge_circuit_constant,
339            "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: {:?}",
340            calculated_signet_bridge_circuit_constant,
341            hex::encode(calculated_signet_bridge_circuit_constant)
342        );
343    }
344
345    #[test]
346    fn test_signet_test_bridge_circuit_constant() {
347        let signet_bridge_elf = SIGNET_BRIDGE_CIRCUIT_ELF_TEST;
348        let signet_bridge_circuit_method_id =
349            compute_image_id(signet_bridge_elf).expect("should compute image id");
350        let calculated_signet_bridge_circuit_constant =
351            calculate_succinct_output_prefix(signet_bridge_circuit_method_id.as_bytes());
352
353        let signet_bridge_circuit_constant = SIGNET_TEST_BRIDGE_CIRCUIT_CONSTANT;
354        assert_eq!(
355            calculated_signet_bridge_circuit_constant,
356            signet_bridge_circuit_constant,
357            "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: {:?}",
358            calculated_signet_bridge_circuit_constant,
359            hex::encode(calculated_signet_bridge_circuit_constant)
360        );
361    }
362
363    #[test]
364    fn test_header_chain_method_ids() {
365        let networks = [
366            (
367                MAINNET_HEADER_CHAIN_ELF,
368                MAINNET_HEADER_CHAIN_METHOD_ID,
369                "mainnet",
370            ),
371            (
372                TESTNET4_HEADER_CHAIN_ELF,
373                TESTNET4_HEADER_CHAIN_METHOD_ID,
374                "testnet4",
375            ),
376            (
377                SIGNET_HEADER_CHAIN_ELF,
378                SIGNET_HEADER_CHAIN_METHOD_ID,
379                "signet",
380            ),
381            (
382                REGTEST_HEADER_CHAIN_ELF,
383                REGTEST_HEADER_CHAIN_METHOD_ID,
384                "regtest",
385            ),
386        ];
387
388        for (elf, method_id, network) in networks.into_iter() {
389            let header_chain_circuit_method_id = compute_image_id(elf);
390            assert_eq!(
391                header_chain_circuit_method_id.expect("should compute image id").as_words(),
392                method_id,
393                "Header chain method ID mismatch for {network}, please update the constant here: circuits-lib/src/common/constants.rs",
394            );
395        }
396    }
397
398    #[test]
399    fn test_work_only_method_ids() {
400        let networks = [
401            (
402                MAINNET_WORK_ONLY_ELF,
403                MAINNET_WORK_ONLY_METHOD_ID,
404                "mainnet",
405            ),
406            (
407                TESTNET4_WORK_ONLY_ELF,
408                TESTNET4_WORK_ONLY_METHOD_ID,
409                "testnet4",
410            ),
411            (SIGNET_WORK_ONLY_ELF, SIGNET_WORK_ONLY_METHOD_ID, "signet"),
412            (
413                REGTEST_WORK_ONLY_ELF,
414                REGTEST_WORK_ONLY_METHOD_ID,
415                "regtest",
416            ),
417        ];
418
419        for (elf, method_id, network) in networks.into_iter() {
420            let work_only_circuit_method_id =
421                compute_image_id(elf).expect("should compute image id");
422            let current_method_id = work_only_circuit_method_id.as_bytes();
423            assert_eq!(
424                current_method_id,
425                method_id,
426                "Work only method ID mismatch for {network}, please update the constant here: circuits-lib/src/bridge_circuit/constants.rs. Hex format of correct value: {:?}",
427                hex::encode(current_method_id)
428            );
429        }
430    }
431}