| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 | 
							- //! Binary for starting regtest mints
 
- //!
 
- //! This binary provides a programmatic way to start regtest mints for testing purposes:
 
- //! 1. Sets up a regtest environment with CLN and LND nodes
 
- //! 2. Starts CLN and LND mint instances using the cdk-mintd library
 
- //! 3. Configures the mints to connect to the respective Lightning Network backends
 
- //! 4. Waits for both mints to be ready and responsive
 
- //! 5. Keeps them running until interrupted (Ctrl+C)
 
- //! 6. Gracefully shuts down all services on receiving shutdown signal
 
- //!
 
- //! This approach offers better control and integration compared to external scripts,
 
- //! making it easier to run integration tests with consistent configuration.
 
- use std::fs;
 
- use std::path::Path;
 
- use std::sync::Arc;
 
- use std::time::Duration;
 
- use anyhow::{bail, Result};
 
- use bip39::Mnemonic;
 
- use cashu::Amount;
 
- use cdk_integration_tests::cli::CommonArgs;
 
- use cdk_integration_tests::init_regtest::start_regtest_end;
 
- use cdk_integration_tests::shared;
 
- use cdk_ldk_node::CdkLdkNode;
 
- use cdk_mintd::config::LoggingConfig;
 
- use clap::Parser;
 
- use ldk_node::lightning::ln::msgs::SocketAddress;
 
- use tokio::runtime::Runtime;
 
- use tokio::signal;
 
- use tokio::signal::unix::SignalKind;
 
- use tokio::sync::{oneshot, Notify};
 
- use tokio::time::timeout;
 
- use tokio_util::sync::CancellationToken;
 
- #[derive(Parser)]
 
- #[command(name = "start-regtest-mints")]
 
- #[command(about = "Start regtest mints", long_about = None)]
 
- struct Args {
 
-     #[command(flatten)]
 
-     common: CommonArgs,
 
-     /// Database type (sqlite)
 
-     database_type: String,
 
-     /// Working directory path
 
-     work_dir: String,
 
-     /// Mint address (default: 127.0.0.1)
 
-     #[arg(default_value = "127.0.0.1")]
 
-     mint_addr: String,
 
-     /// CLN port (default: 8085)
 
-     #[arg(default_value_t = 8085)]
 
-     cln_port: u16,
 
-     /// LND port (default: 8087)
 
-     #[arg(default_value_t = 8087)]
 
-     lnd_port: u16,
 
-     /// LDK port (default: 8089)
 
-     #[arg(default_value_t = 8089)]
 
-     ldk_port: u16,
 
- }
 
- /// Start regtest CLN mint using the library
 
- async fn start_cln_mint(
 
-     temp_dir: &Path,
 
-     port: u16,
 
-     shutdown: Arc<Notify>,
 
- ) -> Result<tokio::task::JoinHandle<()>> {
 
-     let cln_rpc_path = temp_dir
 
-         .join("cln")
 
-         .join("one")
 
-         .join("regtest")
 
-         .join("lightning-rpc");
 
-     let cln_config = cdk_mintd::config::Cln {
 
-         rpc_path: cln_rpc_path,
 
-         bolt12: false,
 
-         fee_percent: 0.0,
 
-         reserve_fee_min: 0.into(),
 
-     };
 
-     // Create settings struct for CLN mint using shared function
 
-     let settings = shared::create_cln_settings(
 
-         port,
 
-         temp_dir
 
-             .join("cln")
 
-             .join("one")
 
-             .join("regtest")
 
-             .join("lightning-rpc"),
 
-         "eye survey guilt napkin crystal cup whisper salt luggage manage unveil loyal".to_string(),
 
-         cln_config,
 
-     );
 
-     println!("Starting CLN mintd on port {port}");
 
-     let temp_dir = temp_dir.to_path_buf();
 
-     let shutdown_clone = shutdown.clone();
 
-     // Run the mint in a separate task
 
-     let handle = tokio::spawn(async move {
 
-         // Create a future that resolves when the shutdown signal is received
 
-         let shutdown_future = async move {
 
-             shutdown_clone.notified().await;
 
-             println!("CLN mint shutdown signal received");
 
-         };
 
-         match cdk_mintd::run_mintd_with_shutdown(&temp_dir, &settings, shutdown_future, None, None)
 
-             .await
 
-         {
 
-             Ok(_) => println!("CLN mint exited normally"),
 
-             Err(e) => eprintln!("CLN mint exited with error: {e}"),
 
-         }
 
-     });
 
-     Ok(handle)
 
- }
 
