Skip to content

Commit

Permalink
add error for finalize_psbt
Browse files Browse the repository at this point in the history
  • Loading branch information
jbesraa committed Aug 20, 2023
1 parent 1438451 commit 64602c3
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 70 deletions.
39 changes: 19 additions & 20 deletions payjoin-cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bitcoincore_rpc::RpcApi;
use clap::ArgMatches;
use config::{Config, File, FileFormat};
use payjoin::bitcoin::psbt::Psbt;
use payjoin::receive::{Error, PayjoinProposal, ProvisionalProposal};
use payjoin::receive::{Error, ProvisionalProposal};
use payjoin::{bitcoin, PjUriExt, UriExt};
use rouille::{Request, Response};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -296,7 +296,7 @@ impl App {
})?;
log::trace!("check4");

let mut payjoin = payjoin.identify_receiver_outputs(|output_script| {
let mut provisional_payjoin = payjoin.identify_receiver_outputs(|output_script| {
if let Ok(address) = bitcoin::Address::from_script(output_script, network) {
self.bitcoind
.get_address_info(&address)
Expand All @@ -309,7 +309,7 @@ impl App {

if !self.config.sub_only {
// Select receiver payjoin inputs.
_ = try_contributing_inputs(&mut payjoin, &self.bitcoind)
_ = try_contributing_inputs(&mut provisional_payjoin, &self.bitcoind)
.map_err(|e| log::warn!("Failed to contribute inputs: {}", e));
}

Expand All @@ -318,24 +318,23 @@ impl App {
.get_new_address(None, None)
.map_err(|e| Error::Server(e.into()))?
.assume_checked();
payjoin.substitute_output_address(receiver_substitute_address);
provisional_payjoin.substitute_output_address(receiver_substitute_address);

let payjoin_proposal_psbt = payjoin.apply_fee(Some(1))?;

log::debug!("Extracted PSBT: {:#?}", payjoin_proposal_psbt);
// Sign payjoin psbt
let payjoin_base64_string = base64::encode(&payjoin_proposal_psbt.serialize());
// `wallet_process_psbt` adds available utxo data and finalizes
let payjoin_proposal_psbt = self
.bitcoind
.wallet_process_psbt(&payjoin_base64_string, None, None, Some(false))
.map_err(|e| Error::Server(e.into()))?
.psbt;
let payjoin_proposal_psbt = Psbt::from_str(&payjoin_proposal_psbt)
.context("Failed to parse PSBT")
.map_err(|e| Error::Server(e.into()))?;
let payjoin_proposal = payjoin.prepare_psbt(payjoin_proposal_psbt)?;
let payjoin_proposal_psbt = payjoin_proposal.get_payjoin_psbt();
let payjoi_proposal = provisional_payjoin.finalize_proposal(
|psbt: &Psbt| {
self.bitcoind
.wallet_process_psbt(
&bitcoin::base64::encode(psbt.serialize()),
None,
None,
Some(false),
)
.map(|res| Psbt::from_str(&res.psbt).map_err(|e| Error::Server(e.into())))
.map_err(|e| Error::Server(e.into()))?
},
Some(bitcoin::FeeRate::MIN),
)?;
let payjoin_proposal_psbt = payjoi_proposal.psbt();
log::debug!("Receiver's Payjoin proposal PSBT Rsponse: {:#?}", payjoin_proposal_psbt);

let payload = base64::encode(&payjoin_proposal_psbt.serialize());
Expand Down
2 changes: 1 addition & 1 deletion payjoin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ bip21 = "0.3.1"
log = { version = "0.4.14"}
rand = { version = "0.8.4", optional = true }
url = "2.2.2"
bitcoind = { version = "0.31.1", features = ["0_21_2"] }

[dev-dependencies]
env_logger = "0.9.0"
bitcoind = { version = "0.31.1", features = ["0_21_2"] }

[package.metadata.docs.rs]
features = ["send", "receive"]
4 changes: 0 additions & 4 deletions payjoin/src/receive/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ pub struct RequestError(InternalRequestError);
#[derive(Debug)]
pub(crate) enum InternalRequestError {
Psbt(bitcoin::psbt::Error),
PsbtParseError(bitcoin::psbt::PsbtParseError),
Base64(bitcoin::base64::DecodeError),
BitcoinCoreRpc(bitcoind::bitcoincore_rpc::Error),
Io(std::io::Error),
MissingHeader(&'static str),
InvalidContentType(String),
Expand Down Expand Up @@ -80,8 +78,6 @@ impl fmt::Display for RequestError {
}

match &self.0 {
InternalRequestError::PsbtParseError(e) => write_error(f, "psbt-parse-error", e),
InternalRequestError::BitcoinCoreRpc(e) => write_error(f, "bitcoin-core-rpc-error", e),
InternalRequestError::Psbt(e) => write_error(f, "psbt-error", e),
InternalRequestError::Base64(e) => write_error(f, "base64-decode-error", e),
InternalRequestError::Io(e) => write_error(f, "io-error", e),
Expand Down
43 changes: 15 additions & 28 deletions payjoin/src/receive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,6 @@ use bitcoin::{Amount, FeeRate, OutPoint, Script, TxOut};
mod error;
mod optional_parameters;

use bitcoind::bitcoincore_rpc;
use bitcoind::bitcoincore_rpc::core_rpc_json::WalletProcessPsbtResult;
pub use error::{Error, RequestError, SelectionError};
use error::{InternalRequestError, InternalSelectionError};
use optional_parameters::Params;
Expand Down Expand Up @@ -553,7 +551,6 @@ impl OutputsUnknown {
}

/// A mutable checked proposal that the receiver may contribute inputs to to make a payjoin.

pub struct PayjoinProposal {
payjoin_psbt: Psbt,
params: Params,
Expand All @@ -569,9 +566,9 @@ impl PayjoinProposal {
self.params.disable_output_substitution
}

pub fn get_owned_vouts(&self) -> Vec<usize> { self.owned_vouts.clone() }
pub fn get_owned_vouts(&self) -> &Vec<usize> { &self.owned_vouts }

pub fn get_payjoin_psbt(&self) -> Psbt { self.payjoin_psbt.clone() }
pub fn psbt(&self) -> &Psbt { &self.payjoin_psbt }
}

/// A mutable checked proposal that the receiver may contribute inputs to to make a payjoin.
Expand Down Expand Up @@ -724,12 +721,11 @@ impl ProvisionalProposal {
/// this is kind of a "build_proposal" step before we sign and finalize and extract
///
/// WARNING: DO NOT ALTER INPUTS OR OUTPUTS AFTER THIS STEP
pub fn apply_fee(
fn apply_fee(
&mut self,
min_feerate_sat_per_vb: Option<u64>,
min_feerate_sat_per_vb: Option<FeeRate>,
) -> Result<&Psbt, RequestError> {
let min_feerate =
FeeRate::from_sat_per_vb_unchecked(min_feerate_sat_per_vb.unwrap_or_default());
let min_feerate = min_feerate_sat_per_vb.unwrap_or(FeeRate::MIN);
log::trace!("min_feerate: {:?}", min_feerate);
log::trace!("params.min_feerate: {:?}", self.params.min_feerate);
let min_feerate = max(min_feerate, self.params.min_feerate);
Expand Down Expand Up @@ -777,7 +773,7 @@ impl ProvisionalProposal {
/// and return a PSBT that can produce a consensus-valid transaction that the sender will accept.
///
/// wallet_process_psbt should sign and finalize receiver inputs
pub fn prepare_psbt(mut self, processed_psbt: Psbt) -> Result<PayjoinProposal, RequestError> {
fn prepare_psbt(mut self, processed_psbt: Psbt) -> Result<PayjoinProposal, RequestError> {
self.payjoin_psbt = processed_psbt;
log::trace!("Preparing PSBT {:#?}", self.payjoin_psbt);
for input in self.payjoin_psbt.inputs_mut() {
Expand Down Expand Up @@ -817,24 +813,15 @@ impl ProvisionalProposal {

pub fn finalize_proposal(
mut self,
wallet_process_psbt: impl Fn(&str) -> Result<WalletProcessPsbtResult, bitcoincore_rpc::Error>,
min_feerate_sat_per_vb: Option<u64>,
) -> Result<PayjoinProposal, RequestError> {
let payjoin_proposal_psbt: &Psbt = self.apply_fee(min_feerate_sat_per_vb)?;
let payjoin_base64_string = bitcoin::base64::encode(&payjoin_proposal_psbt.serialize());
let payjoin_proposal_psbt = match wallet_process_psbt(&payjoin_base64_string) {
Ok(p) => p.psbt,
Err(e) => return Err(RequestError::from(InternalRequestError::BitcoinCoreRpc(e))),
};
let payjoin_proposal_psbt = match Psbt::from_str(&payjoin_proposal_psbt) {
Ok(p) => p,
Err(e) => return Err(RequestError::from(InternalRequestError::PsbtParseError(e))),
};

let payjoin_proposal = match self.prepare_psbt(payjoin_proposal_psbt) {
Ok(p) => p,
Err(e) => return Err(RequestError::from(e)),
};
wallet_process_psbt: impl Fn(&Psbt) -> Result<Psbt, Error>,
min_feerate_sat_per_vb: Option<FeeRate>,
) -> Result<PayjoinProposal, Error> {
let psbt = self.apply_fee(min_feerate_sat_per_vb)?;
let psbt = wallet_process_psbt(psbt).map_err(|e| {
log::error!("wallet_process_psbt error");
Error::from(e)
})?;
let payjoin_proposal = self.prepare_psbt(psbt).map_err(RequestError::from)?;
Ok(payjoin_proposal)
}
}
Expand Down
41 changes: 24 additions & 17 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ mod integration {
use bitcoin::psbt::Psbt;
use bitcoin::{Amount, OutPoint};
use bitcoind::bitcoincore_rpc;
use bitcoind::bitcoincore_rpc::core_rpc_json::AddressType;
use bitcoind::bitcoincore_rpc::core_rpc_json::{AddressType, WalletProcessPsbtResult};
use bitcoind::bitcoincore_rpc::RpcApi;
use log::{debug, log_enabled, Level};
use payjoin::bitcoin::base64;
use payjoin::receive::Headers;
use payjoin::send::Request;
use payjoin::{bitcoin, PjUriExt, Uri, UriExt};
use payjoin::{bitcoin, Error, PjUriExt, Uri, UriExt};

#[test]
fn integration_test() {
Expand Down Expand Up @@ -200,20 +200,27 @@ mod integration {
let receiver_substitute_address =
receiver.get_new_address(None, None).unwrap().assume_checked();
payjoin.substitute_output_address(receiver_substitute_address);

let payjoin_proposal_psbt = payjoin.apply_fee(None).unwrap();

// Sign payjoin psbt
let payjoin_base64_string = base64::encode(&payjoin_proposal_psbt.serialize());
let payjoin_proposal_psbt = receiver
.wallet_process_psbt(&payjoin_base64_string, None, None, Some(false))
.unwrap()
.psbt;
let payjoin_proposal_psbt = Psbt::from_str(&payjoin_proposal_psbt).unwrap();

let payjoin_proposal_psbt = payjoin.prepare_psbt(payjoin_proposal_psbt).unwrap();
debug!("Receiver's Payjoin proposal PSBT: {:#?}", payjoin_proposal_psbt.get_payjoin_psbt());

base64::encode(&payjoin_proposal_psbt.get_payjoin_psbt().serialize())
let payjoin_proposal = payjoin
.finalize_proposal(
|psbt: &Psbt| {
Ok(receiver
.wallet_process_psbt(
&bitcoin::base64::encode(psbt.serialize()),
None,
None,
Some(false),
)
.map(|res: WalletProcessPsbtResult| {
let psbt = Psbt::from_str(&res.psbt).unwrap();
return psbt;
})
.unwrap())
},
Some(bitcoin::FeeRate::MIN),
)
.unwrap();
let psbt = payjoin_proposal.psbt();
debug!("Receiver's Payjoin proposal PSBT: {:#?}", &psbt);
base64::encode(&psbt.serialize())
}
}

0 comments on commit 64602c3

Please sign in to comment.