commit a8ef065e84b5628db961eb87fc54822cb242db19
parent 8e866a37cbfbea19b7da6c062fea493efa26acdc
Author: Antoine A <>
Date: Wed, 17 Nov 2021 15:12:15 +0100
Make integration test run on testnet
Diffstat:
3 files changed, 144 insertions(+), 35 deletions(-)
diff --git a/src/bin/test.rs b/src/bin/test.rs
@@ -1,12 +1,13 @@
use core::panic;
-use std::panic::AssertUnwindSafe;
+use std::{collections::HashSet, panic::AssertUnwindSafe};
use bitcoincore_rpc::{
- bitcoin::{Address, Amount},
+ bitcoin::{Address, Amount, Txid},
+ json::GetTransactionResultDetailCategory as Category,
Client, RpcApi,
};
use depolymerization::{
- rpc::{common_rpc, dirty_guess_network, last_transaction, wallet_rpc, Network, CLIENT, WIRE},
+ rpc::{common_rpc, dirty_guess_network, network_dir_path, wallet_rpc, Network, CLIENT, WIRE},
utils::rand_key,
ClientExtended,
};
@@ -18,73 +19,173 @@ use owo_colors::OwoColorize;
/// As we test against an bitcoin JSON-RPC server and ordering of transaction is important
/// we want our tests to run sequentially and share commons rpc connections.
pub fn main() {
- let network = dirty_guess_network();
+ let test_amount = Amount::from_sat(420);
+ // Network check
+ let network = dirty_guess_network();
match network {
Network::MainNet => {
panic!("Do not run tests on the mainnet, you are going to loose money")
}
- Network::TestNet => println!("Running on testnet, slow network mining"),
+ Network::TestNet => println!("{}", "Running on testnet, slow network mining".yellow()),
Network::RegTest => println!("Running on regtest, fast manual mining"),
}
- let rpc = common_rpc(network).unwrap();
- rpc.load_wallet(&WIRE).ok();
- rpc.load_wallet(&CLIENT).ok();
+
+ // Wallet check
+ {
+ let existing_wallets: HashSet<String> =
+ std::fs::read_dir(network_dir_path(network).join("wallets"))
+ .unwrap()
+ .filter_map(|it| it.ok())
+ .map(|it| it.file_name().to_string_lossy().to_string())
+ .collect();
+
+ let rpc = common_rpc(network).expect("Failed to open common client");
+ if !existing_wallets.contains(CLIENT) || !existing_wallets.contains(WIRE) {
+ println!("Generate tests wallets");
+ // Create wallets
+ rpc.create_wallet(&WIRE, None, None, None, None).unwrap();
+ rpc.create_wallet(&CLIENT, None, None, None, None).unwrap();
+ }
+
+ // Load wallets
+ rpc.load_wallet(&WIRE).ok();
+ rpc.load_wallet(&CLIENT).ok();
+ }
+
+ // Client initialization
let client_rpc = wallet_rpc(network, CLIENT);
let wire_rpc = wallet_rpc(network, WIRE);
let client_addr = client_rpc.get_new_address(None, None).unwrap();
let wire_addr = wire_rpc.get_new_address(None, None).unwrap();
- println!(
- "Initial state:\n{} {}\n{} {}",
- WIRE,
- wire_rpc.get_balance(None, None).unwrap(),
- CLIENT,
- client_rpc.get_balance(None, None).unwrap()
- );
+
+ // Balance check
+ {
+ let balance = client_rpc.get_balance(None, None).unwrap();
+ let min_balance = test_amount * 3;
+ if balance < min_balance {
+ println!(
+ "{}",
+ format_args!(
+ "Client wallet have only {}, {} are required to perform the test",
+ balance, min_balance
+ )
+ .yellow()
+ );
+ match network {
+ Network::MainNet | Network::TestNet => {
+ if network == Network::MainNet {
+ println!("Send coins to this address: {}", client_addr);
+ } else {
+ println!("Request coins from a faucet such as https://bitcoinfaucet.uo1.net/send.php to this address: {}", client_addr);
+ }
+ println!("Waiting for the transaction...");
+ while client_rpc.get_balance(None, None).unwrap() < min_balance {
+ client_rpc.wait_for_new_block(0).ok();
+ }
+ }
+ Network::RegTest => {
+ println!("Add 50B to client wallet");
+ client_rpc
+ .generate_to_address(
+ 101, /* Need 100 blocks to validate */
+ &client_addr,
+ )
+ .unwrap();
+ }
+ }
+ }
+
+ println!(
+ "Initial state:\n{} {}\n{} {}",
+ WIRE,
+ wire_rpc.get_balance(None, None).unwrap(),
+ CLIENT,
+ client_rpc.get_balance(None, None).unwrap()
+ );
+ }
run_test("OpReturn metadata", || {
+ // Send metadata
let msg = "J'aime le chocolat".as_bytes();
- client_rpc
- .send_op_return(&wire_addr, Amount::from_sat(4200), msg)
+ let id = client_rpc
+ .send_op_return(&wire_addr, test_amount, msg)
.unwrap();
+ // Check in mempool
+ assert!(
+ tx_exist(&client_rpc, &id, 0, Category::Send).unwrap(),
+ "Not in mempool"
+ );
+ // Check mined
next_block(network, &client_rpc, &client_addr);
- let last = last_transaction(&wire_rpc).unwrap();
- let (_, decoded) = wire_rpc.get_tx_op_return(&last).unwrap();
- assert_eq!(&msg, &decoded.as_slice());
+ assert!(
+ tx_exist(&wire_rpc, &id, 1, Category::Receive).unwrap(),
+ "Not mined"
+ );
+ // Check extract
+ let (_, extracted) = wire_rpc.get_tx_op_return(&id).unwrap();
+ assert_eq!(msg, extracted, "Corrupted metadata");
});
run_test("SegWit metadata", || {
+ // Send metadata
let key = rand_key();
- client_rpc
- .send_segwit_key(&wire_addr, Amount::from_sat(4200), &key)
+ let id = client_rpc
+ .send_segwit_key(&wire_addr, test_amount, &key)
.unwrap();
+ // Check in mempool
+ assert!(
+ tx_exist(&client_rpc, &id, 0, Category::Send).unwrap(),
+ "Not in mempool"
+ );
+ // Check mined
next_block(network, &client_rpc, &client_addr);
- let last = last_transaction(&wire_rpc).unwrap();
- let (_, decoded) = wire_rpc.get_tx_segwit_key(&last).unwrap();
- assert_eq!(key, decoded);
+ assert!(
+ tx_exist(&wire_rpc, &id, 1, Category::Receive).unwrap(),
+ "Not mined"
+ );
+ // Check extract
+ let (_, extracted) = wire_rpc.get_tx_segwit_key(&id).unwrap();
+ assert_eq!(key, extracted, "Corrupted metadata");
});
}
fn next_block(network: Network, rpc: &Client, address: &Address) {
match network {
- Network::TestNet => {
+ Network::RegTest => {
// Manually mine a block
rpc.generate_to_address(1, address).unwrap();
}
_ => {
// Wait for the next block
- rpc.wait_for_new_block(60 * 60 * 1000).unwrap();
+ rpc.wait_for_new_block(0).ok();
}
}
}
fn run_test(name: &str, test: impl FnOnce() -> ()) -> bool {
- println!("{}", name.cyan());
+ println!("{}", format_args!("{} start", name).cyan());
let result = std::panic::catch_unwind(AssertUnwindSafe(test));
if result.is_ok() {
- println!("{}", "Ok".green())
+ println!("{}", format_args!("{} OK", name).green())
} else {
- println!("{}", "Err".red())
+ dbg!(&result);
+ println!("{}", format_args!("{} ERR", name).red())
}
return result.is_ok();
}
+
+fn tx_exist(
+ rpc: &Client,
+ id: &Txid,
+ min_confirmation: i32,
+ detail: Category,
+) -> bitcoincore_rpc::Result<bool> {
+ let txs = rpc.list_transactions(None, None, None, None).unwrap();
+ let found = txs.into_iter().any(|tx| {
+ tx.detail.category == detail
+ && tx.info.confirmations >= min_confirmation
+ && tx.info.txid == *id
+ });
+ Ok(found)
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -320,10 +320,9 @@ pub mod rpc {
pub const CLIENT: &str = "client";
pub const WIRE: &str = "wire";
- pub const RPC_URL: &str = "http://localhost:18443";
/// Bitcoin networks
- #[derive(Debug, Clone, Copy)]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Network {
MainNet,
TestNet,
@@ -340,6 +339,15 @@ pub mod rpc {
}
}
+ pub fn rpc_url(network: Network) -> String {
+ let port = match network {
+ Network::MainNet => 8332,
+ Network::TestNet => 18332,
+ Network::RegTest => 18443,
+ };
+ format!("https://127.0.0.1:{}", port)
+ }
+
pub fn data_dir_path() -> PathBuf {
// https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md#:~:text=By%20default%2C%20the%20configuration%20file,file%3E%20option%20in%20the%20bitcoin.
if cfg!(target_os = "windows") {
@@ -365,14 +373,14 @@ pub mod rpc {
pub fn common_rpc(network: Network) -> bitcoincore_rpc::Result<Client> {
Client::new(
- RPC_URL,
+ &rpc_url(network),
Auth::CookieFile(network_dir_path(network).join(".cookie")),
)
}
pub fn wallet_rpc(network: Network, wallet: &str) -> Client {
Client::new(
- &format!("{}/wallet/{}", RPC_URL, wallet),
+ &format!("{}/wallet/{}", rpc_url(network), wallet),
Auth::CookieFile(network_dir_path(network).join(".cookie")),
)
.expect(&format!("Failed to open wallet '{}' client", wallet))
diff --git a/src/main.rs b/src/main.rs
@@ -214,7 +214,7 @@ fn main() {
println!("Receive message using {}", method.to_string());
let (_, mut hash) = received_since(&wire_rpc, None).unwrap();
loop {
- wire_rpc.wait_for_new_block(60 * 60 * 1000).ok();
+ wire_rpc.wait_for_new_block(0).ok();
println!("new block");
let (ids, nhash) = received_since(&wire_rpc, Some(&hash)).unwrap();
hash = nhash;