1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Check used at mint start up
//!
//! These checks are need in the case the mint was offline and the lightning node was node.
//! 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::PaymentProcessorKey;
impl Mint {
/// Check the status of all pending mint quotes in the mint db
/// with all the lighting backends. This check that any payments
/// received while the mint was offline are accounted for, and the wallet can mint associated ecash
pub async fn check_pending_mint_quotes(&self) -> Result<(), Error> {
let pending_quotes = self.get_pending_mint_quotes().await?;
tracing::info!("There are {} pending mint quotes.", pending_quotes.len());
for quote in pending_quotes.iter() {
tracing::debug!("Checking status of mint quote: {}", quote.id);
if let Err(err) = self.check_mint_quote_paid("e.id).await {
tracing::error!("Could not check status of {}, {}", quote.id, err);
}
}
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 = PaymentProcessorKey {
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_proof,
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(())
}
}