Skip to content

Commit b6a829f

Browse files
committed
Implement all methods in raw_transactions section
Implement all the methods in the `raw_transactions` section of the API docs. Integration most of them leaving some for another day. This was a long running patch and as such a bunch of other unrelated stuff snuck in - such is the nature of this crate.
1 parent ffd719e commit b6a829f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+6199
-869
lines changed

client/src/client_sync/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ pub mod v26;
1616
pub mod v27;
1717
pub mod v28;
1818

19+
use std::collections::HashMap;
1920
use std::fs::File;
2021
use std::io::{BufRead, BufReader};
2122
use std::path::PathBuf;
2223

23-
use bitcoin::Txid;
24+
use bitcoin::{Address, Amount, Txid};
2425
use serde::{Deserialize, Serialize};
2526

2627
pub use crate::client_sync::error::Error;
@@ -235,6 +236,23 @@ pub struct Input {
235236
pub sequence: Option<bitcoin::Sequence>,
236237
}
237238

239+
/// Output used as parameter to `create_raw_transaction`.
240+
// Abuse `HashMap` so we can derive serialize to get the correct JSON object.
241+
#[derive(Debug, Serialize)]
242+
pub struct Output(
243+
/// Map of address to value. Always only has a single item in it.
244+
HashMap<String, f64>,
245+
);
246+
247+
impl Output {
248+
/// Creates a single output that serializes as Core expects.
249+
pub fn new(addr: Address, value: Amount) -> Self {
250+
let mut map = HashMap::new();
251+
map.insert(addr.to_string(), value.to_btc());
252+
Output(map)
253+
}
254+
}
255+
238256
/// An element in the `inputs` argument of method `walletcreatefundedpsbt`.
239257
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
240258
pub struct WalletCreateFundedPsbtInput {

client/src/client_sync/v17/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,21 @@ crate::impl_client_v17__getnetworkinfo!();
7676
crate::impl_client_v17__getpeerinfo!();
7777

7878
// == Rawtransactions ==
79+
crate::impl_client_v17__combinepsbt!();
80+
crate::impl_client_v17__combinerawtransaction!();
81+
crate::impl_client_v17__converttopsbt!();
82+
crate::impl_client_v17__createpsbt!();
7983
crate::impl_client_v17__createrawtransaction!();
84+
crate::impl_client_v17__decodepsbt!();
85+
crate::impl_client_v17__decoderawtransaction!();
86+
crate::impl_client_v17__decodescript!();
87+
crate::impl_client_v17__finalizepsbt!();
8088
crate::impl_client_v17__fundrawtransaction!();
89+
crate::impl_client_v17__getrawtransaction!();
8190
crate::impl_client_v17__sendrawtransaction!();
91+
crate::impl_client_v17__signrawtransaction!();
92+
crate::impl_client_v17__signrawtransactionwithkey!();
93+
crate::impl_client_v17__testmempoolaccept!();
8294

8395
// == Wallet ==
8496
crate::impl_client_v17__addmultisigaddress!();

client/src/client_sync/v17/raw_transactions.rs

Lines changed: 191 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,67 @@
99
//!
1010
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.
1111
12+
/// Implements Bitcoin Core JSON-RPC API method `combinepsbt`
13+
#[macro_export]
14+
macro_rules! impl_client_v17__combinepsbt {
15+
() => {
16+
impl Client {
17+
pub fn combine_psbt(&self, txs: &[bitcoin::Psbt]) -> Result<CombinePsbt> {
18+
let txs = txs.iter().map(|psbt| format!("{}", psbt)).collect::<Vec<String>>();
19+
self.call("combinepsbt", &[txs.into()])
20+
}
21+
}
22+
};
23+
}
24+
25+
/// Implements Bitcoin Core JSON-RPC API method `combinerawtransaction`
26+
#[macro_export]
27+
macro_rules! impl_client_v17__combinerawtransaction {
28+
() => {
29+
impl Client {
30+
pub fn combine_raw_transaction(
31+
&self,
32+
txs: &[bitcoin::Transaction],
33+
) -> Result<CombineRawTransaction> {
34+
let encoded = txs
35+
.iter()
36+
.map(|tx| bitcoin::consensus::encode::serialize_hex(tx))
37+
.collect::<Vec<String>>();
38+
self.call("combinerawtransaction", &[into_json(encoded)?])
39+
}
40+
}
41+
};
42+
}
43+
44+
/// Implements Bitcoin Core JSON-RPC API method `converttopsbt`
45+
#[macro_export]
46+
macro_rules! impl_client_v17__converttopsbt {
47+
() => {
48+
impl Client {
49+
pub fn convert_to_psbt(&self, tx: &bitcoin::Transaction) -> Result<ConvertToPsbt> {
50+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
51+
self.call("converttopsbt", &[hex.into()])
52+
}
53+
}
54+
};
55+
}
56+
57+
/// Implements Bitcoin Core JSON-RPC API method `createpsbt`
58+
#[macro_export]
59+
macro_rules! impl_client_v17__createpsbt {
60+
() => {
61+
impl Client {
62+
pub fn create_psbt(
63+
&self,
64+
inputs: &[$crate::client_sync::Input],
65+
outputs: &[$crate::client_sync::Output],
66+
) -> Result<CreatePsbt> {
67+
self.call("createpsbt", &[into_json(inputs)?, into_json(outputs)?])
68+
}
69+
}
70+
};
71+
}
72+
1273
/// Implements Bitcoin Core JSON-RPC API method `createrawtransaction`
1374
#[macro_export]
1475
macro_rules! impl_client_v17__createrawtransaction {
@@ -17,24 +78,98 @@ macro_rules! impl_client_v17__createrawtransaction {
1778
pub fn create_raw_transaction(
1879
&self,
1980
inputs: &[$crate::client_sync::Input],
20-
outputs: &std::collections::BTreeMap<String, f64>, // Map of address to amount.
81+
outputs: &[$crate::client_sync::Output],
2182
) -> Result<CreateRawTransaction> {
2283
self.call("createrawtransaction", &[into_json(inputs)?, into_json(outputs)?])
2384
}
2485
}
2586
};
2687
}
2788