- /// Start regtest LND mint using the library
 
- async fn start_lnd_mint(
 
-     temp_dir: &Path,
 
-     port: u16,
 
-     shutdown: Arc<Notify>,
 
- ) -> Result<tokio::task::JoinHandle<()>> {
 
-     let lnd_cert_file = temp_dir.join("lnd").join("two").join("tls.cert");
 
-     let lnd_macaroon_file = temp_dir
 
-         .join("lnd")
 
-         .join("two")
 
-         .join("data")
 
-         .join("chain")
 
-         .join("bitcoin")
 
-         .join("regtest")
 
-         .join("admin.macaroon");
 
-     let lnd_work_dir = temp_dir.join("lnd_mint");
 
-     // Create work directory for LND mint
 
-     fs::create_dir_all(&lnd_work_dir)?;
 
-     let lnd_config = cdk_mintd::config::Lnd {
 
-         address: "https://localhost:10010".to_string(),
 
-         cert_file: lnd_cert_file,
 
-         macaroon_file: lnd_macaroon_file,
 
-         fee_percent: 0.0,
 
-         reserve_fee_min: 0.into(),
 
-     };
 
-     // Create settings struct for LND mint using shared function
 
-     let settings = shared::create_lnd_settings(
 
-         port,
 
-         lnd_config,
 
-         "cattle gold bind busy sound reduce tone addict baby spend february strategy".to_string(),
 
-     );
 
-     println!("Starting LND mintd on port {port}");
 
-     let lnd_work_dir = lnd_work_dir.clone();
 
-     let shutdown_clone = shutdown.clone();
 
-     // Run the mint in a separate task
 
-     let handle = tokio::spawn(async move {
 
-         // Create a future that resolves when the shutdown signal is received
 
-         let shutdown_future = async move {
 
-             shutdown_clone.notified().await;
 
-             println!("LND mint shutdown signal received");
 
-         };
 
-         match cdk_mintd::run_mintd_with_shutdown(
 
-             &lnd_work_dir,
 
-             &settings,
 
-             shutdown_future,
 
-             None,
 
-             None,
 
-         )
 
-         .await
 
-         {
 
-             Ok(_) => println!("LND mint exited normally"),
 
-             Err(e) => eprintln!("LND mint exited with error: {e}"),
 
-         }
 
-     });
 
-     Ok(handle)
 
- }
 
- /// Start regtest LDK mint using the library
 
