Skip to content
Draft
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
4 changes: 4 additions & 0 deletions client/src/client_sync/v17/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod network;
pub mod raw_transactions;
pub mod util;
pub mod wallet;
pub mod zmq;

use std::collections::{BTreeMap, HashMap};
use std::path::Path;
Expand Down Expand Up @@ -159,6 +160,9 @@ crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();

/// Argument to the `Client::get_new_address_with_type` function.
///
/// For Core versions 0.17 through to v22. For Core v23 and onwards use `v23::AddressType`.
Expand Down
6 changes: 5 additions & 1 deletion client/src/client_sync/v17/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,11 @@ macro_rules! impl_client_v17__send_many {
impl Client {
pub fn send_many(&self, amounts: BTreeMap<Address, Amount>) -> Result<SendMany> {
let dummy = ""; // Must be set to "" for backwards compatibility.
self.call("sendmany", &[into_json(dummy)?, into_json(amounts)?])
let amount_btc: BTreeMap<String, f64> = amounts
.into_iter()
.map(|(addr, amount)| (addr.to_string(), amount.to_btc()))
.collect();
self.call("sendmany", &[into_json(dummy)?, into_json(amount_btc)?])
}
}
};
Expand Down
15 changes: 15 additions & 0 deletions client/src/client_sync/v17/zmq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: CC0-1.0

//! Macros for implementing JSON-RPC methods for the `== Zmq ==` section (v0.17).

/// Implements Bitcoin Core JSON-RPC API method `getzmqnotifications`.
#[macro_export]
macro_rules! impl_client_v17__get_zmq_notifications {
() => {
impl Client {
pub fn get_zmq_notifications(&self) -> Result<Vec<GetZmqNotifications>> {
self.call("getzmqnotifications", &[])
}
}
};
}
3 changes: 3 additions & 0 deletions client/src/client_sync/v18/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
3 changes: 3 additions & 0 deletions client/src/client_sync/v19/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
3 changes: 3 additions & 0 deletions client/src/client_sync/v20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v21/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ crate::impl_client_v17__remove_pruned_funds!();
crate::impl_client_v17__rescan_blockchain!();
crate::impl_client_v21__send!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -186,6 +187,9 @@ crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();

/// Request object for the `importdescriptors` method.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
Expand Down
42 changes: 42 additions & 0 deletions client/src/client_sync/v21/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,48 @@ macro_rules! impl_client_v21__send {
};
}

/// Implements Bitcoin Core JSON-RPC API method `sendmany` with `verbose=true` (v21+).
#[macro_export]
macro_rules! impl_client_v21__send_many_verbose {
() => {
impl Client {
pub fn send_many_verbose(
&self,
amounts: BTreeMap<Address, Amount>,
) -> Result<SendManyVerbose> {
let dummy = ""; // Backwards compatibility dummy.
let amount_btc: BTreeMap<String, f64> = amounts
.into_iter()
.map(|(addr, amount)| (addr.to_string(), amount.to_btc()))
.collect();
let minconf = 1u64;
let comment = "";
let subtract_fee_from: Vec<String> = Vec::new();
let replaceable = true;
let conf_target = 1u64;
let estimate_mode = "unset";
let fee_rate = serde_json::Value::Null;
let verbose = true;
self.call(
"sendmany",
&[
into_json(dummy)?,
into_json(amount_btc)?,
minconf.into(),
comment.into(),
into_json(subtract_fee_from)?,
replaceable.into(),
conf_target.into(),
estimate_mode.into(),
fee_rate,
verbose.into(),
],
)
}
}
};
}