89+
/// Implements Bitcoin Core JSON-RPC API method `decodepsbt`
90+
#[macro_export]
91+
macro_rules! impl_client_v17__decodepsbt {
92+
() => {
93+
impl Client {
94+
pub fn decode_psbt(&self, psbt: &str) -> Result<DecodePsbt> {
95+
self.call("decodepsbt", &[psbt.into()])
96+
}
97+
}
98+
};
99+
}
100+
101+
/// Implements Bitcoin Core JSON-RPC API method `finalizepsbt`
102+
#[macro_export]
103+
macro_rules! impl_client_v17__finalizepsbt {
104+
() => {
105+
impl Client {
106+
pub fn finalize_psbt(&self, psbt: &bitcoin::Psbt) -> Result<FinalizePsbt> {
107+
let psbt = format!("{}", psbt);
108+
self.call("finalizepsbt", &[psbt.into()])
109+
}
110+
}
111+
};
112+
}
113+
114+
/// Implements Bitcoin Core JSON-RPC API method `decoderawtransaction`
115+
#[macro_export]
116+
macro_rules! impl_client_v17__decoderawtransaction {
117+
() => {
118+
impl Client {
119+
pub fn decode_raw_transaction(
120+
&self,
121+
tx: &bitcoin::Transaction,
122+
) -> Result<DecodeRawTransaction> {
123+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
124+
self.call("decoderawtransaction", &[hex.into()])
125+
}
126+
}
127+
};
128+
}
129+
130+
/// Implements Bitcoin Core JSON-RPC API method `decodescript`
131+
#[macro_export]
132+
macro_rules! impl_client_v17__decodescript {
133+
() => {
134+
impl Client {
135+
// Arg is the hex encoded script we want to decode.
136+
pub fn decode_script(&self, script: &str) -> Result<DecodeScript> {
137+
self.call("decodescript", &[script.into()])
138+
}
139+
}
140+
};
141+
}
142+
28143
/// Implements Bitcoin Core JSON-RPC API method `fundrawtransaction`
29144
#[macro_export]
30145
macro_rules! impl_client_v17__fundrawtransaction {
31146
() => {
32147
impl Client {
33148
pub fn fund_raw_transaction(
34149
&self,
35-
hex: &str, // Hex encoded transaction.
150+
tx: &bitcoin::Transaction,
36151
) -> Result<FundRawTransaction> {
37-
self.call("fundrawtransaction", &[into_json(hex)?])
152+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
153+
self.call("fundrawtransaction", &[hex.into()])
154+
}
155+
}
156+
};
157+
}
158+
159+
/// Implements Bitcoin Core JSON-RPC API method `getrawtransaction`
160+
#[macro_export]
161+
macro_rules! impl_client_v17__getrawtransaction {
162+
() => {
163+
impl Client {
164+
pub fn get_raw_transaction(&self, txid: bitcoin::Txid) -> Result<GetRawTransaction> {
165+
self.call("getrawtransaction", &[into_json(&txid)?, false.into()])
166+
}
167+
168+
pub fn get_raw_transaction_verbose(
169+
&self,
170+
txid: Txid,
171+
) -> Result<GetRawTransactionVerbose> {
172+
self.call("getrawtransaction", &[into_json(&txid)?, true.into()])
38173
}
39174
}
40175
};
@@ -55,3 +190,56 @@ macro_rules! impl_client_v17__sendrawtransaction {
55190
}
56191
};
57192
}
193+
194+
/// Implements Bitcoin Core JSON-RPC API method `signrawtransaction`
195+
#[macro_export]
196+
macro_rules! impl_client_v17__signrawtransaction {
197+
() => {
198+
impl Client {
199+
pub fn sign_raw_transaction(
200+
&self,
201+
tx: &bitcoin::Transaction,
202+
) -> Result<SignRawTransaction> {
203+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
204+
self.call("signrawtransaction", &[hex.into()])
205+
}
206+
}
207+
};
208+
}
209+
210+
/// Implements Bitcoin Core JSON-RPC API method `signrawtransactionwithkey`
211+
#[macro_export]
212+
macro_rules! impl_client_v17__signrawtransactionwithkey {
213+
() => {
214+
impl Client {
215+
pub fn sign_raw_transaction_with_key(
216+
&self,
217+
tx: &bitcoin::Transaction,
218+
keys: &[bitcoin::PrivateKey],
219+
) -> Result<SignRawTransaction> {
220+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
221+
let keys = keys.iter().map(|k| format!("{}", k)).collect::<Vec<String>>();
222+
self.call("signrawtransactionwithkey", &[hex.into(), into_json(keys)?])
223+
}
224+
}
225+
};
226+
}
227+
228+
/// Implements Bitcoin Core JSON-RPC API method `testmempoolaccept`
229+
#[macro_export]
230+
macro_rules! impl_client_v17__testmempoolaccept {
231+
() => {
232+
impl Client {
233+
pub fn test_mempool_accept(
234+
&self,
235+
txs: &[bitcoin::Transaction],
236+
) -> Result<TestMempoolAccept> {
237+
let encoded = txs
238+
.iter()
239+
.map(|tx| bitcoin::consensus::encode::serialize_hex(tx))
240+
.collect::<Vec<String>>();
241+
self.call("testmempoolaccept", &[into_json(encoded)?])
242+
}
243+
}
244+
};
245+
}

