|
@@ -1004,91 +1004,89 @@ impl Mint {
|
|
total_spent: Amount,
|
|
total_spent: Amount,
|
|
) -> Result<MeltQuoteBolt11Response, Error> {
|
|
) -> Result<MeltQuoteBolt11Response, Error> {
|
|
tracing::debug!("Processing melt quote: {}", melt_request.quote);
|
|
tracing::debug!("Processing melt quote: {}", melt_request.quote);
|
|
|
|
+
|
|
let quote = self
|
|
let quote = self
|
|
.localstore
|
|
.localstore
|
|
.get_melt_quote(&melt_request.quote)
|
|
.get_melt_quote(&melt_request.quote)
|
|
.await?
|
|
.await?
|
|
.ok_or(Error::UnknownQuote)?;
|
|
.ok_or(Error::UnknownQuote)?;
|
|
|
|
|
|
- if let Some(outputs) = &melt_request.outputs {
|
|
|
|
- let blinded_messages: Vec<PublicKey> =
|
|
|
|
- outputs.iter().map(|b| b.blinded_secret).collect();
|
|
|
|
|
|
+ let input_ys = melt_request
|
|
|
|
+ .inputs
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|p| hash_to_curve(&p.secret.to_bytes()))
|
|
|
|
+ .collect::<Result<Vec<PublicKey>, _>>()?;
|
|
|
|
|
|
- if self
|
|
|
|
- .localstore
|
|
|
|
- .get_blind_signatures(&blinded_messages)
|
|
|
|
- .await?
|
|
|
|
- .iter()
|
|
|
|
- .flatten()
|
|
|
|
- .next()
|
|
|
|
- .is_some()
|
|
|
|
- {
|
|
|
|
- tracing::info!("Output has already been signed",);
|
|
|
|
|
|
+ self.localstore
|
|
|
|
+ .update_proofs_states(&input_ys, State::Spent)
|
|
|
|
+ .await?;
|
|
|
|
|
|
- return Err(Error::BlindedMessageAlreadySigned);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ self.localstore
|
|
|
|
+ .update_melt_quote_state(&melt_request.quote, MeltQuoteState::Paid)
|
|
|
|
+ .await?;
|
|
|
|
|
|
let mut change = None;
|
|
let mut change = None;
|
|
|
|
|
|
- if let Some(outputs) = melt_request.outputs.clone() {
|
|
|
|
- let change_target = melt_request.proofs_amount() - total_spent;
|
|
|
|
- let mut amounts = change_target.split();
|
|
|
|
- let mut change_sigs = Vec::with_capacity(amounts.len());
|
|
|
|
|
|
+ // Check if there is change to return
|
|
|
|
+ if melt_request.proofs_amount() > total_spent {
|
|
|
|
+ // Check if wallet provided change outputs
|
|
|
|
+ if let Some(outputs) = melt_request.outputs.clone() {
|
|
|
|
+ let blinded_messages: Vec<PublicKey> =
|
|
|
|
+ outputs.iter().map(|b| b.blinded_secret).collect();
|
|
|
|
|
|
- if outputs.len().lt(&amounts.len()) {
|
|
|
|
- tracing::debug!(
|
|
|
|
- "Providing change requires {} blinded messages, but only {} provided",
|
|
|
|
- amounts.len(),
|
|
|
|
- outputs.len()
|
|
|
|
- );
|
|
|
|
|
|
+ if self
|
|
|
|
+ .localstore
|
|
|
|
+ .get_blind_signatures(&blinded_messages)
|
|
|
|
+ .await?
|
|
|
|
+ .iter()
|
|
|
|
+ .flatten()
|
|
|
|
+ .next()
|
|
|
|
+ .is_some()
|
|
|
|
+ {
|
|
|
|
+ tracing::info!("Output has already been signed");
|
|
|
|
|
|
- // In the case that not enough outputs are provided to return all change
|
|
|
|
- // Reverse sort the amounts so that the most amount of change possible is
|
|
|
|
- // returned. The rest is burnt
|
|
|
|
- amounts.sort_by(|a, b| b.cmp(a));
|
|
|
|
- }
|
|
|
|
|
|
+ return Err(Error::BlindedMessageAlreadySigned);
|
|
|
|
+ }
|
|
|
|
|
|
- let mut outputs = outputs;
|
|
|
|
|
|
+ let change_target = melt_request.proofs_amount() - total_spent;
|
|
|
|
+ let mut amounts = change_target.split();
|
|
|
|
+ let mut change_sigs = Vec::with_capacity(amounts.len());
|
|
|
|
|
|
- for (amount, blinded_message) in amounts.iter().zip(&mut outputs) {
|
|
|
|
- blinded_message.amount = *amount;
|
|
|
|
|
|
+ if outputs.len().lt(&amounts.len()) {
|
|
|
|
+ tracing::debug!(
|
|
|
|
+ "Providing change requires {} blinded messages, but only {} provided",
|
|
|
|
+ amounts.len(),
|
|
|
|
+ outputs.len()
|
|
|
|
+ );
|
|
|
|
|
|
- let blinded_signature = self.blind_sign(blinded_message).await?;
|
|
|
|
- change_sigs.push(blinded_signature)
|
|
|
|
- }
|
|
|
|
|
|
+ // In the case that not enough outputs are provided to return all change
|
|
|
|
+ // Reverse sort the amounts so that the most amount of change possible is
|
|
|
|
+ // returned. The rest is burnt
|
|
|
|
+ amounts.sort_by(|a, b| b.cmp(a));
|
|
|
|
+ }
|
|
|
|
|
|
- self.localstore
|
|
|
|
- .add_blind_signatures(
|
|
|
|
- &outputs[0..change_sigs.len()]
|
|
|
|
- .iter()
|
|
|
|
- .map(|o| o.blinded_secret)
|
|
|
|
- .collect::<Vec<PublicKey>>(),
|
|
|
|
- &change_sigs,
|
|
|
|
- )
|
|
|
|
- .await?;
|
|
|
|
|
|
+ let mut outputs = outputs;
|
|
|
|
|
|
- change = Some(change_sigs);
|
|
|
|
- } else {
|
|
|
|
- tracing::info!(
|
|
|
|
- "No change outputs provided. Burnt: {:?} sats",
|
|
|
|
- (melt_request.proofs_amount() - total_spent)
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ for (amount, blinded_message) in amounts.iter().zip(&mut outputs) {
|
|
|
|
+ blinded_message.amount = *amount;
|
|
|
|
|
|
- let input_ys: Vec<PublicKey> = melt_request
|
|
|
|
- .inputs
|
|
|
|
- .iter()
|
|
|
|
- .flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
|
|
|
|
- .collect();
|
|
|
|
|
|
+ let blinded_signature = self.blind_sign(blinded_message).await?;
|
|
|
|
+ change_sigs.push(blinded_signature)
|
|
|
|
+ }
|
|
|
|
|
|
- self.localstore
|
|
|
|
- .update_proofs_states(&input_ys, State::Spent)
|
|
|
|
- .await?;
|
|
|
|
|
|
+ self.localstore
|
|
|
|
+ .add_blind_signatures(
|
|
|
|
+ &outputs[0..change_sigs.len()]
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|o| o.blinded_secret)
|
|
|
|
+ .collect::<Vec<PublicKey>>(),
|
|
|
|
+ &change_sigs,
|
|
|
|
+ )
|
|
|
|
+ .await?;
|
|
|
|
|
|
- self.localstore
|
|
|
|
- .update_melt_quote_state(&melt_request.quote, MeltQuoteState::Paid)
|
|
|
|
- .await?;
|
|
|
|
|
|
+ change = Some(change_sigs);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
Ok(MeltQuoteBolt11Response {
|
|
Ok(MeltQuoteBolt11Response {
|
|
amount: quote.amount,
|
|
amount: quote.amount,
|