Skip to content

Commit 9d2151a

Browse files
committed
Make corepc-node optional in payjoin-test-utils
Test constants (ORIGINAL_PSBT, EXAMPLE_URL, etc.) and the TestServices infrastructure don't require bitcoind. Only init_bitcoind* functions need the corepc-node crate, which downloads a ~40MB binary at build time. Move bitcoind-dependent functions to a `bitcoind` module, gated behind a `bitcoind` feature (default = on). Re-export from crate root for backwards compatibility. Downstream consumers can now import payjoin-test-utils for constants without triggering the bitcoind download.
1 parent 117ce51 commit 9d2151a

File tree

3 files changed

+84
-72
lines changed

3 files changed

+84
-72
lines changed

payjoin-test-utils/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ repository = "https://github.com/payjoin/rust-payjoin"
88
rust-version = "1.85"
99
license = "MIT"
1010

11+
[features]
12+
default = ["bitcoind"]
13+
bitcoind = ["dep:corepc-node"]
14+
1115
[dependencies]
1216
axum-server = { version = "0.8", features = ["tls-rustls-no-provider"] }
1317
bitcoin = { version = "0.32.7", features = ["base64"] }
14-
corepc-node = { version = "0.10.0", features = ["download", "29_0"] }
18+
corepc-node = { version = "0.10.0", features = ["download", "29_0"], optional = true }
1519
http = "1.3.1"
1620
ohttp = { package = "bitcoin-ohttp", version = "0.6.0" }
1721
once_cell = "1.21.3"

payjoin-test-utils/src/bitcoind.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use bitcoin::Amount;
2+
pub use corepc_node;
3+
use corepc_node::AddressType;
4+
use tracing::Level;
5+
6+
use crate::BoxError;
7+
8+
pub fn init_bitcoind() -> Result<corepc_node::Node, BoxError> {
9+
let bitcoind_exe = corepc_node::exe_path()?;
10+
let mut conf = corepc_node::Conf::default();
11+
conf.view_stdout = tracing::enabled!(target: "corepc", Level::TRACE);
12+
// conf.args.push("-txindex");
13+
let bitcoind = corepc_node::Node::with_conf(bitcoind_exe, &conf)?;
14+
Ok(bitcoind)
15+
}
16+
17+
pub fn init_bitcoind_sender_receiver(
18+
sender_address_type: Option<AddressType>,
19+
receiver_address_type: Option<AddressType>,
20+
) -> Result<(corepc_node::Node, corepc_node::Client, corepc_node::Client), BoxError> {
21+
let bitcoind = init_bitcoind()?;
22+
let mut wallets = create_and_fund_wallets(
23+
&bitcoind,
24+
vec![("receiver", receiver_address_type), ("sender", sender_address_type)],
25+
)?;
26+
let receiver = wallets.pop().expect("receiver to exist");
27+
let sender = wallets.pop().expect("sender to exist");
28+
29+
Ok((bitcoind, receiver, sender))
30+
}
31+
32+
fn create_and_fund_wallets<W: AsRef<str>>(
33+
bitcoind: &corepc_node::Node,
34+
wallets: Vec<(W, Option<AddressType>)>,
35+
) -> Result<Vec<corepc_node::Client>, BoxError> {
36+
let mut funded_wallets = vec![];
37+
let funding_wallet = bitcoind.create_wallet("funding_wallet")?;
38+
let funding_address = funding_wallet.new_address()?;
39+
// 100 blocks would work here, we add a extra block to cover fees between transfers
40+
bitcoind.client.generate_to_address(101 + wallets.len(), &funding_address)?;
41+
for (wallet_name, address_type) in wallets {
42+
let wallet = bitcoind.create_wallet(wallet_name)?;
43+
let address = wallet.get_new_address(None, address_type)?.into_model()?.0.assume_checked();
44+
funding_wallet.send_to_address(&address, Amount::from_btc(50.0)?)?;
45+
funded_wallets.push(wallet);
46+
}
47+
// Mine the block which funds the different wallets
48+
bitcoind.client.generate_to_address(1, &funding_address)?;
49+
50+
for wallet in funded_wallets.iter() {
51+
let balances = wallet.get_balances()?.into_model()?;
52+
assert_eq!(
53+
balances.mine.trusted,
54+
Amount::from_btc(50.0)?,
55+
"wallet doesn't have expected amount of bitcoin"
56+
);
57+
}
58+
59+
Ok(funded_wallets)
60+
}
61+
62+
pub fn init_bitcoind_multi_sender_single_reciever(
63+
number_of_senders: usize,
64+
) -> Result<(corepc_node::Node, Vec<corepc_node::Client>, corepc_node::Client), BoxError> {
65+
let bitcoind = init_bitcoind()?;
66+
let wallets_to_create =
67+
(0..number_of_senders + 1).map(|i| (format!("sender_{i}"), None)).collect::<Vec<_>>();
68+
let mut wallets = create_and_fund_wallets(&bitcoind, wallets_to_create)?;
69+
let receiver = wallets.pop().expect("receiver to exist");
70+
let senders = wallets;
71+
72+
Ok((bitcoind, senders, receiver))
73+
}