client/src/client_sync/v17/wallet.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,9 @@ macro_rules! impl_client_v17__signrawtransactionwithwallet {
414414
// `hexstring`: The transaction hex string.
415415
pub fn sign_raw_transaction_with_wallet(
416416
&self,
417-
hex: &str,
418-
) -> Result<SignRawTransactionWithWallet> {
417+
tx: &bitcoin::Transaction,
418+
) -> Result<SignRawTransaction> {
419+
let hex = bitcoin::consensus::encode::serialize_hex(tx);
419420
self.call("signrawtransactionwithwallet", &[into_json(hex)?])
420421
}
421422
}

client/src/client_sync/v18/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! We ignore option arguments unless they effect the shape of the returned JSON data.
66
77
pub mod control;
8+
pub mod raw_transactions;
89

910
use std::collections::BTreeMap;
1011
use std::path::Path;
@@ -70,9 +71,24 @@ crate::impl_client_v17__getnetworkinfo!();
7071
crate::impl_client_v17__getpeerinfo!();
7172

7273
// == Rawtransactions ==
74+
crate::impl_client_v18__analyzepsbt!();
75+
crate::impl_client_v17__combinepsbt!();
76+
crate::impl_client_v17__combinerawtransaction!();
77+
crate::impl_client_v17__converttopsbt!();
78+
crate::impl_client_v17__createpsbt!();
7379
crate::impl_client_v17__createrawtransaction!();
80+
crate::impl_client_v17__decodepsbt!();
81+
crate::impl_client_v17__decoderawtransaction!();
82+
crate::impl_client_v17__decodescript!();
83+
crate::impl_client_v17__finalizepsbt!();
7484
crate::impl_client_v17__fundrawtransaction!();
85+
crate::impl_client_v17__getrawtransaction!();
86+
crate::impl_client_v18__joinpsbts!();
7587
crate::impl_client_v17__sendrawtransaction!();
88+
crate::impl_client_v17__signrawtransaction!();
89+
crate::impl_client_v17__signrawtransactionwithkey!();
90+
crate::impl_client_v17__testmempoolaccept!();
91+
crate::impl_client_v18__utxoupdatepsbt!();
7692

