init_regtest.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. use std::env;
  2. use std::net::Ipv4Addr;
  3. use std::path::{Path, PathBuf};
  4. use std::sync::Arc;
  5. use anyhow::Result;
  6. use cdk::types::FeeReserve;
  7. use cdk_cln::Cln as CdkCln;
  8. use cdk_common::database::mint::DynMintKVStore;
  9. use cdk_lnd::Lnd as CdkLnd;
  10. use cdk_sqlite::mint::memory;
  11. use ldk_node::lightning::ln::msgs::SocketAddress;
  12. use ldk_node::Node;
  13. use ln_regtest_rs::bitcoin_client::BitcoinClient;
  14. use ln_regtest_rs::bitcoind::Bitcoind;
  15. use ln_regtest_rs::cln::Clnd;
  16. use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
  17. use ln_regtest_rs::lnd::Lnd;
  18. use tokio::sync::oneshot::Sender;
  19. use tokio::sync::Notify;
  20. pub const BITCOIND_ADDR: &str = "127.0.0.1:18443";
  21. pub const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
  22. pub const ZMQ_RAW_TX: &str = "tcp://127.0.0.1:28333";
  23. pub const BITCOIN_RPC_USER: &str = "testuser";
  24. pub const BITCOIN_RPC_PASS: &str = "testpass";
  25. const BITCOIN_DIR: &str = "bitcoin";
  26. pub const LND_ADDR: &str = "0.0.0.0:18449";
  27. pub const LND_RPC_ADDR: &str = "localhost:10009";
  28. pub const LND_TWO_ADDR: &str = "0.0.0.0:18410";
  29. pub const LND_TWO_RPC_ADDR: &str = "localhost:10010";
  30. pub const CLN_ADDR: &str = "127.0.0.1:19846";
  31. pub const CLN_TWO_ADDR: &str = "127.0.0.1:19847";
  32. /// Configuration for regtest environment
  33. pub struct RegtestConfig {
  34. pub mint_addr: String,
  35. pub cln_port: u16,
  36. pub lnd_port: u16,
  37. pub temp_dir: PathBuf,
  38. }
  39. impl Default for RegtestConfig {
  40. fn default() -> Self {
  41. Self {
  42. mint_addr: "127.0.0.1".to_string(),
  43. cln_port: 8085,
  44. lnd_port: 8087,
  45. temp_dir: std::env::temp_dir().join("cdk-itests-default"),
  46. }
  47. }
  48. }
  49. pub fn get_mint_url_with_config(config: &RegtestConfig, which: &str) -> String {
  50. let port = match which {
  51. "0" => config.cln_port,
  52. "1" => config.lnd_port,
  53. _ => panic!("Unknown mint identifier: {which}"),
  54. };
  55. format!("http://{}:{}", config.mint_addr, port)
  56. }
  57. pub fn get_mint_ws_url_with_config(config: &RegtestConfig, which: &str) -> String {
  58. let port = match which {
  59. "0" => config.cln_port,
  60. "1" => config.lnd_port,
  61. _ => panic!("Unknown mint identifier: {which}"),
  62. };
  63. format!("ws://{}:{}/v1/ws", config.mint_addr, port)
  64. }
  65. pub fn get_temp_dir() -> PathBuf {
  66. let dir = env::var("CDK_ITESTS_DIR").expect("Temp dir not set");
  67. std::fs::create_dir_all(&dir).unwrap();
  68. dir.parse().expect("Valid path buf")
  69. }
  70. pub fn get_temp_dir_with_config(config: &RegtestConfig) -> &PathBuf {
  71. &config.temp_dir
  72. }
  73. pub fn get_bitcoin_dir(temp_dir: &Path) -> PathBuf {
  74. let dir = temp_dir.join(BITCOIN_DIR);
  75. std::fs::create_dir_all(&dir).unwrap();
  76. dir
  77. }
  78. pub fn init_bitcoind(work_dir: &Path) -> Bitcoind {
  79. Bitcoind::new(
  80. get_bitcoin_dir(work_dir),
  81. BITCOIND_ADDR.parse().unwrap(),
  82. BITCOIN_RPC_USER.to_string(),
  83. BITCOIN_RPC_PASS.to_string(),
  84. ZMQ_RAW_BLOCK.to_string(),
  85. ZMQ_RAW_TX.to_string(),
  86. )
  87. }
  88. pub fn init_bitcoin_client() -> Result<BitcoinClient> {
  89. BitcoinClient::new(
  90. "wallet".to_string(),
  91. BITCOIND_ADDR.into(),
  92. None,
  93. Some(BITCOIN_RPC_USER.to_string()),
  94. Some(BITCOIN_RPC_PASS.to_string()),
  95. )
  96. }
  97. pub fn get_cln_dir(work_dir: &Path, name: &str) -> PathBuf {
  98. let dir = work_dir.join("cln").join(name);
  99. std::fs::create_dir_all(&dir).unwrap();
  100. dir
  101. }
  102. pub fn get_lnd_dir(work_dir: &Path, name: &str) -> PathBuf {
  103. let dir = work_dir.join("lnd").join(name);
  104. std::fs::create_dir_all(&dir).unwrap();
  105. dir
  106. }
  107. pub fn get_lnd_cert_file_path(lnd_dir: &Path) -> PathBuf {
  108. lnd_dir.join("tls.cert")
  109. }
  110. pub fn get_lnd_macaroon_path(lnd_dir: &Path) -> PathBuf {
  111. lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon")
  112. }
  113. pub async fn init_lnd(
  114. work_dir: &Path,
  115. lnd_dir: PathBuf,
  116. lnd_addr: &str,
  117. lnd_rpc_addr: &str,
  118. ) -> Lnd {
  119. Lnd::new(
  120. get_bitcoin_dir(work_dir),
  121. lnd_dir,
  122. lnd_addr.parse().unwrap(),
  123. lnd_rpc_addr.to_string(),
  124. BITCOIN_RPC_USER.to_string(),
  125. BITCOIN_RPC_PASS.to_string(),
  126. ZMQ_RAW_BLOCK.to_string(),
  127. ZMQ_RAW_TX.to_string(),
  128. )
  129. }
  130. pub fn generate_block(bitcoin_client: &BitcoinClient) -> Result<()> {
  131. let mine_to_address = bitcoin_client.get_new_address()?;
  132. let blocks = 10;
  133. tracing::info!("Mining {blocks} blocks to {mine_to_address}");
  134. bitcoin_client.generate_blocks(&mine_to_address, 10)?;
  135. Ok(())
  136. }
  137. pub async fn create_cln_backend(cln_client: &ClnClient) -> Result<CdkCln> {
  138. let rpc_path = cln_client.rpc_path.clone();
  139. let fee_reserve = FeeReserve {
  140. min_fee_reserve: 1.into(),
  141. percent_fee_reserve: 1.0,
  142. };
  143. let kv_store: DynMintKVStore = Arc::new(memory::empty().await?);
  144. Ok(CdkCln::new(rpc_path, fee_reserve, kv_store).await?)
  145. }
  146. pub async fn create_lnd_backend(lnd_client: &LndClient) -> Result<CdkLnd> {
  147. let fee_reserve = FeeReserve {
  148. min_fee_reserve: 1.into(),
  149. percent_fee_reserve: 1.0,
  150. };
  151. let kv_store: DynMintKVStore = Arc::new(memory::empty().await?);
  152. Ok(CdkLnd::new(
  153. lnd_client.address.clone(),
  154. lnd_client.cert_file.clone(),
  155. lnd_client.macaroon_file.clone(),
  156. fee_reserve,
  157. kv_store,
  158. )
  159. .await?)
  160. }
  161. pub async fn fund_ln<C>(bitcoin_client: &BitcoinClient, ln_client: &C) -> Result<()>
  162. where
  163. C: LightningClient,
  164. {
  165. let ln_address = ln_client.get_new_onchain_address().await?;
  166. bitcoin_client.send_to_address(&ln_address, 5_000_000)?;
  167. ln_client.wait_chain_sync().await?;
  168. let mine_to_address = bitcoin_client.get_new_address()?;
  169. bitcoin_client.generate_blocks(&mine_to_address, 10)?;
  170. ln_client.wait_chain_sync().await?;
  171. Ok(())
  172. }
  173. pub async fn open_channel<C1, C2>(cln_client: &C1, lnd_client: &C2) -> Result<()>
  174. where
  175. C1: LightningClient,
  176. C2: LightningClient,
  177. {
  178. let cln_info = cln_client.get_connect_info().await?;
  179. let cln_pubkey = cln_info.pubkey;
  180. let cln_address = cln_info.address;
  181. let cln_port = cln_info.port;
  182. lnd_client
  183. .connect_peer(cln_pubkey.to_string(), cln_address.to_string(), cln_port)
  184. .await
  185. .unwrap();
  186. cln_client.wait_chain_sync().await?;
  187. lnd_client.wait_chain_sync().await?;
  188. lnd_client
  189. .open_channel(1_500_000, &cln_pubkey.to_string(), Some(750_000))
  190. .await
  191. .unwrap();
  192. Ok(())
  193. }
  194. pub async fn start_regtest_end(
  195. work_dir: &Path,
  196. sender: Sender<()>,
  197. notify: Arc<Notify>,
  198. ldk_node: Option<Arc<Node>>,
  199. ) -> anyhow::Result<()> {
  200. let mut bitcoind = init_bitcoind(work_dir);
  201. bitcoind.start_bitcoind()?;
  202. let bitcoin_client = init_bitcoin_client()?;
  203. bitcoin_client.create_wallet().ok();
  204. bitcoin_client.load_wallet()?;
  205. let new_add = bitcoin_client.get_new_address()?;
  206. bitcoin_client.generate_blocks(&new_add, 200).unwrap();
  207. let cln_one_dir = get_cln_dir(work_dir, "one");
  208. let mut clnd = Clnd::new(
  209. get_bitcoin_dir(work_dir),
  210. cln_one_dir.clone(),
  211. CLN_ADDR.into(),
  212. BITCOIN_RPC_USER.to_string(),
  213. BITCOIN_RPC_PASS.to_string(),
  214. );
  215. clnd.start_clnd()?;
  216. let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
  217. cln_client.wait_chain_sync().await.unwrap();
  218. fund_ln(&bitcoin_client, &cln_client).await.unwrap();
  219. // Create second cln
  220. let cln_two_dir = get_cln_dir(work_dir, "two");
  221. let mut clnd_two = Clnd::new(
  222. get_bitcoin_dir(work_dir),
  223. cln_two_dir.clone(),
  224. CLN_TWO_ADDR.into(),
  225. BITCOIN_RPC_USER.to_string(),
  226. BITCOIN_RPC_PASS.to_string(),
  227. );
  228. clnd_two.start_clnd()?;
  229. let cln_two_client = ClnClient::new(cln_two_dir.clone(), None).await?;
  230. cln_two_client.wait_chain_sync().await.unwrap();
  231. fund_ln(&bitcoin_client, &cln_two_client).await.unwrap();
  232. let lnd_dir = get_lnd_dir(work_dir, "one");
  233. println!("{}", lnd_dir.display());
  234. let mut lnd = init_lnd(work_dir, lnd_dir.clone(), LND_ADDR, LND_RPC_ADDR).await;
  235. lnd.start_lnd().unwrap();
  236. tracing::info!("Started lnd node");
  237. let lnd_client = LndClient::new(
  238. format!("https://{LND_RPC_ADDR}"),
  239. get_lnd_cert_file_path(&lnd_dir),
  240. get_lnd_macaroon_path(&lnd_dir),
  241. )
  242. .await?;
  243. lnd_client.wait_chain_sync().await.unwrap();
  244. if let Some(node) = ldk_node.as_ref() {
  245. tracing::info!("Starting ldk node");
  246. node.start()?;
  247. let addr = node.onchain_payment().new_address().unwrap();
  248. bitcoin_client.send_to_address(&addr.to_string(), 5_000_000)?;
  249. }
  250. fund_ln(&bitcoin_client, &lnd_client).await.unwrap();
  251. // create second lnd node
  252. let work_dir = get_temp_dir();
  253. let lnd_two_dir = get_lnd_dir(&work_dir, "two");
  254. let mut lnd_two = init_lnd(
  255. &work_dir,
  256. lnd_two_dir.clone(),
  257. LND_TWO_ADDR,
  258. LND_TWO_RPC_ADDR,
  259. )
  260. .await;
  261. lnd_two.start_lnd().unwrap();
  262. tracing::info!("Started second lnd node");
  263. let lnd_two_client = LndClient::new(
  264. format!("https://{LND_TWO_RPC_ADDR}"),
  265. get_lnd_cert_file_path(&lnd_two_dir),
  266. get_lnd_macaroon_path(&lnd_two_dir),
  267. )
  268. .await?;
  269. lnd_two_client.wait_chain_sync().await.unwrap();
  270. fund_ln(&bitcoin_client, &lnd_two_client).await.unwrap();
  271. // Open channels concurrently
  272. // Open channels
  273. {
  274. open_channel(&cln_client, &lnd_client).await.unwrap();
  275. tracing::info!("Opened channel between cln and lnd one");
  276. generate_block(&bitcoin_client)?;
  277. // open_channel(&bitcoin_client, &cln_client, &cln_two_client)
  278. // .await
  279. // .unwrap();
  280. // tracing::info!("Opened channel between cln and cln two");
  281. open_channel(&lnd_client, &lnd_two_client).await.unwrap();
  282. tracing::info!("Opened channel between lnd and lnd two");
  283. generate_block(&bitcoin_client)?;
  284. // open_channel(&cln_client, &lnd_two_client).await.unwrap();
  285. // tracing::info!("Opened channel between cln and lnd two");
  286. open_channel(&cln_two_client, &lnd_client).await.unwrap();
  287. tracing::info!("Opened channel between cln two and lnd");
  288. generate_block(&bitcoin_client)?;
  289. open_channel(&cln_client, &lnd_two_client).await.unwrap();
  290. tracing::info!("Opened channel between cln and lnd two");
  291. generate_block(&bitcoin_client)?;
  292. if let Some(node) = ldk_node {
  293. let pubkey = node.node_id();
  294. let listen_addr = node.listening_addresses();
  295. let listen_addr = listen_addr.as_ref().unwrap().first().unwrap();
  296. let (listen_addr, port) = match listen_addr {
  297. SocketAddress::TcpIpV4 { addr, port } => (Ipv4Addr::from(*addr).to_string(), port),
  298. _ => panic!(),
  299. };
  300. tracing::info!("Opening channel from cln to ldk");
  301. cln_client
  302. .connect_peer(pubkey.to_string(), listen_addr.clone(), *port)
  303. .await?;
  304. cln_client
  305. .open_channel(1_500_000, &pubkey.to_string(), Some(750_000))
  306. .await
  307. .unwrap();
  308. generate_block(&bitcoin_client)?;
  309. let cln_two_info = cln_two_client.get_connect_info().await?;
  310. cln_client
  311. .connect_peer(cln_two_info.pubkey, listen_addr.clone(), cln_two_info.port)
  312. .await?;
  313. tracing::info!("Opening channel from lnd to ldk");
  314. let cln_info = cln_client.get_connect_info().await?;
  315. node.connect(
  316. cln_info.pubkey.parse()?,
  317. SocketAddress::TcpIpV4 {
  318. addr: cln_info
  319. .address
  320. .split('.')
  321. .map(|part| part.parse())
  322. .collect::<Result<Vec<u8>, _>>()?
  323. .try_into()
  324. .unwrap(),
  325. port: cln_info.port,
  326. },
  327. true,
  328. )?;
  329. let lnd_info = lnd_client.get_connect_info().await?;
  330. node.connect(
  331. lnd_info.pubkey.parse()?,
  332. SocketAddress::TcpIpV4 {
  333. addr: [127, 0, 0, 1],
  334. port: lnd_info.port,
  335. },
  336. true,
  337. )?;
  338. // lnd_client
  339. // .open_channel(1_500_000, &pubkey.to_string(), Some(750_000))
  340. // .await
  341. // .unwrap();
  342. generate_block(&bitcoin_client)?;
  343. lnd_client.wait_chain_sync().await?;
  344. node.open_announced_channel(
  345. lnd_info.pubkey.parse()?,
  346. SocketAddress::TcpIpV4 {
  347. addr: [127, 0, 0, 1],
  348. port: lnd_info.port,
  349. },
  350. 1_000_000,
  351. Some(500_000_000),
  352. None,
  353. )?;
  354. generate_block(&bitcoin_client)?;
  355. tracing::info!("Ldk channels opened");
  356. node.sync_wallets()?;
  357. tracing::info!("Ldk wallet synced");
  358. cln_client.wait_channels_active().await?;
  359. lnd_client.wait_channels_active().await?;
  360. node.stop()?;
  361. } else {
  362. cln_client.wait_channels_active().await?;
  363. lnd_client.wait_channels_active().await?;
  364. generate_block(&bitcoin_client)?;
  365. }
  366. }
  367. tracing::info!("Regtest channels active");
  368. // Send notification that regtest set up is complete
  369. sender.send(()).expect("Could not send oneshot");
  370. // Wait until we are told to shutdown
  371. // If we return the bitcoind, lnd, and cln will be dropped and shutdown
  372. notify.notified().await;
  373. Ok(())
  374. }