Browse Source

feat: melt startup check into cdk

thesimplekid 4 months ago
parent
commit
4cefe875f1
4 changed files with 103 additions and 93 deletions
  1. 3 92
      crates/cdk-mintd/src/main.rs
  2. 4 0
      crates/cdk/src/error.rs
  3. 95 0
      crates/cdk/src/mint/start_up_check.rs
  4. 1 1
      flake.nix

+ 3 - 92
crates/cdk-mintd/src/main.rs

@@ -14,8 +14,8 @@ use bip39::Mnemonic;
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::cdk_lightning;
 use cdk::cdk_lightning::MintLightning;
-use cdk::mint::{MeltQuote, Mint, MintBuilder, MintMeltLimits};
-use cdk::nuts::{ContactInfo, CurrencyUnit, MeltQuoteState, MintVersion, PaymentMethod};
+use cdk::mint::{MintBuilder, MintMeltLimits};
+use cdk::nuts::{ContactInfo, CurrencyUnit, MintVersion, PaymentMethod};
 use cdk::types::LnKey;
 use cdk_mintd::cli::CLIArgs;
 use cdk_mintd::config::{self, DatabaseEngine, LnBackend};
@@ -275,7 +275,7 @@ async fn main() -> anyhow::Result<()> {
     // Checks the status of all pending melt quotes
     // Pending melt quotes where the payment has gone through inputs are burnt
     // Pending melt quotes where the payment has **failed** inputs are reset to unspent
-    check_pending_melt_quotes(Arc::clone(&mint), &ln_backends).await?;
+    mint.check_pending_melt_quotes().await?;
 
     let listen_addr = settings.info.listen_host;
     let listen_port = settings.info.listen_port;
@@ -344,95 +344,6 @@ async fn main() -> anyhow::Result<()> {
     Ok(())
 }
 
-async fn check_pending_melt_quotes(
-    mint: Arc<Mint>,
-    ln_backends: &HashMap<LnKey, Arc<dyn MintLightning<Err = cdk_lightning::Error> + Send + Sync>>,
-) -> Result<()> {
-    let melt_quotes = mint.localstore.get_melt_quotes().await?;
-    let pending_quotes: Vec<MeltQuote> = melt_quotes
-        .into_iter()
-        .filter(|q| q.state == MeltQuoteState::Pending || q.state == MeltQuoteState::Unknown)
-        .collect();
-    tracing::info!("There are {} pending melt quotes.", pending_quotes.len());
-
-    for pending_quote in pending_quotes {
-        tracing::debug!("Checking status for melt quote {}.", pending_quote.id);
-        let melt_request_ln_key = mint.localstore.get_melt_request(&pending_quote.id).await?;
-
-        let (melt_request, ln_key) = match melt_request_ln_key {
-            None => (
-                None,
-                LnKey {
-                    unit: pending_quote.unit,
-                    method: PaymentMethod::Bolt11,
-                },
-            ),
-            Some((melt_request, ln_key)) => (Some(melt_request), ln_key),
-        };
-
-        let ln_backend = match ln_backends.get(&ln_key) {
-            Some(ln_backend) => ln_backend,
-            None => {
-                tracing::warn!("No backend for ln key: {:?}", ln_key);
-                continue;
-            }
-        };
-
-        let pay_invoice_response = ln_backend
-            .check_outgoing_payment(&pending_quote.request_lookup_id)
-            .await?;
-
-        match melt_request {
-            Some(melt_request) => {
-                match pay_invoice_response.status {
-                    MeltQuoteState::Paid => {
-                        if let Err(err) = mint
-                            .process_melt_request(
-                                &melt_request,
-                                pay_invoice_response.payment_preimage,
-                                pay_invoice_response.total_spent,
-                            )
-                            .await
-                        {
-                            tracing::error!(
-                                "Could not process melt request for pending quote: {}",
-                                melt_request.quote
-                            );
-                            tracing::error!("{}", err);
-                        }
-                    }
-                    MeltQuoteState::Unpaid | MeltQuoteState::Unknown | MeltQuoteState::Failed => {
-                        // Payment has not been made we want to unset
-                        tracing::info!("Lightning payment for quote {} failed.", pending_quote.id);
-                        if let Err(err) = mint.process_unpaid_melt(&melt_request).await {
-                            tracing::error!("Could not reset melt quote state: {}", err);
-                        }
-                    }
-                    MeltQuoteState::Pending => {
-                        tracing::warn!(
-                            "LN payment pending, proofs are stuck as pending for quote: {}",
-                            melt_request.quote
-                        );
-                        // Quote is still pending we do not want to do anything
-                        // continue to check next quote
-                    }
-                }
-            }
-            None => {
-                tracing::warn!(
-                    "There is no stored melt request for pending melt quote: {}",
-                    pending_quote.id
-                );
-
-                mint.localstore
-                    .update_melt_quote_state(&pending_quote.id, pay_invoice_response.status)
-                    .await?;
-            }
-        };
-    }
-    Ok(())
-}
-
 fn work_dir() -> Result<PathBuf> {
     let home_dir = home::home_dir().ok_or(anyhow!("Unknown home dir"))?;
 

+ 4 - 0
crates/cdk/src/error.rs

@@ -243,6 +243,10 @@ pub enum Error {
     #[cfg(any(feature = "wallet", feature = "mint"))]
     #[error(transparent)]
     Database(#[from] crate::cdk_database::Error),
+    /// Lightning Error
+    #[cfg(feature = "mint")]
+    #[error(transparent)]
+    Lightning(#[from] crate::cdk_lightning::Error),
 }
 
 /// CDK Error Response

+ 95 - 0
crates/cdk/src/mint/start_up_check.rs

@@ -4,6 +4,8 @@
 //! These ensure that the status of the mint or melt quote matches in the mint db and on the node.
 
 use super::{Error, Mint};
+use crate::mint::{MeltQuote, MeltQuoteState, PaymentMethod};
+use crate::types::LnKey;
 
 impl Mint {
     /// Check the status of all pending mint quotes in the mint db
@@ -40,4 +42,97 @@ impl Mint {
         }
         Ok(())
     }
+
+    /// Checks the states of melt quotes that are **PENDING** or **UNKNOWN** to the mint with the ln node
+    pub async fn check_pending_melt_quotes(&self) -> Result<(), Error> {
+        let melt_quotes = self.localstore.get_melt_quotes().await?;
+        let pending_quotes: Vec<MeltQuote> = melt_quotes
+            .into_iter()
+            .filter(|q| q.state == MeltQuoteState::Pending || q.state == MeltQuoteState::Unknown)
+            .collect();
+        tracing::info!("There are {} pending melt quotes.", pending_quotes.len());
+
+        for pending_quote in pending_quotes {
+            tracing::debug!("Checking status for melt quote {}.", pending_quote.id);
+            let melt_request_ln_key = self.localstore.get_melt_request(&pending_quote.id).await?;
+
+            let (melt_request, ln_key) = match melt_request_ln_key {
+                None => {
+                    let ln_key = LnKey {
+                        unit: pending_quote.unit,
+                        method: PaymentMethod::Bolt11,
+                    };
+
+                    (None, ln_key)
+                }
+                Some((melt_request, ln_key)) => (Some(melt_request), ln_key),
+            };
+
+            let ln_backend = match self.ln.get(&ln_key) {
+                Some(ln_backend) => ln_backend,
+                None => {
+                    tracing::warn!("No backend for ln key: {:?}", ln_key);
+                    continue;
+                }
+            };
+
+            let pay_invoice_response = ln_backend
+                .check_outgoing_payment(&pending_quote.request_lookup_id)
+                .await?;
+
+            match melt_request {
+                Some(melt_request) => {
+                    match pay_invoice_response.status {
+                        MeltQuoteState::Paid => {
+                            if let Err(err) = self
+                                .process_melt_request(
+                                    &melt_request,
+                                    pay_invoice_response.payment_preimage,
+                                    pay_invoice_response.total_spent,
+                                )
+                                .await
+                            {
+                                tracing::error!(
+                                    "Could not process melt request for pending quote: {}",
+                                    melt_request.quote
+                                );
+                                tracing::error!("{}", err);
+                            }
+                        }
+                        MeltQuoteState::Unpaid
+                        | MeltQuoteState::Unknown
+                        | MeltQuoteState::Failed => {
+                            // Payment has not been made we want to unset
+                            tracing::info!(
+                                "Lightning payment for quote {} failed.",
+                                pending_quote.id
+                            );
+                            if let Err(err) = self.process_unpaid_melt(&melt_request).await {
+                                tracing::error!("Could not reset melt quote state: {}", err);
+                            }
+                        }
+                        MeltQuoteState::Pending => {
+                            tracing::warn!(
+                                "LN payment pending, proofs are stuck as pending for quote: {}",
+                                melt_request.quote
+                            );
+                            // Quote is still pending we do not want to do anything
+                            // continue to check next quote
+                        }
+                    }
+                }
+                None => {
+                    tracing::warn!(
+                        "There is no stored melt request for pending melt quote: {}",
+                        pending_quote.id
+                    );
+
+                    self.localstore
+                        .update_melt_quote_state(&pending_quote.id, pay_invoice_response.status)
+                        .await?;
+                }
+            };
+        }
+        Ok(())
+    }
 }

+ 1 - 1
flake.nix

@@ -53,7 +53,7 @@
           targets = [ "wasm32-unknown-unknown" ]; # wasm
         };
 
-        # Nighly for creating lock files
+        # Nightly for creating lock files
         nightly_toolchain = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
           extensions = [ "rustfmt" "clippy" "rust-analyzer" ];
         });