/// Implements Bitcoin Core JSON-RPC API method `unloadwallet`.
#[macro_export]
macro_rules! impl_client_v21__unload_wallet {
Expand Down
4 changes: 4 additions & 0 deletions client/src/client_sync/v22/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ crate::impl_client_v17__remove_pruned_funds!();
crate::impl_client_v17__rescan_blockchain!();
crate::impl_client_v21__send!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -188,3 +189,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v23/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ crate::impl_client_v17__rescan_blockchain!();
crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -194,6 +195,9 @@ crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();

/// Argument to the `Client::get_new_address_with_type` function.
///
/// For Core v23 and onwards. For earlier versions use `v17::AddressType`.
Expand Down
4 changes: 4 additions & 0 deletions client/src/client_sync/v24/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -197,3 +198,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v25/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -198,3 +199,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v26/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -207,3 +208,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v27/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -201,3 +202,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v28/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -206,3 +207,6 @@ crate::impl_client_v17__wallet_lock!();
crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();
4 changes: 4 additions & 0 deletions client/src/client_sync/v29/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ crate::impl_client_v23__restore_wallet!();
crate::impl_client_v21__send!();
crate::impl_client_v24__send_all!();
crate::impl_client_v17__send_many!();
crate::impl_client_v21__send_many_verbose!();
crate::impl_client_v17__send_to_address!();
crate::impl_client_v17__set_hd_seed!();
crate::impl_client_v17__set_tx_fee!();
Expand All @@ -207,6 +208,9 @@ crate::impl_client_v17__wallet_passphrase!();
crate::impl_client_v17__wallet_passphrase_change!();
crate::impl_client_v17__wallet_process_psbt!();

// == Zmq ==
crate::impl_client_v17__get_zmq_notifications!();

/// Arg for the `getblocktemplate` method. (v29+).
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub struct TemplateRequest {
Expand Down
56 changes: 56 additions & 0 deletions integration_test/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,31 @@ fn wallet__get_unconfirmed_balance__modelled() {
model.unwrap();
}

#[test]
fn wallet__get_wallet_info__modelled() {
let node = Node::with_wallet(Wallet::Default, &[]);
node.mine_a_block();

let json: GetWalletInfo = node.client.get_wallet_info().expect("getwalletinfo");
let model: Result<mtype::GetWalletInfo, GetWalletInfoError> = json.into_model();
let wallet_info = model.unwrap();

assert!(!wallet_info.wallet_name.is_empty());

#[cfg(not(feature = "v18_and_below"))]
{
assert!(wallet_info.avoid_reuse.is_some());
assert!(wallet_info.scanning.is_some());
}

#[cfg(not(feature = "v25_and_below"))]
{
let last_processed = wallet_info.last_processed_block.as_ref().expect("last_processed_block");
let best_hash = node.client.best_block_hash().expect("best_block_hash");
assert_eq!(last_processed.hash, best_hash);
}
}

#[test]
fn wallet__import_address() {
let node = match () {
Expand Down Expand Up @@ -857,6 +882,37 @@ fn wallet__unload_wallet() {
create_load_unload_wallet();
}

#[test]
fn wallet__send_many__modelled() {
let node = Node::with_wallet(Wallet::Default, &[]);
node.fund_wallet();

let addr1 = node.client.new_address().expect("newaddress");
let addr2 = node.client.new_address().expect("newaddress");

let mut amounts = BTreeMap::new();
amounts.insert(addr1, Amount::from_sat(100_000));
amounts.insert(addr2, Amount::from_sat(100_000));

let json: SendMany = node.client.send_many(amounts.clone()).expect("sendmany");
let model: Result<mtype::SendMany, _> = json.into_model();
let txid = model.unwrap().0;

assert_eq!(txid.to_string().len(), 64);

#[cfg(not(feature = "v20_and_below"))]
{
let json_verbose: SendManyVerbose = node
.client
.send_many_verbose(amounts)
.expect("sendmany verbose");
let model_verbose: Result<mtype::SendManyVerbose, _> = json_verbose.into_model();
let verbose = model_verbose.unwrap();
assert_eq!(verbose.txid.to_string().len(), 64);
assert_eq!(verbose.fee_reason, "Fallback fee");
}
}

#[cfg(not(feature = "v20_and_below"))]
#[test]
fn wallet__send__modelled() {
Expand Down
22 changes: 22 additions & 0 deletions integration_test/tests/zmq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: CC0-1.0

//! Tests for methods found under the `== Zmq ==` section of the API docs.

#![allow(non_snake_case)] // Test names intentionally use double underscore.
#![allow(unused_imports)] // Because of feature gated tests.

use integration_test::{Node, Wallet, NodeExt as _};
use node::vtype::*; // All the version specific types.

#[test]
#[cfg(not(feature = "v17"))]
fn zmq__get_zmq_notifications__modelled() {
// Start node with a ZMQ notification enabled so we have at least one entry.
// Using hashblock as it is lightweight.
let node = Node::with_wallet(Wallet::Default, &["-zmqpubhashblock=tcp://127.0.0.1:29000"]);

let list: Vec<GetZmqNotifications> = node.client.get_zmq_notifications().expect("getzmqnotifications");
let zmq_notification = &list[0];
assert_eq!(zmq_notification.type_, "pubhashblock");
assert_eq!(zmq_notification.address, "tcp://127.0.0.1:29000");
}
16 changes: 8 additions & 8 deletions types/src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ pub use self::{
CreateWallet, DumpPrivKey, GetAddressInfo, GetAddressInfoEmbedded, GetAddressesByLabel,
GetBalance, GetBalances, GetBalancesMine, GetBalancesWatchOnly, GetHdKeys, GetNewAddress,
GetRawChangeAddress, GetReceivedByAddress, GetReceivedByLabel, GetTransaction,
GetTransactionDetail, GetUnconfirmedBalance, GetWalletInfo, HdKey, HdKeyDescriptor,
LastProcessedBlock, ListAddressGroupings, ListAddressGroupingsItem, ListLockUnspent,
ListLockUnspentItem, ListReceivedByAddress, ListReceivedByAddressItem, ListReceivedByLabel,
ListReceivedByLabelItem, ListSinceBlock, ListSinceBlockTransaction, ListTransactions,
ListTransactionsItem, ListUnspent, ListUnspentItem, ListWallets, LoadWallet, PsbtBumpFee,
RescanBlockchain, ScriptType, Send, SendAll, SendMany, SendToAddress, SignMessage,
SimulateRawTransaction, TransactionCategory, UnloadWallet, WalletCreateFundedPsbt,
WalletDisplayAddress, WalletProcessPsbt,
GetTransactionDetail, GetUnconfirmedBalance, GetWalletInfo, GetWalletInfoScanning, HdKey,
HdKeyDescriptor, LastProcessedBlock, ListAddressGroupings, ListAddressGroupingsItem,
ListLockUnspent, ListLockUnspentItem, ListReceivedByAddress, ListReceivedByAddressItem,
ListReceivedByLabel, ListReceivedByLabelItem, ListSinceBlock, ListSinceBlockTransaction,
ListTransactions, ListTransactionsItem, ListUnspent, ListUnspentItem, ListWallets,
LoadWallet, PsbtBumpFee, RescanBlockchain, ScriptType, Send, SendAll, SendMany,
SendManyVerbose, SendToAddress, SignMessage, SimulateRawTransaction, TransactionCategory,
UnloadWallet, WalletCreateFundedPsbt, WalletDisplayAddress, WalletProcessPsbt,
},
};
Loading