- async fn start_ldk_mint(
 
-     temp_dir: &Path,
 
-     port: u16,
 
-     shutdown: Arc<Notify>,
 
-     runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
 
- ) -> Result<tokio::task::JoinHandle<()>> {
 
-     let ldk_work_dir = temp_dir.join("ldk_mint");
 
-     // Create work directory for LDK mint
 
-     fs::create_dir_all(&ldk_work_dir)?;
 
-     // Configure LDK node for regtest
 
-     let ldk_config = cdk_mintd::config::LdkNode {
 
-         fee_percent: 0.0,
 
-         reserve_fee_min: 0.into(),
 
-         bitcoin_network: Some("regtest".to_string()),
 
-         // Use bitcoind RPC for regtest
 
-         chain_source_type: Some("bitcoinrpc".to_string()),
 
-         bitcoind_rpc_host: Some("127.0.0.1".to_string()),
 
-         bitcoind_rpc_port: Some(18443),
 
-         bitcoind_rpc_user: Some("testuser".to_string()),
 
-         bitcoind_rpc_password: Some("testpass".to_string()),
 
-         esplora_url: None,
 
-         storage_dir_path: Some(ldk_work_dir.to_string_lossy().to_string()),
 
-         ldk_node_host: Some("127.0.0.1".to_string()),
 
-         ldk_node_port: Some(port + 10), // Use a different port for the LDK node P2P connections
 
-         gossip_source_type: None,
 
-         rgs_url: None,
 
-         webserver_host: Some("127.0.0.1".to_string()),
 
-         webserver_port: Some(port + 1), // Use next port for web interface
 
-     };
 
-     // Create settings struct for LDK mint using a new shared function
 
-     let settings = create_ldk_settings(port, ldk_config, Mnemonic::generate(12)?.to_string());
 
-     println!("Starting LDK mintd on port {port}");
 
-     let ldk_work_dir = ldk_work_dir.clone();
 
-     let shutdown_clone = shutdown.clone();
 
-     // Run the mint in a separate task
 
-     let handle = tokio::spawn(async move {
 
-         // Create a future that resolves when the shutdown signal is received
 
-         let shutdown_future = async move {
 
-             shutdown_clone.notified().await;
 
-             println!("LDK mint shutdown signal received");
 
-         };
 
-         match cdk_mintd::run_mintd_with_shutdown(
 
-             &ldk_work_dir,
 
-             &settings,
 
-             shutdown_future,
 
-             None,
 
-             runtime,
 
-         )
 
-         .await
 
-         {
 
-             Ok(_) => println!("LDK mint exited normally"),
 
-             Err(e) => eprintln!("LDK mint exited with error: {e}"),
 
-         }
 
-     });
 
-     Ok(handle)
 
- }
 
- /// Create settings for an LDK mint
 
- fn create_ldk_settings(
 
-     port: u16,
 
-     ldk_config: cdk_mintd::config::LdkNode,
 
-     mnemonic: String,
 
- ) -> cdk_mintd::config::Settings {
 
-     cdk_mintd::config::Settings {
 
-         info: cdk_mintd::config::Info {
 
-             url: format!("http://127.0.0.1:{port}"),
 
-             listen_host: "127.0.0.1".to_string(),
 
-             listen_port: port,
 
-             seed: None,
 
-             mnemonic: Some(mnemonic),
 
-             signatory_url: None,
 
-             signatory_certs: None,
 
-             input_fee_ppk: None,
 
-             http_cache: cdk_axum::cache::Config::default(),
 
-             enable_swagger_ui: None,
 
-             logging: LoggingConfig::default(),
 
-         },
 
-         mint_info: cdk_mintd::config::MintInfo::default(),
 
-         ln: cdk_mintd::config::Ln {
 
-             ln_backend: cdk_mintd::config::LnBackend::LdkNode,
 
-             invoice_description: None,
 
-             min_mint: 1.into(),
 
-             max_mint: 500_000.into(),
 
-             min_melt: 1.into(),
 
-             max_melt: 500_000.into(),
 
-         },
 
-         cln: None,
 
-         lnbits: None,
 
-         lnd: None,
 
-         ldk_node: Some(ldk_config),
 
-         fake_wallet: None,
 
-         grpc_processor: None,
 
-         database: cdk_mintd::config::Database::default(),
 
-         mint_management_rpc: None,
 
-         auth: None,
 
-     }
 
- }
 
