mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-06 13:45:53 +01:00
Merge pull request #555 from thesimplekid/regtest_muli_mint
Add LND mint to regtest itests
This commit is contained in:
@@ -12,6 +12,7 @@ use cdk::nuts::{
|
||||
};
|
||||
use cdk::util::unix_time;
|
||||
use paste::paste;
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::ws::main_websocket;
|
||||
@@ -232,6 +233,7 @@ pub async fn post_mint_bolt11(
|
||||
(status = 500, description = "Server error", body = ErrorResponse, content_type = "application/json")
|
||||
)
|
||||
))]
|
||||
#[instrument(skip_all)]
|
||||
/// Request a quote for melting tokens
|
||||
pub async fn post_melt_bolt11_quote(
|
||||
State(state): State<MintState>,
|
||||
@@ -261,6 +263,7 @@ pub async fn post_melt_bolt11_quote(
|
||||
/// Get melt quote by ID
|
||||
///
|
||||
/// Get melt quote state.
|
||||
#[instrument(skip_all)]
|
||||
pub async fn get_check_melt_bolt11_quote(
|
||||
State(state): State<MintState>,
|
||||
Path(quote_id): Path<Uuid>,
|
||||
@@ -290,6 +293,7 @@ pub async fn get_check_melt_bolt11_quote(
|
||||
/// Melt tokens for a Bitcoin payment that the mint will make for the user in exchange
|
||||
///
|
||||
/// Requests tokens to be destroyed and sent out via Lightning.
|
||||
#[instrument(skip_all)]
|
||||
pub async fn post_melt_bolt11(
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MeltBolt11Request<Uuid>>,
|
||||
|
||||
@@ -21,6 +21,7 @@ bip39 = { version = "2.0", features = ["rand"] }
|
||||
anyhow = "1"
|
||||
cdk = { path = "../cdk", features = ["mint", "wallet"] }
|
||||
cdk-cln = { path = "../cdk-cln" }
|
||||
cdk-lnd = { path = "../cdk-lnd" }
|
||||
cdk-axum = { path = "../cdk-axum" }
|
||||
cdk-sqlite = { path = "../cdk-sqlite" }
|
||||
cdk-redb = { path = "../cdk-redb" }
|
||||
@@ -34,7 +35,7 @@ uuid = { version = "1", features = ["v4"] }
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
# ln-regtest-rs = { path = "../../../../ln-regtest-rs" }
|
||||
ln-regtest-rs = { git = "https://github.com/thesimplekid/ln-regtest-rs", rev = "166038b5" }
|
||||
ln-regtest-rs = { git = "https://github.com/thesimplekid/ln-regtest-rs", rev = "f9e7bbbb" }
|
||||
lightning-invoice = { version = "0.32.0", features = ["serde", "std"] }
|
||||
tracing = { version = "0.1", default-features = false, features = [
|
||||
"attributes",
|
||||
|
||||
@@ -3,13 +3,15 @@ use std::env;
|
||||
use anyhow::Result;
|
||||
use cdk::cdk_database::mint_memory::MintMemoryDatabase;
|
||||
use cdk_integration_tests::init_regtest::{
|
||||
fund_ln, get_bitcoin_dir, get_cln_dir, get_temp_dir, init_bitcoin_client, init_bitcoind,
|
||||
init_lnd, init_lnd_client, open_channel, start_cln_mint, BITCOIN_RPC_PASS, BITCOIN_RPC_USER,
|
||||
create_cln_backend, create_lnd_backend, create_mint, fund_ln, generate_block, get_bitcoin_dir,
|
||||
get_cln_dir, get_lnd_cert_file_path, get_lnd_dir, get_lnd_macaroon_path, get_temp_dir,
|
||||
init_bitcoin_client, init_bitcoind, init_lnd, open_channel, BITCOIN_RPC_PASS, BITCOIN_RPC_USER,
|
||||
LND_ADDR, LND_RPC_ADDR, LND_TWO_ADDR, LND_TWO_RPC_ADDR,
|
||||
};
|
||||
use cdk_redb::MintRedbDatabase;
|
||||
use cdk_sqlite::MintSqliteDatabase;
|
||||
use ln_regtest_rs::cln::Clnd;
|
||||
use ln_regtest_rs::ln_client::{ClnClient, LightningClient};
|
||||
use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
const CLN_ADDR: &str = "127.0.0.1:19846";
|
||||
@@ -22,10 +24,11 @@ async fn main() -> Result<()> {
|
||||
let sqlx_filter = "sqlx=warn";
|
||||
let hyper_filter = "hyper=warn";
|
||||
let h2_filter = "h2=warn";
|
||||
let rustls_filter = "rustls=warn";
|
||||
|
||||
let env_filter = EnvFilter::new(format!(
|
||||
"{},{},{},{}",
|
||||
default_filter, sqlx_filter, hyper_filter, h2_filter
|
||||
"{},{},{},{},{}",
|
||||
default_filter, sqlx_filter, hyper_filter, h2_filter, rustls_filter
|
||||
));
|
||||
|
||||
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||
@@ -69,45 +72,136 @@ async fn main() -> Result<()> {
|
||||
|
||||
let cln_two_client = ClnClient::new(cln_two_dir.clone(), None).await?;
|
||||
|
||||
cln_client.wait_chain_sync().await.unwrap();
|
||||
cln_two_client.wait_chain_sync().await.unwrap();
|
||||
|
||||
fund_ln(&bitcoin_client, &cln_two_client).await.unwrap();
|
||||
|
||||
let mut lnd = init_lnd().await;
|
||||
let lnd_dir = get_lnd_dir("one");
|
||||
println!("{}", lnd_dir.display());
|
||||
|
||||
let mut lnd = init_lnd(lnd_dir.clone(), LND_ADDR, LND_RPC_ADDR).await;
|
||||
lnd.start_lnd().unwrap();
|
||||
tracing::info!("Started lnd node");
|
||||
|
||||
let lnd_client = init_lnd_client().await.unwrap();
|
||||
let lnd_client = LndClient::new(
|
||||
format!("https://{}", LND_RPC_ADDR),
|
||||
get_lnd_cert_file_path(&lnd_dir),
|
||||
get_lnd_macaroon_path(&lnd_dir),
|
||||
)
|
||||
.await?;
|
||||
|
||||
lnd_client.wait_chain_sync().await.unwrap();
|
||||
|
||||
fund_ln(&bitcoin_client, &lnd_client).await.unwrap();
|
||||
|
||||
open_channel(&bitcoin_client, &cln_client, &lnd_client)
|
||||
.await
|
||||
.unwrap();
|
||||
// create second lnd node
|
||||
let lnd_two_dir = get_lnd_dir("two");
|
||||
let mut lnd_two = init_lnd(lnd_two_dir.clone(), LND_TWO_ADDR, LND_TWO_RPC_ADDR).await;
|
||||
lnd_two.start_lnd().unwrap();
|
||||
tracing::info!("Started second lnd node");
|
||||
|
||||
let addr = "127.0.0.1";
|
||||
let port = 8085;
|
||||
let lnd_two_client = LndClient::new(
|
||||
format!("https://{}", LND_TWO_RPC_ADDR),
|
||||
get_lnd_cert_file_path(&lnd_two_dir),
|
||||
get_lnd_macaroon_path(&lnd_two_dir),
|
||||
)
|
||||
.await?;
|
||||
|
||||
lnd_two_client.wait_chain_sync().await.unwrap();
|
||||
|
||||
fund_ln(&bitcoin_client, &lnd_two_client).await.unwrap();
|
||||
|
||||
// Open channels concurrently
|
||||
// Open channels
|
||||
{
|
||||
open_channel(&cln_client, &lnd_client).await.unwrap();
|
||||
tracing::info!("Opened channel between cln and lnd one");
|
||||
generate_block(&bitcoin_client)?;
|
||||
// open_channel(&bitcoin_client, &cln_client, &cln_two_client)
|
||||
// .await
|
||||
// .unwrap();
|
||||
// tracing::info!("Opened channel between cln and cln two");
|
||||
|
||||
open_channel(&lnd_client, &lnd_two_client).await.unwrap();
|
||||
tracing::info!("Opened channel between lnd and lnd two");
|
||||
generate_block(&bitcoin_client)?;
|
||||
|
||||
// open_channel(&cln_client, &lnd_two_client).await.unwrap();
|
||||
// tracing::info!("Opened channel between cln and lnd two");
|
||||
open_channel(&cln_two_client, &lnd_client).await.unwrap();
|
||||
tracing::info!("Opened channel between cln two and lnd");
|
||||
generate_block(&bitcoin_client)?;
|
||||
|
||||
open_channel(&cln_client, &lnd_two_client).await.unwrap();
|
||||
tracing::info!("Opened channel between cln and lnd two");
|
||||
generate_block(&bitcoin_client)?;
|
||||
|
||||
cln_client.wait_channels_active().await?;
|
||||
cln_two_client.wait_channels_active().await?;
|
||||
lnd_client.wait_channels_active().await?;
|
||||
lnd_two_client.wait_channels_active().await?;
|
||||
}
|
||||
|
||||
let mint_addr = "127.0.0.1";
|
||||
let cln_mint_port = 8085;
|
||||
|
||||
let mint_db_kind = env::var("MINT_DATABASE")?;
|
||||
|
||||
let temp_dir_path = get_temp_dir();
|
||||
let db_path = get_temp_dir().join("mint");
|
||||
let cln_path = temp_dir_path.join("one");
|
||||
let lnd_mint_db_path = get_temp_dir().join("lnd_mint");
|
||||
let cln_mint_db_path = get_temp_dir().join("cln_mint");
|
||||
|
||||
let cln_backend = create_cln_backend(&cln_client).await?;
|
||||
let lnd_mint_port = 8087;
|
||||
|
||||
let lnd_backend = create_lnd_backend(&lnd_two_client).await?;
|
||||
|
||||
match mint_db_kind.as_str() {
|
||||
"MEMORY" => {
|
||||
start_cln_mint(addr, port, MintMemoryDatabase::default(), cln_path).await?;
|
||||
tokio::spawn(async move {
|
||||
create_mint(
|
||||
mint_addr,
|
||||
cln_mint_port,
|
||||
MintMemoryDatabase::default(),
|
||||
cln_backend,
|
||||
)
|
||||
.await
|
||||
.expect("Could not start cln mint");
|
||||
});
|
||||
|
||||
create_mint(
|
||||
mint_addr,
|
||||
lnd_mint_port,
|
||||
MintMemoryDatabase::default(),
|
||||
lnd_backend,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
"SQLITE" => {
|
||||
let sqlite_db = MintSqliteDatabase::new(&db_path).await?;
|
||||
tokio::spawn(async move {
|
||||
let sqlite_db = MintSqliteDatabase::new(&cln_mint_db_path)
|
||||
.await
|
||||
.expect("Could not create mint db");
|
||||
sqlite_db.migrate().await;
|
||||
create_mint(mint_addr, cln_mint_port, sqlite_db, cln_backend)
|
||||
.await
|
||||
.expect("Could not start cln mint");
|
||||
});
|
||||
|
||||
let sqlite_db = MintSqliteDatabase::new(&lnd_mint_db_path).await?;
|
||||
sqlite_db.migrate().await;
|
||||
start_cln_mint(addr, port, sqlite_db, cln_path).await?;
|
||||
create_mint(mint_addr, lnd_mint_port, sqlite_db, lnd_backend).await?;
|
||||
}
|
||||
"REDB" => {
|
||||
let redb_db = MintRedbDatabase::new(&db_path).unwrap();
|
||||
start_cln_mint(addr, port, redb_db, cln_path).await?;
|
||||
tokio::spawn(async move {
|
||||
let redb_db = MintRedbDatabase::new(&cln_mint_db_path).unwrap();
|
||||
create_mint(mint_addr, cln_mint_port, redb_db, cln_backend)
|
||||
.await
|
||||
.expect("Could not start cln mint");
|
||||
});
|
||||
|
||||
let redb_db = MintRedbDatabase::new(&lnd_mint_db_path).unwrap();
|
||||
|
||||
create_mint(mint_addr, lnd_mint_port, redb_db, lnd_backend).await?;
|
||||
}
|
||||
_ => panic!("Unknown mint db type: {}", mint_db_kind),
|
||||
};
|
||||
|
||||
@@ -5,7 +5,9 @@ use axum::Router;
|
||||
use cdk::mint::Mint;
|
||||
use tokio::sync::Notify;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use tracing::instrument;
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn start_mint(addr: &str, port: u16, mint: Mint) -> Result<()> {
|
||||
let mint_arc = Arc::new(mint);
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use bip39::Mnemonic;
|
||||
use cdk::cdk_database::{self, MintDatabase};
|
||||
use cdk::cdk_lightning::{self, MintLightning};
|
||||
use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
|
||||
use cdk::nuts::{CurrencyUnit, PaymentMethod};
|
||||
use cdk_cln::Cln as CdkCln;
|
||||
use cdk_lnd::Lnd as CdkLnd;
|
||||
use ln_regtest_rs::bitcoin_client::BitcoinClient;
|
||||
use ln_regtest_rs::bitcoind::Bitcoind;
|
||||
use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
|
||||
use ln_regtest_rs::lnd::Lnd;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::init_mint::start_mint;
|
||||
|
||||
@@ -20,11 +23,14 @@ pub const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
|
||||
pub const ZMQ_RAW_TX: &str = "tcp://127.0.0.1:28333";
|
||||
pub const BITCOIN_RPC_USER: &str = "testuser";
|
||||
pub const BITCOIN_RPC_PASS: &str = "testpass";
|
||||
const LND_ADDR: &str = "0.0.0.0:18449";
|
||||
const LND_RPC_ADDR: &str = "localhost:10009";
|
||||
|
||||
const BITCOIN_DIR: &str = "bitcoin";
|
||||
const LND_DIR: &str = "lnd";
|
||||
|
||||
pub const LND_ADDR: &str = "0.0.0.0:18449";
|
||||
pub const LND_RPC_ADDR: &str = "localhost:10009";
|
||||
|
||||
pub const LND_TWO_ADDR: &str = "0.0.0.0:18410";
|
||||
pub const LND_TWO_RPC_ADDR: &str = "localhost:10010";
|
||||
|
||||
pub fn get_mint_addr() -> String {
|
||||
env::var("cdk_itests_mint_addr").expect("Temp dir set")
|
||||
@@ -77,23 +83,31 @@ pub fn init_bitcoin_client() -> Result<BitcoinClient> {
|
||||
}
|
||||
|
||||
pub fn get_cln_dir(name: &str) -> PathBuf {
|
||||
let dir = get_temp_dir().join(name);
|
||||
let dir = get_temp_dir().join("cln").join(name);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir
|
||||
}
|
||||
|
||||
pub fn get_lnd_dir() -> PathBuf {
|
||||
let dir = get_temp_dir().join(LND_DIR);
|
||||
pub fn get_lnd_dir(name: &str) -> PathBuf {
|
||||
let dir = get_temp_dir().join("lnd").join(name);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir
|
||||
}
|
||||
|
||||
pub async fn init_lnd() -> Lnd {
|
||||
pub fn get_lnd_cert_file_path(lnd_dir: &Path) -> PathBuf {
|
||||
lnd_dir.join("tls.cert")
|
||||
}
|
||||
|
||||
pub fn get_lnd_macaroon_path(lnd_dir: &Path) -> PathBuf {
|
||||
lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon")
|
||||
}
|
||||
|
||||
pub async fn init_lnd(lnd_dir: PathBuf, lnd_addr: &str, lnd_rpc_addr: &str) -> Lnd {
|
||||
Lnd::new(
|
||||
get_bitcoin_dir(),
|
||||
get_lnd_dir(),
|
||||
LND_ADDR.parse().unwrap(),
|
||||
LND_RPC_ADDR.to_string(),
|
||||
lnd_dir,
|
||||
lnd_addr.parse().unwrap(),
|
||||
lnd_rpc_addr.to_string(),
|
||||
BITCOIN_RPC_USER.to_string(),
|
||||
BITCOIN_RPC_PASS.to_string(),
|
||||
ZMQ_RAW_BLOCK.to_string(),
|
||||
@@ -101,16 +115,11 @@ pub async fn init_lnd() -> Lnd {
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn init_lnd_client() -> Result<LndClient> {
|
||||
let lnd_dir = get_lnd_dir();
|
||||
let cert_file = lnd_dir.join("tls.cert");
|
||||
let macaroon_file = lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon");
|
||||
LndClient::new(
|
||||
format!("https://{}", LND_RPC_ADDR).parse().unwrap(),
|
||||
cert_file,
|
||||
macaroon_file,
|
||||
)
|
||||
.await
|
||||
pub fn generate_block(bitcoin_client: &BitcoinClient) -> Result<()> {
|
||||
let mine_to_address = bitcoin_client.get_new_address()?;
|
||||
bitcoin_client.generate_blocks(&mine_to_address, 10)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_cln_backend(cln_client: &ClnClient) -> Result<CdkCln> {
|
||||
@@ -124,14 +133,27 @@ pub async fn create_cln_backend(cln_client: &ClnClient) -> Result<CdkCln> {
|
||||
Ok(CdkCln::new(rpc_path, fee_reserve).await?)
|
||||
}
|
||||
|
||||
pub async fn start_cln_mint<D>(addr: &str, port: u16, database: D, dir: PathBuf) -> Result<()>
|
||||
pub async fn create_lnd_backend(lnd_client: &LndClient) -> Result<CdkLnd> {
|
||||
let fee_reserve = FeeReserve {
|
||||
min_fee_reserve: 1.into(),
|
||||
percent_fee_reserve: 1.0,
|
||||
};
|
||||
|
||||
Ok(CdkLnd::new(
|
||||
lnd_client.address.clone(),
|
||||
lnd_client.cert_file.clone(),
|
||||
lnd_client.macaroon_file.clone(),
|
||||
fee_reserve,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn create_mint<D, L>(addr: &str, port: u16, database: D, lighting: L) -> Result<()>
|
||||
where
|
||||
D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
|
||||
L: MintLightning<Err = cdk_lightning::Error> + Send + Sync + 'static,
|
||||
{
|
||||
let cln_client = ClnClient::new(dir.clone(), None).await?;
|
||||
|
||||
let cln_backend = create_cln_backend(&cln_client).await?;
|
||||
|
||||
let mut mint_builder = MintBuilder::new();
|
||||
|
||||
mint_builder = mint_builder.with_localstore(Arc::new(database));
|
||||
@@ -140,7 +162,7 @@ where
|
||||
CurrencyUnit::Sat,
|
||||
PaymentMethod::Bolt11,
|
||||
MintMeltLimits::new(1, 5_000),
|
||||
Arc::new(cln_backend),
|
||||
Arc::new(lighting),
|
||||
);
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
@@ -165,7 +187,7 @@ where
|
||||
{
|
||||
let ln_address = ln_client.get_new_onchain_address().await?;
|
||||
|
||||
bitcoin_client.send_to_address(&ln_address, 2_000_000)?;
|
||||
bitcoin_client.send_to_address(&ln_address, 5_000_000)?;
|
||||
|
||||
ln_client.wait_chain_sync().await?;
|
||||
|
||||
@@ -177,11 +199,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn open_channel<C1, C2>(
|
||||
bitcoin_client: &BitcoinClient,
|
||||
cln_client: &C1,
|
||||
lnd_client: &C2,
|
||||
) -> Result<()>
|
||||
pub async fn open_channel<C1, C2>(cln_client: &C1, lnd_client: &C2) -> Result<()>
|
||||
where
|
||||
C1: LightningClient,
|
||||
C2: LightningClient,
|
||||
@@ -197,19 +215,13 @@ where
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cln_client.wait_chain_sync().await?;
|
||||
lnd_client.wait_chain_sync().await?;
|
||||
|
||||
lnd_client
|
||||
.open_channel(1_500_000, &cln_pubkey.to_string(), Some(750_000))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mine_to_address = bitcoin_client.get_new_address()?;
|
||||
bitcoin_client.generate_blocks(&mine_to_address, 10)?;
|
||||
|
||||
cln_client.wait_chain_sync().await?;
|
||||
lnd_client.wait_chain_sync().await?;
|
||||
|
||||
cln_client.wait_channels_active().await?;
|
||||
lnd_client.wait_channels_active().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -15,17 +15,32 @@ use cdk::nuts::{
|
||||
use cdk::wallet::client::{HttpClient, MintConnector};
|
||||
use cdk::wallet::{Wallet, WalletSubscription};
|
||||
use cdk_integration_tests::init_regtest::{
|
||||
get_cln_dir, get_mint_url, get_mint_ws_url, init_lnd_client,
|
||||
get_cln_dir, get_lnd_cert_file_path, get_lnd_dir, get_lnd_macaroon_path, get_mint_port,
|
||||
get_mint_url, get_mint_ws_url, LND_RPC_ADDR, LND_TWO_RPC_ADDR,
|
||||
};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use lightning_invoice::Bolt11Invoice;
|
||||
use ln_regtest_rs::ln_client::{ClnClient, LightningClient};
|
||||
use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
|
||||
use ln_regtest_rs::InvoiceStatus;
|
||||
use serde_json::json;
|
||||
use tokio::time::timeout;
|
||||
use tokio_tungstenite::connect_async;
|
||||
use tokio_tungstenite::tungstenite::protocol::Message;
|
||||
|
||||
// This is the ln wallet we use to send/receive ln payements as the wallet
|
||||
async fn init_lnd_client() -> LndClient {
|
||||
let lnd_dir = get_lnd_dir("one");
|
||||
let cert_file = lnd_dir.join("tls.cert");
|
||||
let macaroon_file = lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon");
|
||||
LndClient::new(
|
||||
format!("https://{}", LND_RPC_ADDR),
|
||||
cert_file,
|
||||
macaroon_file,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn get_notification<T: StreamExt<Item = Result<Message, E>> + Unpin, E: Debug>(
|
||||
reader: &mut T,
|
||||
timeout_to_wait: Duration,
|
||||
@@ -60,7 +75,7 @@ async fn get_notification<T: StreamExt<Item = Result<Message, E>> + Unpin, E: De
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_mint_melt_round_trip() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await.unwrap();
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url(),
|
||||
@@ -143,7 +158,7 @@ async fn test_regtest_mint_melt_round_trip() -> Result<()> {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_mint_melt() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await?;
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url(),
|
||||
@@ -174,7 +189,7 @@ async fn test_regtest_mint_melt() -> Result<()> {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_restore() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await?;
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let seed = Mnemonic::generate(12)?.to_seed_normalized("");
|
||||
let wallet = Wallet::new(
|
||||
@@ -231,7 +246,8 @@ async fn test_restore() -> Result<()> {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_pay_invoice_twice() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await?;
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let seed = Mnemonic::generate(12)?.to_seed_normalized("");
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url(),
|
||||
@@ -243,7 +259,10 @@ async fn test_pay_invoice_twice() -> Result<()> {
|
||||
|
||||
let mint_quote = wallet.mint_quote(100.into(), None).await?;
|
||||
|
||||
lnd_client.pay_invoice(mint_quote.request).await?;
|
||||
lnd_client
|
||||
.pay_invoice(mint_quote.request)
|
||||
.await
|
||||
.expect("Could not pay invoice");
|
||||
|
||||
let proofs = wallet
|
||||
.mint(&mint_quote.id, SplitTarget::default(), None)
|
||||
@@ -266,8 +285,8 @@ async fn test_pay_invoice_twice() -> Result<()> {
|
||||
match melt_two {
|
||||
Err(err) => match err {
|
||||
cdk::Error::RequestAlreadyPaid => (),
|
||||
_ => {
|
||||
bail!("Wrong invoice already paid");
|
||||
err => {
|
||||
bail!("Wrong invoice already paid: {}", err.to_string());
|
||||
}
|
||||
},
|
||||
Ok(_) => {
|
||||
@@ -284,7 +303,7 @@ async fn test_pay_invoice_twice() -> Result<()> {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_internal_payment() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await?;
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let seed = Mnemonic::generate(12)?.to_seed_normalized("");
|
||||
let wallet = Wallet::new(
|
||||
@@ -328,13 +347,33 @@ async fn test_internal_payment() -> Result<()> {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
let check_paid = match get_mint_port() {
|
||||
8085 => {
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
|
||||
let payment_hash = Bolt11Invoice::from_str(&mint_quote.request)?;
|
||||
let check_paid = cln_client
|
||||
.check_incoming_payment_status(&payment_hash.payment_hash().to_string())
|
||||
.await?;
|
||||
let payment_hash = Bolt11Invoice::from_str(&mint_quote.request)?;
|
||||
cln_client
|
||||
.check_incoming_payment_status(&payment_hash.payment_hash().to_string())
|
||||
.await
|
||||
.expect("Could not check invoice")
|
||||
}
|
||||
8087 => {
|
||||
let lnd_two_dir = get_lnd_dir("two");
|
||||
let lnd_client = LndClient::new(
|
||||
format!("https://{}", LND_TWO_RPC_ADDR),
|
||||
get_lnd_cert_file_path(&lnd_two_dir),
|
||||
get_lnd_macaroon_path(&lnd_two_dir),
|
||||
)
|
||||
.await?;
|
||||
let payment_hash = Bolt11Invoice::from_str(&mint_quote.request)?;
|
||||
lnd_client
|
||||
.check_incoming_payment_status(&payment_hash.payment_hash().to_string())
|
||||
.await
|
||||
.expect("Could not check invoice")
|
||||
}
|
||||
_ => panic!("Unknown mint port"),
|
||||
};
|
||||
|
||||
match check_paid {
|
||||
InvoiceStatus::Unpaid => (),
|
||||
@@ -356,7 +395,7 @@ async fn test_internal_payment() -> Result<()> {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_cached_mint() -> Result<()> {
|
||||
let lnd_client = init_lnd_client().await.unwrap();
|
||||
let lnd_client = init_lnd_client().await;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url(),
|
||||
|
||||
@@ -25,10 +25,12 @@ use error::Error;
|
||||
use fedimint_tonic_lnd::lnrpc::fee_limit::Limit;
|
||||
use fedimint_tonic_lnd::lnrpc::payment::PaymentStatus;
|
||||
use fedimint_tonic_lnd::lnrpc::FeeLimit;
|
||||
use fedimint_tonic_lnd::tonic::Code;
|
||||
use fedimint_tonic_lnd::Client;
|
||||
use futures::{Stream, StreamExt};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::instrument;
|
||||
|
||||
pub mod error;
|
||||
|
||||
@@ -75,6 +77,7 @@ impl Lnd {
|
||||
impl MintLightning for Lnd {
|
||||
type Err = cdk_lightning::Error;
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn get_settings(&self) -> Settings {
|
||||
Settings {
|
||||
mpp: false,
|
||||
@@ -83,14 +86,17 @@ impl MintLightning for Lnd {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn is_wait_invoice_active(&self) -> bool {
|
||||
self.wait_invoice_is_active.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn cancel_wait_invoice(&self) {
|
||||
self.wait_invoice_cancel_token.cancel()
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn wait_any_invoice(
|
||||
&self,
|
||||
) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> {
|
||||
@@ -163,6 +169,7 @@ impl MintLightning for Lnd {
|
||||
.boxed())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn get_payment_quote(
|
||||
&self,
|
||||
melt_quote_request: &MeltQuoteBolt11Request,
|
||||
@@ -189,6 +196,7 @@ impl MintLightning for Lnd {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn pay_invoice(
|
||||
&self,
|
||||
melt_quote: mint::MeltQuote,
|
||||
@@ -196,6 +204,23 @@ impl MintLightning for Lnd {
|
||||
max_fee: Option<Amount>,
|
||||
) -> Result<PayInvoiceResponse, Self::Err> {
|
||||
let payment_request = melt_quote.request;
|
||||
let bolt11 = Bolt11Invoice::from_str(&payment_request)?;
|
||||
|
||||
let pay_state = self
|
||||
.check_outgoing_payment(&bolt11.payment_hash().to_string())
|
||||
.await?;
|
||||
|
||||
match pay_state.status {
|
||||
MeltQuoteState::Unpaid | MeltQuoteState::Unknown | MeltQuoteState::Failed => (),
|
||||
MeltQuoteState::Paid => {
|
||||
tracing::debug!("Melt attempted on invoice already paid");
|
||||
return Err(Self::Err::InvoiceAlreadyPaid);
|
||||
}
|
||||
MeltQuoteState::Pending => {
|
||||
tracing::debug!("Melt attempted on invoice already pending");
|
||||
return Err(Self::Err::InvoicePaymentPending);
|
||||
}
|
||||
}
|
||||
|
||||
let amount_msat: u64 = match melt_quote.msat_to_pay {
|
||||
Some(amount_msat) => amount_msat.into(),
|
||||
@@ -225,7 +250,10 @@ impl MintLightning for Lnd {
|
||||
.lightning()
|
||||
.send_payment_sync(fedimint_tonic_lnd::tonic::Request::new(pay_req))
|
||||
.await
|
||||
.map_err(|_| Error::PaymentFailed)?
|
||||
.map_err(|err| {
|
||||
tracing::warn!("Lightning payment failed: {}", err);
|
||||
Error::PaymentFailed
|
||||
})?
|
||||
.into_inner();
|
||||
|
||||
let total_amount = payment_response
|
||||
@@ -250,6 +278,7 @@ impl MintLightning for Lnd {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self, description))]
|
||||
async fn create_invoice(
|
||||
&self,
|
||||
amount: Amount,
|
||||
@@ -287,6 +316,7 @@ impl MintLightning for Lnd {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn check_incoming_invoice_status(
|
||||
&self,
|
||||
request_lookup_id: &str,
|
||||
@@ -319,6 +349,7 @@ impl MintLightning for Lnd {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn check_outgoing_payment(
|
||||
&self,
|
||||
payment_hash: &str,
|
||||
@@ -327,15 +358,32 @@ impl MintLightning for Lnd {
|
||||
payment_hash: hex::decode(payment_hash).map_err(|_| Error::InvalidHash)?,
|
||||
no_inflight_updates: true,
|
||||
};
|
||||
let mut payment_stream = self
|
||||
|
||||
let payment_response = self
|
||||
.client
|
||||
.lock()
|
||||
.await
|
||||
.router()
|
||||
.track_payment_v2(track_request)
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
.await;
|
||||
|
||||
let mut payment_stream = match payment_response {
|
||||
Ok(stream) => stream.into_inner(),
|
||||
Err(err) => {
|
||||
let err_code = err.code();
|
||||
if err_code == Code::NotFound {
|
||||
return Ok(PayInvoiceResponse {
|
||||
payment_lookup_id: payment_hash.to_string(),
|
||||
payment_preimage: None,
|
||||
status: MeltQuoteState::Unknown,
|
||||
total_spent: Amount::ZERO,
|
||||
unit: self.get_settings().unit,
|
||||
});
|
||||
} else {
|
||||
return Err(cdk_lightning::Error::UnknownPaymentState);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while let Some(update_result) = payment_stream.next().await {
|
||||
match update_result {
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::util::unix_time;
|
||||
use crate::{cdk_lightning, Amount, Error};
|
||||
|
||||
impl Mint {
|
||||
#[instrument(skip_all)]
|
||||
fn check_melt_request_acceptable(
|
||||
&self,
|
||||
amount: Amount,
|
||||
|
||||
@@ -12,11 +12,11 @@ cleanup() {
|
||||
wait $CDK_ITEST_MINT_BIN_PID
|
||||
|
||||
echo "Mint binary terminated"
|
||||
|
||||
# Kill processes
|
||||
lncli --lnddir="$cdk_itests/lnd" --network=regtest stop
|
||||
lightning-cli --regtest --lightning-dir="$cdk_itests/one/" stop
|
||||
lightning-cli --regtest --lightning-dir="$cdk_itests/two/" stop
|
||||
lncli --lnddir="$cdk_itests/lnd/one" --network=regtest stop
|
||||
lncli --lnddir="$cdk_itests/lnd/two" --network=regtest --rpcserver=localhost:10010 stop
|
||||
lightning-cli --regtest --lightning-dir="$cdk_itests/cln/one/" stop
|
||||
lightning-cli --regtest --lightning-dir="$cdk_itests/cln/two/" stop
|
||||
bitcoin-cli --datadir="$cdk_itests/bitcoin" -rpcuser=testuser -rpcpassword=testpass -rpcport=18443 stop
|
||||
|
||||
# Remove the temporary directory
|
||||
@@ -47,7 +47,10 @@ export MINT_DATABASE="$1";
|
||||
|
||||
cargo build -p cdk-integration-tests
|
||||
cargo build --bin regtest_mint
|
||||
# cargo run --bin regtest_mint > "$cdk_itests/mint.log" 2>&1 &
|
||||
cargo run --bin regtest_mint &
|
||||
|
||||
echo $cdk_itests
|
||||
# Capture its PID
|
||||
CDK_ITEST_MINT_BIN_PID=$!
|
||||
|
||||
@@ -84,9 +87,13 @@ done
|
||||
# Run cargo test
|
||||
cargo test -p cdk-integration-tests --test regtest
|
||||
|
||||
# Run cargo test with the http_subscription feature
|
||||
# # Run cargo test with the http_subscription feature
|
||||
cargo test -p cdk-integration-tests --test regtest --features http_subscription
|
||||
|
||||
# Run tests with lnd mint
|
||||
export cdk_itests_mint_port=8087;
|
||||
cargo test -p cdk-integration-tests --test regtest
|
||||
|
||||
# Capture the exit status of cargo test
|
||||
test_status=$?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user