Skip to main content

hypercall/shared/
env.rs

1//! Environment and mode detection utilities.
2//!
3//! Three separate concerns:
4//! - `is_testnet_mode()`, "which network?" Controls chain IDs, the default catalog
5//!   path selection, and other network-specific settings.
6//!   Set on all testnet and staging deployments.
7//! - `test_endpoints_enabled()`, "allow dangerous /test/* endpoints?" Controls
8//!   spot-price manipulation, IV overrides, instrument expiry, etc.
9//!   Should only be set in local dev and CI, never on deployed environments.
10//! - `faucet` cargo feature: compile-time gate for the `/faucet` route.
11//!   Enabled by `test-endpoints` (local dev, CI) or independently for testnet deploys.
12//!   Never enabled for real-money builds (AWS staging, mainnet).
13
14use crate::backend_config::ModesConfig;
15use std::future::Future;
16
17/// Returns true if running in testnet/dev mode.
18pub fn is_testnet_mode(modes: &ModesConfig) -> bool {
19    modes.testnet_mode
20}
21
22/// Returns true if dangerous test manipulation endpoints are enabled.
23///
24/// This is now a compile-time check via the `test-endpoints` cargo feature.
25/// The feature gates mock feeds, mock oracles, and `/test/*` endpoints.
26/// Should only be enabled for local dev and CI builds, never in deployed binaries.
27pub fn test_endpoints_enabled(_modes: &ModesConfig) -> bool {
28    cfg!(feature = "test-endpoints")
29}
30
31/// Run an async block synchronously from sync code.
32///
33/// Used for testnet-only initialization (funding test accounts in engine builder).
34/// Handles both multi-threaded and single-threaded tokio runtimes:
35/// - Multi-threaded: uses `block_in_place` (efficient, does not block other tasks)
36/// - Single-threaded: spawns a thread with new runtime (avoids deadlock)
37/// - No runtime: creates a temporary runtime
38///
39/// NOTE: This is only called when `modes.testnet_mode=true`. In production, the code path
40/// that uses this is skipped entirely.
41pub fn block_on_async<F, T>(f: F) -> T
42where
43    F: Future<Output = T> + Send + 'static,
44    T: Send + 'static,
45{
46    // Try to get current runtime handle
47    if let Ok(handle) = tokio::runtime::Handle::try_current() {
48        // We're inside a tokio runtime - check if multi-threaded
49        // block_in_place only works on multi-threaded runtime
50        match handle.runtime_flavor() {
51            tokio::runtime::RuntimeFlavor::MultiThread => {
52                tokio::task::block_in_place(|| handle.block_on(f))
53            }
54            _ => {
55                // Single-threaded runtime: spawn blocking thread
56                std::thread::scope(|s| {
57                    s.spawn(|| {
58                        let rt = tokio::runtime::Builder::new_current_thread()
59                            .enable_all()
60                            .build()
61                            .expect("Failed to create runtime");
62                        rt.block_on(f)
63                    })
64                    .join()
65                    .expect("Thread panicked")
66                })
67            }
68        }
69    } else {
70        // Not inside tokio runtime - create one
71        let rt = tokio::runtime::Builder::new_current_thread()
72            .enable_all()
73            .build()
74            .expect("Failed to create runtime");
75        rt.block_on(f)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_mode_helpers_return_config_values() {
85        let modes = ModesConfig {
86            testnet_mode: true,
87            enable_test_endpoints: false,
88            skip_external_oracle: false,
89        };
90
91        assert!(is_testnet_mode(&modes));
92        // test_endpoints_enabled is now compile-time via cfg!(feature = "test-endpoints")
93        assert_eq!(
94            test_endpoints_enabled(&modes),
95            cfg!(feature = "test-endpoints")
96        );
97    }
98
99    #[test]
100    fn test_block_on_async_outside_runtime() {
101        let result = block_on_async(async { 42 });
102        assert_eq!(result, 42);
103    }
104
105    #[tokio::test]
106    async fn test_block_on_async_inside_runtime() {
107        let result = block_on_async(async { 42 });
108        assert_eq!(result, 42);
109    }
110}