init_regtest.rs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. use std::collections::HashMap;
  2. use std::env;
  3. use std::path::PathBuf;
  4. use std::sync::Arc;
  5. use anyhow::Result;
  6. use axum::Router;
  7. use bip39::Mnemonic;
  8. use cdk::cdk_database::{self, MintDatabase};
  9. use cdk::cdk_lightning::MintLightning;
  10. use cdk::mint::{FeeReserve, Mint};
  11. use cdk::nuts::{CurrencyUnit, MintInfo};
  12. use cdk::types::{LnKey, QuoteTTL};
  13. use cdk_cln::Cln as CdkCln;
  14. use ln_regtest_rs::bitcoin_client::BitcoinClient;
  15. use ln_regtest_rs::bitcoind::Bitcoind;
  16. use ln_regtest_rs::cln::Clnd;
  17. use ln_regtest_rs::cln_client::ClnClient;
  18. use ln_regtest_rs::lnd::Lnd;
  19. use ln_regtest_rs::lnd_client::LndClient;
  20. use tokio::sync::Notify;
  21. use tower_http::cors::CorsLayer;
  22. use tracing_subscriber::EnvFilter;
  23. const BITCOIND_ADDR: &str = "127.0.0.1:18443";
  24. const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
  25. const ZMQ_RAW_TX: &str = "tcp://127.0.0.1:28333";
  26. const BITCOIN_RPC_USER: &str = "testuser";
  27. const BITCOIN_RPC_PASS: &str = "testpass";
  28. const CLN_ADDR: &str = "127.0.0.1:19846";
  29. const LND_ADDR: &str = "0.0.0.0:18444";
  30. const LND_RPC_ADDR: &str = "https://127.0.0.1:10009";
  31. const BITCOIN_DIR: &str = "bitcoin";
  32. const CLN_DIR: &str = "cln";
  33. const LND_DIR: &str = "lnd";
  34. pub fn get_mint_addr() -> String {
  35. env::var("cdk_itests_mint_addr").expect("Temp dir set")
  36. }
  37. pub fn get_mint_port() -> u16 {
  38. let dir = env::var("cdk_itests_mint_port").expect("Temp dir set");
  39. dir.parse().unwrap()
  40. }
  41. pub fn get_mint_url() -> String {
  42. format!("http://{}:{}", get_mint_addr(), get_mint_port())
  43. }
  44. pub fn get_mint_ws_url() -> String {
  45. format!("ws://{}:{}/v1/ws", get_mint_addr(), get_mint_port())
  46. }
  47. pub fn get_temp_dir() -> PathBuf {
  48. let dir = env::var("cdk_itests").expect("Temp dir set");
  49. std::fs::create_dir_all(&dir).unwrap();
  50. dir.parse().expect("Valid path buf")
  51. }
  52. pub fn get_bitcoin_dir() -> PathBuf {
  53. let dir = get_temp_dir().join(BITCOIN_DIR);
  54. std::fs::create_dir_all(&dir).unwrap();
  55. dir
  56. }
  57. pub fn init_bitcoind() -> Bitcoind {
  58. Bitcoind::new(
  59. get_bitcoin_dir(),
  60. BITCOIND_ADDR.parse().unwrap(),
  61. BITCOIN_RPC_USER.to_string(),
  62. BITCOIN_RPC_PASS.to_string(),
  63. ZMQ_RAW_BLOCK.to_string(),
  64. ZMQ_RAW_TX.to_string(),
  65. )
  66. }
  67. pub fn init_bitcoin_client() -> Result<BitcoinClient> {
  68. BitcoinClient::new(
  69. "wallet".to_string(),
  70. BITCOIND_ADDR.into(),
  71. None,
  72. Some(BITCOIN_RPC_USER.to_string()),
  73. Some(BITCOIN_RPC_PASS.to_string()),
  74. )
  75. }
  76. pub fn get_cln_dir() -> PathBuf {
  77. let dir = get_temp_dir().join(CLN_DIR);
  78. std::fs::create_dir_all(&dir).unwrap();
  79. dir
  80. }
  81. pub fn init_cln() -> Clnd {
  82. Clnd::new(
  83. get_bitcoin_dir(),
  84. get_cln_dir(),
  85. CLN_ADDR.to_string().parse().unwrap(),
  86. BITCOIN_RPC_USER.to_string(),
  87. BITCOIN_RPC_PASS.to_string(),
  88. )
  89. }
  90. pub async fn init_cln_client() -> Result<ClnClient> {
  91. ClnClient::new(get_cln_dir(), None).await
  92. }
  93. pub fn get_lnd_dir() -> PathBuf {
  94. let dir = get_temp_dir().join(LND_DIR);
  95. std::fs::create_dir_all(&dir).unwrap();
  96. dir
  97. }
  98. pub async fn init_lnd() -> Lnd {
  99. Lnd::new(
  100. get_bitcoin_dir(),
  101. get_lnd_dir(),
  102. LND_ADDR.parse().unwrap(),
  103. BITCOIN_RPC_USER.to_string(),
  104. BITCOIN_RPC_PASS.to_string(),
  105. ZMQ_RAW_BLOCK.to_string(),
  106. ZMQ_RAW_TX.to_string(),
  107. )
  108. }
  109. pub async fn init_lnd_client() -> Result<LndClient> {
  110. let lnd_dir = get_lnd_dir();
  111. let cert_file = lnd_dir.join("tls.cert");
  112. let macaroon_file = lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon");
  113. LndClient::new(LND_RPC_ADDR.parse().unwrap(), cert_file, macaroon_file).await
  114. }
  115. pub async fn create_cln_backend(cln_client: &ClnClient) -> Result<CdkCln> {
  116. let rpc_path = cln_client.rpc_path.clone();
  117. let fee_reserve = FeeReserve {
  118. min_fee_reserve: 1.into(),
  119. percent_fee_reserve: 1.0,
  120. };
  121. Ok(CdkCln::new(rpc_path, fee_reserve).await?)
  122. }
  123. pub async fn create_mint<D>(
  124. database: D,
  125. ln_backends: HashMap<
  126. LnKey,
  127. Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>,
  128. >,
  129. ) -> Result<Mint>
  130. where
  131. D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
  132. {
  133. let nuts = cdk::nuts::Nuts::new()
  134. .nut07(true)
  135. .nut08(true)
  136. .nut09(true)
  137. .nut10(true)
  138. .nut11(true)
  139. .nut12(true)
  140. .nut14(true);
  141. let mint_info = MintInfo::new().nuts(nuts);
  142. let mnemonic = Mnemonic::generate(12)?;
  143. let mut supported_units: HashMap<CurrencyUnit, (u64, u8)> = HashMap::new();
  144. supported_units.insert(CurrencyUnit::Sat, (0, 32));
  145. let quote_ttl = QuoteTTL::new(10000, 10000);
  146. let mint = Mint::new(
  147. &get_mint_url(),
  148. &mnemonic.to_seed_normalized(""),
  149. mint_info,
  150. quote_ttl,
  151. Arc::new(database),
  152. ln_backends,
  153. supported_units,
  154. HashMap::new(),
  155. )
  156. .await?;
  157. Ok(mint)
  158. }
  159. pub async fn start_cln_mint<D>(addr: &str, port: u16, database: D) -> Result<()>
  160. where
  161. D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
  162. {
  163. let default_filter = "debug";
  164. let sqlx_filter = "sqlx=warn";
  165. let hyper_filter = "hyper=warn";
  166. let env_filter = EnvFilter::new(format!(
  167. "{},{},{}",
  168. default_filter, sqlx_filter, hyper_filter
  169. ));
  170. // Parse input
  171. tracing_subscriber::fmt().with_env_filter(env_filter).init();
  172. let cln_client = init_cln_client().await?;
  173. let cln_backend = create_cln_backend(&cln_client).await?;
  174. let mut ln_backends: HashMap<
  175. LnKey,
  176. Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>,
  177. > = HashMap::new();
  178. ln_backends.insert(
  179. LnKey::new(CurrencyUnit::Sat, cdk::nuts::PaymentMethod::Bolt11),
  180. Arc::new(cln_backend),
  181. );
  182. let mint = create_mint(database, ln_backends.clone()).await?;
  183. let cache_time_to_live = 3600;
  184. let cache_time_to_idle = 3600;
  185. let mint_arc = Arc::new(mint);
  186. let v1_service = cdk_axum::create_mint_router(
  187. Arc::clone(&mint_arc),
  188. cache_time_to_live,
  189. cache_time_to_idle,
  190. )
  191. .await
  192. .unwrap();
  193. let mint_service = Router::new()
  194. .merge(v1_service)
  195. .layer(CorsLayer::permissive());
  196. let mint = Arc::clone(&mint_arc);
  197. let shutdown = Arc::new(Notify::new());
  198. tokio::spawn({
  199. let shutdown = Arc::clone(&shutdown);
  200. async move { mint.wait_for_paid_invoices(shutdown).await }
  201. });
  202. println!("Staring Axum server");
  203. axum::Server::bind(&format!("{}:{}", addr, port).as_str().parse().unwrap())
  204. .serve(mint_service.into_make_service())
  205. .await?;
  206. Ok(())
  207. }
  208. pub async fn fund_ln(
  209. bitcoin_client: &BitcoinClient,
  210. cln_client: &ClnClient,
  211. lnd_client: &LndClient,
  212. ) -> Result<()> {
  213. let lnd_address = lnd_client.get_new_address().await?;
  214. bitcoin_client.send_to_address(&lnd_address, 2_000_000)?;
  215. let cln_address = cln_client.get_new_address().await?;
  216. bitcoin_client.send_to_address(&cln_address, 2_000_000)?;
  217. let mining_address = bitcoin_client.get_new_address()?;
  218. bitcoin_client.generate_blocks(&mining_address, 200)?;
  219. cln_client.wait_chain_sync().await?;
  220. lnd_client.wait_chain_sync().await?;
  221. Ok(())
  222. }
  223. pub async fn open_channel(
  224. bitcoin_client: &BitcoinClient,
  225. cln_client: &ClnClient,
  226. lnd_client: &LndClient,
  227. ) -> Result<()> {
  228. let cln_info = cln_client.get_info().await?;
  229. let cln_pubkey = cln_info.id;
  230. let cln_address = "127.0.0.1";
  231. let cln_port = 19846;
  232. lnd_client
  233. .connect(cln_pubkey.to_string(), cln_address.to_string(), cln_port)
  234. .await
  235. .unwrap();
  236. lnd_client
  237. .open_channel(1_500_000, &cln_pubkey.to_string(), Some(750_000))
  238. .await
  239. .unwrap();
  240. let mine_to_address = bitcoin_client.get_new_address()?;
  241. bitcoin_client.generate_blocks(&mine_to_address, 10)?;
  242. cln_client.wait_chain_sync().await?;
  243. lnd_client.wait_chain_sync().await?;
  244. cln_client.wait_channels_active().await?;
  245. lnd_client.wait_channels_active().await?;
  246. Ok(())
  247. }