Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use silentpayments::sending::generate_recipient_pubkeys;
use silentpayments::utils::sending::calculate_partial_secret;
use silentpayments::SilentPaymentAddress;
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
use wallet::io::FileExt;
use wallet::silentpayments::{SilentPaymentKeysFile, SpendKey};

const READY_TIMEOUT: Duration = Duration::from_secs(30);
const STOP_TIMEOUT: Duration = Duration::from_secs(45);
Expand All @@ -33,6 +35,13 @@ pub fn start_bitcoind() -> Node {
Node::with_conf(exe, &conf).unwrap()
}

pub fn random_signing_keys() -> SilentPaymentKeysFile {
let mut rng = bitcoin::secp256k1::rand::rngs::OsRng;
let scan = SecretKey::new(&mut rng);
let spend = SecretKey::new(&mut rng);
SilentPaymentKeysFile::new(scan, SpendKey::Secret(spend))
}

async fn connect(socket_path: &Path) -> server::Client {
let stream = tokio::net::UnixStream::connect(socket_path).await.unwrap();
let (reader, writer) = stream.into_split();
Expand All @@ -59,21 +68,30 @@ pub struct TestNode {

impl TestNode {
pub fn start() -> Self {
Self::start_connected(CLOSED_PEER)
Self::start_connected(CLOSED_PEER, None)
}

pub fn start_connected(peer: impl std::fmt::Display) -> Self {
pub fn start_connected(
peer: impl std::fmt::Display,
keys: Option<SilentPaymentKeysFile>,
) -> Self {
let tempdir = tempfile::tempdir().unwrap();
let datadir = tempdir.path().canonicalize().unwrap();
let process = Command::new(env!("CARGO_BIN_EXE_node"))
let mut command = Command::new(env!("CARGO_BIN_EXE_node"));
command
.arg("--network")
.arg("regtest")
.arg("--datadir")
.arg(&datadir)
.arg("--connect")
.arg(peer.to_string())
.spawn()
.unwrap();
.arg(peer.to_string());
// With no keys, the node starts without a wallet.
if let Some(keys) = keys {
let keys_path = datadir.join("keys.bin");
keys.save(&keys_path).unwrap();
command.arg("--sp-keys-file").arg(&keys_path);
}
let process = command.spawn().unwrap();
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
Expand Down Expand Up @@ -251,6 +269,21 @@ impl Drop for TestNode {
}
}

pub fn wait_for_core_mempool(core: &Node, txid: &str, timeout: Duration) {
let deadline = Instant::now() + timeout;
loop {
let mempool = core.client.get_raw_mempool().unwrap();
if mempool.0.iter().any(|entry| entry == txid) {
return;
}
assert!(
Instant::now() < deadline,
"Core did not accept {txid} within {timeout:?}"
);
std::thread::sleep(POLL_INTERVAL);
}
}

// Core cannot send to a silent payment address, so build the BIP-352 payment
// here, broadcast it through Core, and mine it.
pub fn fund_silent_payment(core: &Node, sp_address: &str, amount: Amount) {
Expand Down
2 changes: 1 addition & 1 deletion tests/core_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn connects_to_bitcoin_core() {
let core = start_bitcoind();
let p2p = core.params.p2p_socket.unwrap();

let node = TestNode::start_connected(p2p);
let node = TestNode::start_connected(p2p, None);

let deadline = Instant::now() + CONNECT_TIMEOUT;
loop {
Expand Down
2 changes: 1 addition & 1 deletion tests/core_reorg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn follows_bitcoin_core_reorg() {
let initial_hash = core.client.best_block_hash().expect("best block hash");

let p2p = core.params.p2p_socket.expect("bitcoind p2p socket");
let node = TestNode::start_connected(p2p);
let node = TestNode::start_connected(p2p, None);
node.wait_for_tip(initial_height, initial_hash, SYNC_TIMEOUT);

let fork_block = core
Expand Down
2 changes: 1 addition & 1 deletion tests/core_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn follows_bitcoin_core_chain() {
assert_eq!(core_height, BLOCKS as u64);

let p2p = core.params.p2p_socket.expect("bitcoind p2p socket");
let node = TestNode::start_connected(p2p);
let node = TestNode::start_connected(p2p, None);

node.wait_for_tip(core_height, core_hash, SYNC_TIMEOUT);

Expand Down
53 changes: 53 additions & 0 deletions tests/tx_valid_to_core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
mod common;

use std::time::Duration;

use bitcoin::Amount;
use common::{fund_silent_payment, start_bitcoind, wait_for_core_mempool, TestNode};

const SYNC_TIMEOUT: Duration = Duration::from_secs(60);
const ACCEPT_TIMEOUT: Duration = Duration::from_secs(30);

#[test]
fn node_transaction_is_valid_to_core() {
let core = start_bitcoind();
let p2p = core.params.p2p_socket.unwrap();
println!("step 1/6: bitcoind started on regtest");

let node = TestNode::start_connected(p2p, Some(common::random_signing_keys()));
println!("step 2/6: spend-capable node started and connected to Core");

let sp_address = node.receive_address();
println!("step 3/6: node receive address {sp_address}");

let funded = Amount::from_sat(100_000_000);
fund_silent_payment(&core, &sp_address, funded);
println!(
"step 4/6: broadcast a {} sat silent payment to the node",
funded.to_sat()
);

let balance = node.wait_for_balance(funded, SYNC_TIMEOUT);
println!("step 5/6: node scanned the payment, balance = {balance}");

let destination = core.client.new_address().unwrap();
let out = node.cli(&[
"wallet",
"send-to-address",
&destination.to_string(),
"50000000",
"5",
]);
assert!(
out.status.success(),
"send-to-address failed: {}",
String::from_utf8_lossy(&out.stderr)
);
let stdout = String::from_utf8_lossy(&out.stdout);
let txid = stdout.split_whitespace().last().expect("txid in output");

wait_for_core_mempool(&core, txid, ACCEPT_TIMEOUT);
println!("step 6/6: node built {txid} and Core accepted it into the mempool");

node.stop();
}
29 changes: 29 additions & 0 deletions tests/wallet_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
mod common;

use bitcoin::hex::DisplayHex;
use bitcoin::secp256k1::{Secp256k1, SecretKey};
use common::TestNode;
use silentpayments::SilentPaymentAddress;

#[test]
fn imports_keys_over_the_cli() {
let secp = Secp256k1::new();
let node = TestNode::start();

let scan = SecretKey::from_slice(&[0x11; 32]).unwrap();
let spend = SecretKey::from_slice(&[0x12; 32]).unwrap();
let scan_hex = scan.secret_bytes().to_lower_hex_string();
let spend_pub_hex = spend
.x_only_public_key(&secp)
.0
.serialize()
.to_lower_hex_string();

node.import_keys(&scan_hex, &spend_pub_hex);

let address = node.receive_address();
SilentPaymentAddress::try_from(address.as_str())
.expect("import should yield a valid silent payment address");

node.stop();
}
2 changes: 1 addition & 1 deletion tests/wallet_receive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn receives_a_silent_payment() {
let p2p = core.params.p2p_socket.unwrap();
println!("step 1/5: bitcoind started on regtest");

let node = TestNode::start_connected(p2p);
let node = TestNode::start_connected(p2p, None);
println!("step 2/5: node started and connected to Core");

let secp = Secp256k1::new();
Expand Down
Loading