feat: tests on lnd node

This commit is contained in:
thesimplekid
2025-01-24 14:40:10 +00:00
parent 486f98bc8b
commit 67be74abb8
7 changed files with 97 additions and 18 deletions

View File

@@ -12,6 +12,7 @@ use cdk::nuts::{
}; };
use cdk::util::unix_time; use cdk::util::unix_time;
use paste::paste; use paste::paste;
use tracing::instrument;
use uuid::Uuid; use uuid::Uuid;
use crate::ws::main_websocket; 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") (status = 500, description = "Server error", body = ErrorResponse, content_type = "application/json")
) )
))] ))]
#[instrument(skip_all)]
/// Request a quote for melting tokens /// Request a quote for melting tokens
pub async fn post_melt_bolt11_quote( pub async fn post_melt_bolt11_quote(
State(state): State<MintState>, State(state): State<MintState>,
@@ -261,6 +263,7 @@ pub async fn post_melt_bolt11_quote(
/// Get melt quote by ID /// Get melt quote by ID
/// ///
/// Get melt quote state. /// Get melt quote state.
#[instrument(skip_all)]
pub async fn get_check_melt_bolt11_quote( pub async fn get_check_melt_bolt11_quote(
State(state): State<MintState>, State(state): State<MintState>,
Path(quote_id): Path<Uuid>, 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 /// 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. /// Requests tokens to be destroyed and sent out via Lightning.
#[instrument(skip_all)]
pub async fn post_melt_bolt11( pub async fn post_melt_bolt11(
State(state): State<MintState>, State(state): State<MintState>,
Json(payload): Json<MeltBolt11Request<Uuid>>, Json(payload): Json<MeltBolt11Request<Uuid>>,

View File

@@ -5,7 +5,9 @@ use axum::Router;
use cdk::mint::Mint; use cdk::mint::Mint;
use tokio::sync::Notify; use tokio::sync::Notify;
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;
use tracing::instrument;
#[instrument(skip_all)]
pub async fn start_mint(addr: &str, port: u16, mint: Mint) -> Result<()> { pub async fn start_mint(addr: &str, port: u16, mint: Mint) -> Result<()> {
let mint_arc = Arc::new(mint); let mint_arc = Arc::new(mint);

View File

@@ -1,5 +1,5 @@
use std::env; use std::env;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
@@ -14,6 +14,7 @@ use ln_regtest_rs::bitcoin_client::BitcoinClient;
use ln_regtest_rs::bitcoind::Bitcoind; use ln_regtest_rs::bitcoind::Bitcoind;
use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient}; use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
use ln_regtest_rs::lnd::Lnd; use ln_regtest_rs::lnd::Lnd;
use tracing::instrument;
use crate::init_mint::start_mint; use crate::init_mint::start_mint;
@@ -93,11 +94,11 @@ pub fn get_lnd_dir(name: &str) -> PathBuf {
dir dir
} }
pub fn get_lnd_cert_file_path(lnd_dir: &PathBuf) -> PathBuf { pub fn get_lnd_cert_file_path(lnd_dir: &Path) -> PathBuf {
lnd_dir.join("tls.cert") lnd_dir.join("tls.cert")
} }
pub fn get_lnd_macaroon_path(lnd_dir: &PathBuf) -> PathBuf { pub fn get_lnd_macaroon_path(lnd_dir: &Path) -> PathBuf {
lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon") lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon")
} }
@@ -147,6 +148,7 @@ pub async fn create_lnd_backend(lnd_client: &LndClient) -> Result<CdkLnd> {
.await?) .await?)
} }
#[instrument(skip_all)]
pub async fn create_mint<D, L>(addr: &str, port: u16, database: D, lighting: L) -> Result<()> pub async fn create_mint<D, L>(addr: &str, port: u16, database: D, lighting: L) -> Result<()>
where where
D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static, D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,

View File

@@ -15,7 +15,8 @@ use cdk::nuts::{
use cdk::wallet::client::{HttpClient, MintConnector}; use cdk::wallet::client::{HttpClient, MintConnector};
use cdk::wallet::{Wallet, WalletSubscription}; use cdk::wallet::{Wallet, WalletSubscription};
use cdk_integration_tests::init_regtest::{ use cdk_integration_tests::init_regtest::{
get_cln_dir, get_lnd_dir, get_mint_url, get_mint_ws_url, LND_RPC_ADDR, 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 futures::{SinkExt, StreamExt};
use lightning_invoice::Bolt11Invoice; use lightning_invoice::Bolt11Invoice;
@@ -258,7 +259,10 @@ async fn test_pay_invoice_twice() -> Result<()> {
let mint_quote = wallet.mint_quote(100.into(), None).await?; 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 let proofs = wallet
.mint(&mint_quote.id, SplitTarget::default(), None) .mint(&mint_quote.id, SplitTarget::default(), None)
@@ -343,13 +347,33 @@ async fn test_internal_payment() -> Result<()> {
.await .await
.unwrap(); .unwrap();
let check_paid = match get_mint_port() {
8085 => {
let cln_one_dir = get_cln_dir("one"); let cln_one_dir = get_cln_dir("one");
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?; let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
let payment_hash = Bolt11Invoice::from_str(&mint_quote.request)?; let payment_hash = Bolt11Invoice::from_str(&mint_quote.request)?;
let check_paid = cln_client cln_client
.check_incoming_payment_status(&payment_hash.payment_hash().to_string()) .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?; .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 { match check_paid {
InvoiceStatus::Unpaid => (), InvoiceStatus::Unpaid => (),

View File

@@ -25,6 +25,7 @@ use error::Error;
use fedimint_tonic_lnd::lnrpc::fee_limit::Limit; use fedimint_tonic_lnd::lnrpc::fee_limit::Limit;
use fedimint_tonic_lnd::lnrpc::payment::PaymentStatus; use fedimint_tonic_lnd::lnrpc::payment::PaymentStatus;
use fedimint_tonic_lnd::lnrpc::FeeLimit; use fedimint_tonic_lnd::lnrpc::FeeLimit;
use fedimint_tonic_lnd::tonic::Code;
use fedimint_tonic_lnd::Client; use fedimint_tonic_lnd::Client;
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use tokio::sync::Mutex; use tokio::sync::Mutex;
@@ -76,6 +77,7 @@ impl Lnd {
impl MintLightning for Lnd { impl MintLightning for Lnd {
type Err = cdk_lightning::Error; type Err = cdk_lightning::Error;
#[instrument(skip_all)]
fn get_settings(&self) -> Settings { fn get_settings(&self) -> Settings {
Settings { Settings {
mpp: false, mpp: false,
@@ -84,14 +86,17 @@ impl MintLightning for Lnd {
} }
} }
#[instrument(skip_all)]
fn is_wait_invoice_active(&self) -> bool { fn is_wait_invoice_active(&self) -> bool {
self.wait_invoice_is_active.load(Ordering::SeqCst) self.wait_invoice_is_active.load(Ordering::SeqCst)
} }
#[instrument(skip_all)]
fn cancel_wait_invoice(&self) { fn cancel_wait_invoice(&self) {
self.wait_invoice_cancel_token.cancel() self.wait_invoice_cancel_token.cancel()
} }
#[instrument(skip_all)]
async fn wait_any_invoice( async fn wait_any_invoice(
&self, &self,
) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> { ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> {
@@ -164,6 +169,7 @@ impl MintLightning for Lnd {
.boxed()) .boxed())
} }
#[instrument(skip_all)]
async fn get_payment_quote( async fn get_payment_quote(
&self, &self,
melt_quote_request: &MeltQuoteBolt11Request, melt_quote_request: &MeltQuoteBolt11Request,
@@ -198,6 +204,23 @@ impl MintLightning for Lnd {
max_fee: Option<Amount>, max_fee: Option<Amount>,
) -> Result<PayInvoiceResponse, Self::Err> { ) -> Result<PayInvoiceResponse, Self::Err> {
let payment_request = melt_quote.request; 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 { let amount_msat: u64 = match melt_quote.msat_to_pay {
Some(amount_msat) => amount_msat.into(), Some(amount_msat) => amount_msat.into(),
@@ -255,6 +278,7 @@ impl MintLightning for Lnd {
}) })
} }
#[instrument(skip(self, description))]
async fn create_invoice( async fn create_invoice(
&self, &self,
amount: Amount, amount: Amount,
@@ -292,6 +316,7 @@ impl MintLightning for Lnd {
}) })
} }
#[instrument(skip(self))]
async fn check_incoming_invoice_status( async fn check_incoming_invoice_status(
&self, &self,
request_lookup_id: &str, request_lookup_id: &str,
@@ -324,6 +349,7 @@ impl MintLightning for Lnd {
} }
} }
#[instrument(skip(self))]
async fn check_outgoing_payment( async fn check_outgoing_payment(
&self, &self,
payment_hash: &str, payment_hash: &str,
@@ -332,15 +358,32 @@ impl MintLightning for Lnd {
payment_hash: hex::decode(payment_hash).map_err(|_| Error::InvalidHash)?, payment_hash: hex::decode(payment_hash).map_err(|_| Error::InvalidHash)?,
no_inflight_updates: true, no_inflight_updates: true,
}; };
let mut payment_stream = self
let payment_response = self
.client .client
.lock() .lock()
.await .await
.router() .router()
.track_payment_v2(track_request) .track_payment_v2(track_request)
.await .await;
.unwrap()
.into_inner(); 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 { while let Some(update_result) = payment_stream.next().await {
match update_result { match update_result {

View File

@@ -21,6 +21,7 @@ use crate::util::unix_time;
use crate::{cdk_lightning, Amount, Error}; use crate::{cdk_lightning, Amount, Error};
impl Mint { impl Mint {
#[instrument(skip_all)]
fn check_melt_request_acceptable( fn check_melt_request_acceptable(
&self, &self,
amount: Amount, amount: Amount,

View File

@@ -28,7 +28,7 @@ cleanup() {
} }
# Set up trap to call cleanup on script exit # Set up trap to call cleanup on script exit
# trap cleanup EXIT trap cleanup EXIT
# Create a temporary directory # Create a temporary directory
export cdk_itests=$(mktemp -d) export cdk_itests=$(mktemp -d)
@@ -47,7 +47,10 @@ export MINT_DATABASE="$1";
cargo build -p cdk-integration-tests cargo build -p cdk-integration-tests
cargo build --bin regtest_mint cargo build --bin regtest_mint
# cargo run --bin regtest_mint > "$cdk_itests/mint.log" 2>&1 &
cargo run --bin regtest_mint & cargo run --bin regtest_mint &
echo $cdk_itests
# Capture its PID # Capture its PID
CDK_ITEST_MINT_BIN_PID=$! CDK_ITEST_MINT_BIN_PID=$!
@@ -82,10 +85,10 @@ done
# Run cargo test # Run cargo test
# cargo test -p cdk-integration-tests --test regtest 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 cargo test -p cdk-integration-tests --test regtest --features http_subscription
# Run tests with lnd mint # Run tests with lnd mint
export cdk_itests_mint_port=8087; export cdk_itests_mint_port=8087;