From acdc8be17d835c84e0108ff00465a90f9e38499f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 6 Jun 2024 20:31:09 +1000 Subject: [PATCH] Demonstrate usage of new bitcoind-json-rpc repo Demo use of the new repo, has bugs in amount parsing somewhere but I wanted to push this up before the weekend. --- Cargo.toml | 12 +++++++++ bitcoind-tests/Cargo.toml | 32 ++++++++++++++++++++++- bitcoind-tests/tests/setup/mod.rs | 19 ++++++++------ bitcoind-tests/tests/test_cpp.rs | 42 ++++++++++++++----------------- bitcoind-tests/tests/test_desc.rs | 36 +++++++++++++------------- 5 files changed, 92 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c374b480a..679dc8f8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,3 +68,15 @@ required-features = ["std", "base64", "compiler"] [workspace] members = ["bitcoind-tests", "fuzz"] exclude = ["embedded"] + +[patch.crates-io.bitcoind] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" +branch = "06-06-miniscript" + +[patch.crates-io.bitcoind-json-rpc-types] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" +branch = "06-06-miniscript" + +[patch.crates-io.bitcoind-json-rpc-client] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" +branch = "06-06-miniscript" \ No newline at end of file diff --git a/bitcoind-tests/Cargo.toml b/bitcoind-tests/Cargo.toml index a9071a05b..78eff8030 100644 --- a/bitcoind-tests/Cargo.toml +++ b/bitcoind-tests/Cargo.toml @@ -9,6 +9,36 @@ publish = false [dependencies] miniscript = {path = "../"} -bitcoind = { version = "0.36.0" } +bitcoind = { version = "0.37.0" } actual-rand = { package = "rand", version = "0.8.4"} secp256k1 = {version = "0.29.0", features = ["rand-std"]} + +[features] +# Enable the same feature in `bitcoind`. +"26_0" = ["bitcoind/26_0"] +"25_2" = ["bitcoind/25_2"] +"25_1" = ["bitcoind/25_1"] +"25_0" = ["bitcoind/25_0"] +"24_2" = ["bitcoind/24_2"] +"24_1" = ["bitcoind/24_1"] +"24_0_1" = ["bitcoind/24_0_1"] +"23_2" = ["bitcoind/23_2"] +"23_1" = ["bitcoind/23_1"] +"23_0" = ["bitcoind/23_0"] +"22_1" = ["bitcoind/22_1"] +"22_0" = ["bitcoind/22_0"] +"0_21_2" = ["bitcoind/0_21_2"] +"0_20_2" = ["bitcoind/0_20_2"] +"0_19_1" = ["bitcoind/0_19_1"] +"0_18_1" = ["bitcoind/0_18_1"] +"0_17_2" = ["bitcoind/0_17_2"] + + +[patch.crates-io.bitcoind] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" + +[patch.crates-io.bitcoind-json-rpc-types] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" + +[patch.crates-io.bitcoind-json-rpc-client] +git = "https://github.com/tcharding/rust-bitcoind-json-rpc" diff --git a/bitcoind-tests/tests/setup/mod.rs b/bitcoind-tests/tests/setup/mod.rs index 294b564ca..70f418b74 100644 --- a/bitcoind-tests/tests/setup/mod.rs +++ b/bitcoind-tests/tests/setup/mod.rs @@ -1,13 +1,14 @@ extern crate miniscript; -use bitcoind::bitcoincore_rpc::RpcApi; -use bitcoind::BitcoinD; -use miniscript::bitcoin; +use core::convert::TryInto; + +use bitcoind::client::json::model; +use bitcoind::client::bitcoin; pub mod test_util; // Launch an instance of bitcoind with -pub fn setup() -> BitcoinD { +pub fn setup() -> bitcoind::BitcoinD { // Create env var BITCOIND_EXE_PATH to point to the ../bitcoind/bin/bitcoind binary let key = "BITCOIND_EXE"; if std::env::var(key).is_err() { @@ -29,13 +30,15 @@ pub fn setup() -> BitcoinD { let bitcoind = bitcoind::BitcoinD::new(exe_path).unwrap(); let cl = &bitcoind.client; // generate to an address by the wallet. And wait for funds to mature - let addr = cl.get_new_address(None, None).unwrap().assume_checked(); + let addr = cl.new_address().unwrap(); let blks = cl.generate_to_address(101, &addr).unwrap(); - assert_eq!(blks.len(), 101); + assert_eq!(blks.0.len(), 101); + let json = cl.get_balance().expect("failed to get balance"); + let concrete: model::GetBalance = json.try_into().unwrap(); assert_eq!( - cl.get_balance(Some(1) /*min conf*/, None).unwrap(), - bitcoin::Amount::from_sat(100_000_000 * 50) + concrete.0, + bitcoin::Amount::from_sat(100_000_000 * 50), ); bitcoind } diff --git a/bitcoind-tests/tests/test_cpp.rs b/bitcoind-tests/tests/test_cpp.rs index 0e06fd810..eb9741f75 100644 --- a/bitcoind-tests/tests/test_cpp.rs +++ b/bitcoind-tests/tests/test_cpp.rs @@ -8,13 +8,15 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; +use std::convert::TryInto; use bitcoin::hashes::{sha256d, Hash}; use bitcoin::psbt::Psbt; use bitcoin::{ psbt, secp256k1, transaction, Amount, OutPoint, Sequence, Transaction, TxIn, TxOut, Txid, }; -use bitcoind::bitcoincore_rpc::{json, Client, RpcApi}; +use bitcoind::{Client, AddressType}; +use bitcoind::client::json::model; // FIXME: Re-export this from someplace easier. use miniscript::bitcoin::absolute; use miniscript::psbt::PsbtExt; use miniscript::{bitcoin, DefiniteDescriptorKey, Descriptor}; @@ -52,11 +54,10 @@ fn btc>(btc: F) -> Amount { Amount::from_btc(btc.into()).unwrap() } // Ideally, we should find by scriptPubkey, but this // works for temp test case fn get_vout(cl: &Client, txid: Txid, value: Amount) -> (OutPoint, TxOut) { - let tx = cl - .get_transaction(&txid, None) - .unwrap() - .transaction() - .unwrap(); + let json = cl.get_transaction(txid).unwrap(); + let concrete: model::GetTransaction = json.try_into().unwrap(); + let tx = concrete.tx; + for (i, txout) in tx.output.into_iter().enumerate() { if txout.value == value { return (OutPoint::new(txid, i as u32), txout); @@ -72,9 +73,9 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { let pks = &testdata.pubdata.pks; // Generate some blocks let blocks = cl - .generate_to_address(500, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(500, &cl.new_address().unwrap()) .unwrap(); - assert_eq!(blocks.len(), 500); + assert_eq!(blocks.0.len(), 500); // Next send some btc to each address corresponding to the miniscript let mut txids = vec![]; @@ -83,21 +84,15 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { .send_to_address( &wsh.address(bitcoin::Network::Regtest).unwrap(), btc(1), - None, - None, - None, - None, - None, - None, ) .unwrap(); txids.push(txid); } // Wait for the funds to mature. let blocks = cl - .generate_to_address(50, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(50, &cl.new_address().unwrap()) .unwrap(); - assert_eq!(blocks.len(), 50); + assert_eq!(blocks.0.len(), 50); // Create a PSBT for each transaction. // Spend one input and spend one output for simplicity. let mut psbts = vec![]; @@ -131,9 +126,8 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { // the node wallet tracks the receiving transaction // and we can check it by gettransaction RPC. let addr = cl - .get_new_address(None, Some(json::AddressType::Bech32)) - .unwrap() - .assume_checked(); + .new_address_with_type(AddressType::Bech32) + .unwrap(); psbt.unsigned_tx.output.push(TxOut { value: Amount::from_sat(99_999_000), script_pubkey: addr.script_pubkey(), @@ -213,21 +207,23 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { // Send the transactions to bitcoin node for mining. // Regtest mode has standardness checks // Check whether the node accepts the transactions - let txid = cl + let json = cl .send_raw_transaction(&tx) .unwrap_or_else(|_| panic!("{} send tx failed for ms {}", i, ms)); - spend_txids.push(txid); + + let concrete: model::SendRawTransaction = json.try_into().unwrap(); + spend_txids.push(concrete.0); } } // Finally mine the blocks and await confirmations let _blocks = cl - .generate_to_address(10, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(10, &cl.new_address().unwrap()) .unwrap(); // Get the required transactions from the node mined in the blocks. for txid in spend_txids { // Check whether the transaction is mined in blocks // Assert that the confirmations are > 0. - let num_conf = cl.get_transaction(&txid, None).unwrap().info.confirmations; + let num_conf = cl.get_transaction(txid).unwrap().confirmations; assert!(num_conf > 0); } } diff --git a/bitcoind-tests/tests/test_desc.rs b/bitcoind-tests/tests/test_desc.rs index a96c0d067..5112c6af0 100644 --- a/bitcoind-tests/tests/test_desc.rs +++ b/bitcoind-tests/tests/test_desc.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::{error, fmt}; +use std::convert::TryInto; use actual_rand as rand; use bitcoin::blockdata::witness::Witness; @@ -17,7 +18,8 @@ use bitcoin::{ absolute, psbt, secp256k1, sighash, transaction, Amount, OutPoint, Sequence, Transaction, TxIn, TxOut, Txid, }; -use bitcoind::bitcoincore_rpc::{json, Client, RpcApi}; +use bitcoind::client::json::model; // FIXME: Re-export this from someplace easier. +use bitcoind::{Client, AddressType}; use miniscript::bitcoin::{self, ecdsa, taproot, ScriptBuf}; use miniscript::psbt::{PsbtExt, PsbtInputExt}; use miniscript::{Descriptor, Miniscript, ScriptContext, ToPublicKey}; @@ -30,11 +32,10 @@ fn btc>(btc: F) -> Amount { Amount::from_btc(btc.into()).unwrap() } // Find the Outpoint by spk fn get_vout(cl: &Client, txid: Txid, value: Amount, spk: ScriptBuf) -> (OutPoint, TxOut) { - let tx = cl - .get_transaction(&txid, None) - .unwrap() - .transaction() - .unwrap(); + let json = cl.get_transaction(txid).unwrap(); + let concrete: model::GetTransaction = json.try_into().unwrap(); + let tx = concrete.tx; + for (i, txout) in tx.output.into_iter().enumerate() { if txout.value == value && spk == txout.script_pubkey { return (OutPoint::new(txid, i as u32), txout); @@ -77,9 +78,9 @@ pub fn test_desc_satisfy( let x_only_pks = &testdata.pubdata.x_only_pks; // Generate some blocks let blocks = cl - .generate_to_address(1, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(1, &cl.new_address().unwrap()) .unwrap(); - assert_eq!(blocks.len(), 1); + assert_eq!(blocks.0.len(), 1); let definite_desc = test_util::parse_test_desc(descriptor, &testdata.pubdata) .map_err(|_| DescError::DescParseError)? @@ -92,13 +93,13 @@ pub fn test_desc_satisfy( // Next send some btc to each address corresponding to the miniscript let txid = cl - .send_to_address(&desc_address, btc(1), None, None, None, None, None, None) + .send_to_address(&desc_address, btc(1)) .unwrap(); // Wait for the funds to mature. let blocks = cl - .generate_to_address(2, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(2, &cl.new_address().unwrap()) .unwrap(); - assert_eq!(blocks.len(), 2); + assert_eq!(blocks.0.len(), 2); // Create a PSBT for each transaction. // Spend one input and spend one output for simplicity. let mut psbt = Psbt { @@ -130,9 +131,8 @@ pub fn test_desc_satisfy( // the node wallet tracks the receiving transaction // and we can check it by gettransaction RPC. let addr = cl - .get_new_address(None, Some(json::AddressType::Bech32)) - .unwrap() - .assume_checked(); + .new_address_with_type(AddressType::Bech32) + .unwrap(); // Had to decrease 'value', so that fees can be increased // (Was getting insufficient fees error, for deep script trees) psbt.unsigned_tx @@ -285,18 +285,20 @@ pub fn test_desc_satisfy( // Send the transactions to bitcoin node for mining. // Regtest mode has standardness checks // Check whether the node accepts the transactions - let txid = cl + let json = cl .send_raw_transaction(&tx) .unwrap_or_else(|_| panic!("send tx failed for desc {}", definite_desc)); + let concrete: model::SendRawTransaction = json.try_into().unwrap(); + let txid = concrete.0; // Finally mine the blocks and await confirmations let _blocks = cl - .generate_to_address(1, &cl.get_new_address(None, None).unwrap().assume_checked()) + .generate_to_address(1, &cl.new_address().unwrap()) .unwrap(); // Get the required transactions from the node mined in the blocks. // Check whether the transaction is mined in blocks // Assert that the confirmations are > 0. - let num_conf = cl.get_transaction(&txid, None).unwrap().info.confirmations; + let num_conf = cl.get_transaction(txid).unwrap().confirmations; assert!(num_conf > 0); Ok(tx.input[0].witness.clone()) }