mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-20 14:14:49 +01:00
feat: tests on lnd node
This commit is contained in:
@@ -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>>,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 cln_one_dir = get_cln_dir("one");
|
let check_paid = match get_mint_port() {
|
||||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
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 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?;
|
.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 {
|
match check_paid {
|
||||||
InvoiceStatus::Unpaid => (),
|
InvoiceStatus::Unpaid => (),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user