Skip to content

Commit 8480c3c

Browse files
committed
Separate send::{v1,v2} modules
This reduces the number of feature gates and works toward a crate where the features are additive and potentially both available at the same time. Right now they're still mutually exclusive (v1 is enabled by not(v2))
1 parent d15d695 commit 8480c3c

File tree

10 files changed

+696
-561
lines changed

10 files changed

+696
-561
lines changed

payjoin-cli/src/app/mod.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use bitcoincore_rpc::bitcoin::Amount;
88
use bitcoincore_rpc::RpcApi;
99
use payjoin::bitcoin::psbt::Psbt;
1010
use payjoin::receive::InputPair;
11-
use payjoin::send::Sender;
1211
use payjoin::{bitcoin, PjUri};
1312

1413
pub mod config;
@@ -31,7 +30,7 @@ pub trait App {
3130
async fn send_payjoin(&self, bip21: &str, fee_rate: &f32) -> Result<()>;
3231
async fn receive_payjoin(self, amount_arg: &str) -> Result<()>;
3332

34-
fn create_pj_request(&self, uri: &PjUri, fee_rate: &f32) -> Result<Sender> {
33+
fn create_original_psbt(&self, uri: &PjUri, fee_rate: &f32) -> Result<Psbt> {
3534
let amount = uri.amount.ok_or_else(|| anyhow!("please specify the amount in the Uri"))?;
3635

3736
// wallet_create_funded_psbt requires a HashMap<address: String, Amount>
@@ -67,11 +66,7 @@ pub trait App {
6766
.psbt;
6867
let psbt = Psbt::from_str(&psbt).with_context(|| "Failed to load PSBT from base64")?;
6968
log::debug!("Original psbt: {:#?}", psbt);
70-
let req_ctx = payjoin::send::SenderBuilder::new(psbt, uri.clone())
71-
.build_recommended(fee_rate)
72-
.with_context(|| "Failed to build payjoin request")?;
73-
74-
Ok(req_ctx)
69+
Ok(psbt)
7570
}
7671

7772
fn process_pj_response(&self, psbt: Psbt) -> Result<bitcoin::Txid> {

payjoin-cli/src/app/v1.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use hyper_util::rt::TokioIo;
1616
use payjoin::bitcoin::psbt::Psbt;
1717
use payjoin::bitcoin::{self, FeeRate};
1818
use payjoin::receive::{PayjoinProposal, UncheckedProposal};
19+
use payjoin::send::v1::SenderBuilder;
1920
use payjoin::{Error, PjUriBuilder, Uri, UriExt};
2021
use tokio::net::TcpListener;
2122

@@ -72,7 +73,13 @@ impl AppTrait for App {
7273
Uri::try_from(bip21).map_err(|e| anyhow!("Failed to create URI from BIP21: {}", e))?;
7374
let uri = uri.assume_checked();
7475
let uri = uri.check_pj_supported().map_err(|_| anyhow!("URI does not support Payjoin"))?;
75-
let (req, ctx) = self.create_pj_request(&uri, fee_rate)?.extract_v1()?;
76+
let psbt = self.create_original_psbt(&uri, fee_rate)?;
77+
let fee_rate_sat_per_kwu = fee_rate * 250.0_f32;
78+
let fee_rate = FeeRate::from_sat_per_kwu(fee_rate_sat_per_kwu.ceil() as u64);
79+
let (req, ctx) = SenderBuilder::new(psbt, uri.clone())
80+
.build_recommended(fee_rate)
81+
.with_context(|| "Failed to build payjoin request")?
82+
.extract_v1()?;
7683
let http = http_agent()?;
7784
let body = String::from_utf8(req.body.clone()).unwrap();
7885
println!("Sending fallback request to {}", &req.url);

payjoin-cli/src/app/v2.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use payjoin::bitcoin::consensus::encode::serialize_hex;
77
use payjoin::bitcoin::psbt::Psbt;
88
use payjoin::bitcoin::{Amount, FeeRate};
99
use payjoin::receive::v2::Receiver;
10-
use payjoin::send::Sender;
10+
use payjoin::send::v2::{Sender, SenderBuilder};
1111
use payjoin::{bitcoin, Error, Uri};
1212
use tokio::signal;
1313
use tokio::sync::watch;
@@ -65,7 +65,12 @@ impl AppTrait for App {
6565
let req_ctx = match self.db.get_send_session(url)? {
6666
Some(send_session) => send_session,
6767
None => {
68-
let mut req_ctx = self.create_pj_request(&uri, fee_rate)?;
68+
let psbt = self.create_original_psbt(&uri, fee_rate)?;
69+
let fee_rate_sat_per_kwu = fee_rate * 250.0_f32;
70+
let fee_rate = FeeRate::from_sat_per_kwu(fee_rate_sat_per_kwu.ceil() as u64);
71+
let mut req_ctx = SenderBuilder::new(psbt, uri.clone())
72+
.build_recommended(fee_rate)
73+
.with_context(|| "Failed to build payjoin request")?;
6974
self.db.insert_send_session(&mut req_ctx, url)?;
7075
req_ctx
7176
}
@@ -192,7 +197,7 @@ impl App {
192197
Ok(())
193198
}
194199

195-
async fn long_poll_post(&self, req_ctx: &mut payjoin::send::Sender) -> Result<Psbt> {
200+
async fn long_poll_post(&self, req_ctx: &mut Sender) -> Result<Psbt> {
196201
match req_ctx.extract_v2(self.config.ohttp_relay.clone()) {
197202
Ok((req, ctx)) => {
198203
println!("Posting Original PSBT Payload request...");

payjoin-cli/src/db/v2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bitcoincore_rpc::jsonrpc::serde_json;
22
use payjoin::receive::v2::Receiver;
3-
use payjoin::send::Sender;
3+
use payjoin::send::v2::Sender;
44
use sled::{IVec, Tree};
55
use url::Url;
66

payjoin/src/send/error.rs

-68
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ use bitcoin::locktime::absolute::LockTime;
44
use bitcoin::transaction::Version;
55
use bitcoin::{AddressType, Sequence};
66

7-
#[cfg(feature = "v2")]
8-
use crate::uri::url_ext::ParseReceiverPubkeyParamError;
9-
107
/// Error building a Sender from a SenderBuilder.
118
///
129
/// This error is unrecoverable.
@@ -84,71 +81,6 @@ impl std::error::Error for BuildSenderError {
8481
}
8582
}
8683

87-
/// Error returned when request could not be created.
88-
///
89-
/// This error can currently only happen due to programmer mistake.
90-
/// `unwrap()`ing it is thus considered OK in Rust but you may achieve nicer message by displaying
91-
/// it.
92-
#[derive(Debug)]
93-
#[cfg(feature = "v2")]
94-
pub struct CreateRequestError(InternalCreateRequestError);
95-
96-
#[derive(Debug)]
97-
#[cfg(feature = "v2")]
98-
pub(crate) enum InternalCreateRequestError {
99-
Url(url::ParseError),
100-
Hpke(crate::hpke::HpkeError),
101-
OhttpEncapsulation(crate::ohttp::OhttpEncapsulationError),
102-
ParseReceiverPubkey(ParseReceiverPubkeyParamError),
103-
MissingOhttpConfig,
104-
Expired(std::time::SystemTime),
105-
}
106-
107-
#[cfg(feature = "v2")]
108-
impl fmt::Display for CreateRequestError {
109-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110-
use InternalCreateRequestError::*;
111-
112-
match &self.0 {
113-
Url(e) => write!(f, "cannot parse url: {:#?}", e),
114-
Hpke(e) => write!(f, "v2 error: {}", e),
115-
OhttpEncapsulation(e) => write!(f, "v2 error: {}", e),
116-
ParseReceiverPubkey(e) => write!(f, "cannot parse receiver public key: {}", e),
117-
MissingOhttpConfig =>
118-
write!(f, "no ohttp configuration with which to make a v2 request available"),
119-
Expired(expiry) => write!(f, "session expired at {:?}", expiry),
120-
}
121-
}
122-
}
123-
124-
#[cfg(feature = "v2")]
125-
impl std::error::Error for CreateRequestError {
126-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
127-
use InternalCreateRequestError::*;
128-
129-
match &self.0 {
130-
Url(error) => Some(error),
131-
Hpke(error) => Some(error),
132-
OhttpEncapsulation(error) => Some(error),
133-
ParseReceiverPubkey(error) => Some(error),
134-
MissingOhttpConfig => None,
135-
Expired(_) => None,
136-
}
137-
}
138-
}
139-
140-
#[cfg(feature = "v2")]
141-
impl From<InternalCreateRequestError> for CreateRequestError {
142-
fn from(value: InternalCreateRequestError) -> Self { CreateRequestError(value) }
143-
}
144-
145-
#[cfg(feature = "v2")]
146-
impl From<ParseReceiverPubkeyParamError> for CreateRequestError {
147-
fn from(value: ParseReceiverPubkeyParamError) -> Self {
148-
CreateRequestError(InternalCreateRequestError::ParseReceiverPubkey(value))
149-
}
150-
}
151-
15284
/// Error that may occur when the response from receiver is malformed.
15385
///
15486
/// This is currently opaque type because we aren't sure which variants will stay.

0 commit comments

Comments
 (0)