7793
// == Wallet ==
7894
crate::impl_client_v17__addmultisigaddress!();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Macros for implementing JSON-RPC methods on a client.
4+
//!
5+
//! Specifically this is methods found under the `== Rawtransactions ==` section of the
6+
//! API docs of Bitcoin Core `v0.18`.
7+
//!
8+
//! All macros require `Client` to be in scope.
9+
//!
10+
//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`.
11+
12+
/// Implements Bitcoin Core JSON-RPC API method `analyzepsbt`
13+
#[macro_export]
14+
macro_rules! impl_client_v18__analyzepsbt {
15+
() => {
16+
impl Client {
17+
pub fn analyze_psbt(&self, psbt: &bitcoin::Psbt) -> Result<AnalyzePsbt> {
18+
let psbt = format!("{}", psbt);
19+
self.call("analyzepsbt", &[psbt.into()])
20+
}
21+
}
22+
};
23+
}
24+
25+
/// Implements Bitcoin Core JSON-RPC API method `joinpsbts`
26+
#[macro_export]
27+
macro_rules! impl_client_v18__joinpsbts {
28+
() => {
29+
impl Client {
30+
pub fn join_psbts(&self, psbts: &[bitcoin::Psbt]) -> Result<JoinPsbts> {
31+
let psbts = psbts.iter().map(|psbt| format!("{}", psbt)).collect::<Vec<String>>();
32+
self.call("joinpsbts", &[psbts.into()])
33+
}
34+
}
35+
};
36+
}
37+
38+
/// Implements Bitcoin Core JSON-RPC API method `uxtoupdatepsbt`
39+
#[macro_export]
40+
macro_rules! impl_client_v18__utxoupdatepsbt {
41+
() => {
42+
impl Client {
43+
pub fn utxo_update_psbt(&self, psbt: &bitcoin::Psbt) -> Result<JoinPsbts> {
44+
let psbt = format!("{}", psbt);
45+
self.call("uxtoupdatepsbt", &[psbt.into()])
46+
}
47+
}
48+
};
49+
}

0 commit comments

Comments
 (0)