payjoin-test-utils/src/lib.rs

Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ use std::str::FromStr;
33
use std::sync::Arc;
44
use std::time::Duration;
55

6+
#[cfg(feature = "bitcoind")]
7+
pub mod bitcoind;
8+
#[cfg(feature = "bitcoind")]
9+
pub use bitcoind::*;
10+
611
use axum_server::tls_rustls::RustlsConfig;
7-
use bitcoin::{Amount, Psbt};
8-
pub use corepc_node; // re-export for convenience
9-
use corepc_node::AddressType;
12+
use bitcoin::Psbt;
1013
use http::StatusCode;
1114
use ohttp::hpke::{Aead, Kdf, Kem};
1215
use ohttp::{KeyId, SymmetricSuite};
@@ -19,7 +22,6 @@ use rustls::pki_types::CertificateDer;
1922
use rustls::RootCertStore;
2023
use tempfile::tempdir;
2124
use tokio::task::JoinHandle;
22-
use tracing::Level;
2325
use tracing_subscriber::{EnvFilter, FmtSubscriber};
2426

2527
pub type BoxError = Box<dyn std::error::Error + 'static>;
@@ -173,77 +175,10 @@ pub fn local_cert_key() -> rcgen::CertifiedKey<rcgen::KeyPair> {
173175
.expect("Failed to generate cert")
174176
}
175177

176-
pub fn init_bitcoind() -> Result<corepc_node::Node, BoxError> {
177-
let bitcoind_exe = corepc_node::exe_path()?;
178-
let mut conf = corepc_node::Conf::default();
179-
conf.view_stdout = tracing::enabled!(target: "corepc", Level::TRACE);
180-
// conf.args.push("-txindex");
181-
let bitcoind = corepc_node::Node::with_conf(bitcoind_exe, &conf)?;
182-
Ok(bitcoind)
183-
}
184-
185-
pub fn init_bitcoind_sender_receiver(
186-
sender_address_type: Option<AddressType>,
187-
receiver_address_type: Option<AddressType>,
188-
) -> Result<(corepc_node::Node, corepc_node::Client, corepc_node::Client), BoxError> {
189-
let bitcoind = init_bitcoind()?;
190-
let mut wallets = create_and_fund_wallets(
191-
&bitcoind,
192-
vec![("receiver", receiver_address_type), ("sender", sender_address_type)],
193-
)?;
194-
let receiver = wallets.pop().expect("receiver to exist");
195-
let sender = wallets.pop().expect("sender to exist");
196-
197-
Ok((bitcoind, receiver, sender))
198-
}
199-
200-
fn create_and_fund_wallets<W: AsRef<str>>(
201-
bitcoind: &corepc_node::Node,
202-
wallets: Vec<(W, Option<AddressType>)>,
203-
) -> Result<Vec<corepc_node::Client>, BoxError> {
204-
let mut funded_wallets = vec![];
205-
let funding_wallet = bitcoind.create_wallet("funding_wallet")?;
206-
let funding_address = funding_wallet.new_address()?;
207-
// 100 blocks would work here, we add a extra block to cover fees between transfers
208-
bitcoind.client.generate_to_address(101 + wallets.len(), &funding_address)?;
209-
for (wallet_name, address_type) in wallets {
210-
let wallet = bitcoind.create_wallet(wallet_name)?;
211-
let address = wallet.get_new_address(None, address_type)?.into_model()?.0.assume_checked();
212-
funding_wallet.send_to_address(&address, Amount::from_btc(50.0)?)?;
213-
funded_wallets.push(wallet);
214-
}
215-
// Mine the block which funds the different wallets
216-
bitcoind.client.generate_to_address(1, &funding_address)?;
217-
218-
for wallet in funded_wallets.iter() {
219-
let balances = wallet.get_balances()?.into_model()?;
220-
assert_eq!(
221-
balances.mine.trusted,
222-
Amount::from_btc(50.0)?,
223-
"wallet doesn't have expected amount of bitcoin"
224-
);
225-
}
226-
227-
Ok(funded_wallets)
228-
}
229-
230178
pub fn http_agent(cert_der: Vec<u8>) -> Result<Client, BoxSendSyncError> {
231179
Ok(http_agent_builder(cert_der).build()?)
232180
}
233181

234-
pub fn init_bitcoind_multi_sender_single_reciever(
235-
number_of_senders: usize,
236-
) -> Result<(corepc_node::Node, Vec<corepc_node::Client>, corepc_node::Client), BoxError> {
237-
let bitcoind = init_bitcoind()?;
238-
let wallets_to_create =
239-
(0..number_of_senders + 1).map(|i| (format!("sender_{i}"), None)).collect::<Vec<_>>();
240-
let mut wallets = create_and_fund_wallets(&bitcoind, wallets_to_create)?;
241-
let receiver = wallets.pop().expect("receiver to exist");
242-
let senders = wallets;
243-
244-
Ok((bitcoind, senders, receiver))
245-
}
246-
247182
fn http_agent_builder(cert_der: Vec<u8>) -> ClientBuilder {
248183
ClientBuilder::new().http1_only().use_rustls_tls().add_root_certificate(
249184
reqwest::tls::Certificate::from_der(cert_der.as_slice())

0 commit comments

Comments
 (0)