- fn main() -> Result<()> {
 
-     let rt = Arc::new(Runtime::new()?);
 
-     let rt_clone = Arc::clone(&rt);
 
-     rt.block_on(async {
 
-         let args = Args::parse();
 
-         // Initialize logging based on CLI arguments
 
-         shared::setup_logging(&args.common);
 
-         let temp_dir = shared::init_working_directory(&args.work_dir)?;
 
-         // Write environment variables to a .env file in the temp_dir
 
-         let mint_url_1 = format!("http://{}:{}", args.mint_addr, args.cln_port);
 
-         let mint_url_2 = format!("http://{}:{}", args.mint_addr, args.lnd_port);
 
-         let mint_url_3 = format!("http://{}:{}", args.mint_addr, args.ldk_port);
 
-         let env_vars: Vec<(&str, &str)> = vec![
 
-             ("CDK_TEST_MINT_URL", &mint_url_1),
 
-             ("CDK_TEST_MINT_URL_2", &mint_url_2),
 
-             ("CDK_TEST_MINT_URL_3", &mint_url_3),
 
-         ];
 
-         shared::write_env_file(&temp_dir, &env_vars)?;
 
-         // Start regtest
 
-         println!("Starting regtest...");
 
-         let shutdown_regtest = shared::create_shutdown_handler();
 
-         let shutdown_clone = shutdown_regtest.clone();
 
-         let (tx, rx) = oneshot::channel();
 
-         let shutdown_clone_one = Arc::clone(&shutdown_clone);
 
-         let ldk_work_dir = temp_dir.join("ldk_mint");
 
-         let cdk_ldk = CdkLdkNode::new(
 
-             bitcoin::Network::Regtest,
 
-             cdk_ldk_node::ChainSource::BitcoinRpc(cdk_ldk_node::BitcoinRpcConfig {
 
-                 host: "127.0.0.1".to_string(),
 
-                 port: 18443,
 
-                 user: "testuser".to_string(),
 
-                 password: "testpass".to_string(),
 
-             }),
 
-             cdk_ldk_node::GossipSource::P2P,
 
-             ldk_work_dir.to_string_lossy().to_string(),
 
-             cdk_common::common::FeeReserve {
 
-                 min_fee_reserve: Amount::ZERO,
 
-                 percent_fee_reserve: 0.0,
 
-             },
 
-             vec![SocketAddress::TcpIpV4 {
 
-                 addr: [127, 0, 0, 1],
 
-                 port: 8092,
 
-             }],
 
-             Some(Arc::clone(&rt_clone)),
 
-         )?;
 
-         let inner_node = cdk_ldk.node();
 
-         let temp_dir_clone = temp_dir.clone();
 
-         let shutdown_clone_two = Arc::clone(&shutdown_clone);
 
-         tokio::spawn(async move {
 
-             start_regtest_end(&temp_dir_clone, tx, shutdown_clone_two, Some(inner_node))
 
-                 .await
 
-                 .expect("Error starting regtest");
 
-         });
 
-         match timeout(Duration::from_secs(300), rx).await {
 
-             Ok(k) => {
 
-                 k?;
 
-                 tracing::info!("Regtest set up");
 
-             }
 
-             Err(_) => {
 
-                 tracing::error!("regtest setup timed out after 5 minutes");
 
-                 anyhow::bail!("Could not set up regtest");
 
-             }
 
-         }
 
-         println!("lnd port: {}", args.ldk_port);
 
-         // Start LND mint
 
-         let lnd_handle = start_lnd_mint(&temp_dir, args.lnd_port, shutdown_clone.clone()).await?;
 
-         // Start LDK mint
 
-         let ldk_handle = start_ldk_mint(
 
-             &temp_dir,
 
-             args.ldk_port,
 
-             shutdown_clone.clone(),
 
-             Some(rt_clone),
 
-         )
 
-         .await?;
 
-         // Start CLN mint
 
-         let cln_handle = start_cln_mint(&temp_dir, args.cln_port, shutdown_clone.clone()).await?;
 
-         let cancel_token = Arc::new(CancellationToken::new());
 
-         // Set up Ctrl+C handler before waiting for mints to be ready
 
-         let ctrl_c_token = Arc::clone(&cancel_token);
 
-         let s_u = shutdown_clone.clone();
 
-         tokio::spawn(async move {
 
-             signal::ctrl_c()
 
-                 .await
 
-                 .expect("failed to install CTRL+C handler");
 
-             tracing::info!("Shutdown signal received during mint setup");
 
-             println!("\nReceived Ctrl+C, shutting down...");
 
-             ctrl_c_token.cancel();
 
-             s_u.notify_waiters();
 
-         });
 
-         match tokio::try_join!(
 
-             shared::wait_for_mint_ready_with_shutdown(
 
-                 args.lnd_port,
 
-                 100,
 
-                 Arc::clone(&cancel_token)
 
-             ),
 
-             shared::wait_for_mint_ready_with_shutdown(
 
-                 args.ldk_port,
 
-                 100,
 
-                 Arc::clone(&cancel_token)
 
-             ),
 
-             shared::wait_for_mint_ready_with_shutdown(
 
-                 args.cln_port,
 
-                 100,
 
-                 Arc::clone(&cancel_token)
 
-             ),
 
-         ) {
 
-             Ok(_) => println!("All mints are ready!"),
 
-             Err(e) => {
 
-                 if cancel_token.is_cancelled() {
 
-                     bail!("Startup canceled by user");
 
-                 }
 
-                 eprintln!("Error waiting for mints to be ready: {e}");
 
-                 return Err(e);
 
-             }
 
-         }
 
-         if cancel_token.is_cancelled() {
 
-             bail!("Token canceled");
 
-         }
 
-         println!("All regtest mints started successfully!");
 
-         println!("CLN mint: http://{}:{}", args.mint_addr, args.cln_port);
 
-         println!("LND mint: http://{}:{}", args.mint_addr, args.lnd_port);
 
-         println!("LDK mint: http://{}:{}", args.mint_addr, args.ldk_port);
 
-         shared::display_mint_info(args.cln_port, &temp_dir, &args.database_type); // Using CLN port for display
 
-         println!();
 
-         println!("Environment variables set:");
 
-         println!(
 
-             "  CDK_TEST_MINT_URL=http://{}:{}",
 
-             args.mint_addr, args.cln_port
 
-         );
 
-         println!(
 
-             "  CDK_TEST_MINT_URL_2=http://{}:{}",
 
-             args.mint_addr, args.lnd_port
 
-         );
 
-         println!(
 
-             "  CDK_TEST_MINT_URL_3=http://{}:{}",
 
-             args.mint_addr, args.ldk_port
 
-         );
 
-         println!("  CDK_ITESTS_DIR={}", temp_dir.display());
 
-         println!();
 
-         println!("You can now run integration tests with:");
 
-         println!("  cargo test -p cdk-integration-tests --test regtest");
 
-         println!("  cargo test -p cdk-integration-tests --test happy_path_mint_wallet");
 
-         println!("  etc.");
 
-         println!();
 
-         println!("Press Ctrl+C to stop the mints...");
 
-         // Create a future to wait for either Ctrl+C signal or unexpected mint termination
 
-         let shutdown_future = async {
 
-             // Wait for either SIGINT (Ctrl+C) or SIGTERM
 
-             let mut sigterm = signal::unix::signal(SignalKind::terminate())
 
-                 .expect("Failed to create SIGTERM signal handler");
 
-             tokio::select! {
 
-                 _ = signal::ctrl_c() => {
 
-                     tracing::info!("Received SIGINT (Ctrl+C), shutting down mints...");
 
-                 }
 
-                 _ = sigterm.recv() => {
 
-                     tracing::info!("Received SIGTERM, shutting down mints...");
 
-                 }
 
-             }
 
-             println!("\nShutdown signal received, shutting down mints...");
 
-             shutdown_clone.notify_waiters();
 
-         };
 
-         // Monitor mint handles for unexpected termination
 
-         let monitor_mints = async {
 
-             loop {
 
-                 if cln_handle.is_finished() {
 
-                     println!("CLN mint finished unexpectedly");
 
-                     return;
 
-                 }
 
-                 if lnd_handle.is_finished() {
 
-                     println!("LND mint finished unexpectedly");
 
-                     return;
 
-                 }
 
-                 if ldk_handle.is_finished() {
 
-                     println!("LDK mint finished unexpectedly");
 
-                     return;
 
-                 }
 
-                 tokio::time::sleep(Duration::from_millis(100)).await;
 
-             }
 
-         };
 
-         // Wait for either shutdown signal or mint termination
 
-         tokio::select! {
 
-             _ = shutdown_clone_one.notified() => {
 
-                 println!("Shutdown signal received, waiting for mints to stop...");
 
-             }
 
-             _ = monitor_mints => {
 
-                 println!("One or more mints terminated unexpectedly");
 
-             }
 
-             _ = shutdown_future => ()
 
-         }
 
-         // Wait for mints to finish gracefully
 
-         if let Err(e) = tokio::try_join!(ldk_handle, cln_handle, lnd_handle) {
 
-             eprintln!("Error waiting for mints to shut down: {e}");
 
-         }
 
-         println!("All services shut down successfully");
 
-         Ok(())
 
-     })
 
- }
 
 
  |