1use std::collections::HashMap;
2use std::fs::File;
3use std::io::{BufRead, BufReader};
4use std::path::PathBuf;
5use std::{fmt, result};
6
7use base64::Engine;
8use base64::engine::general_purpose;
9use bitcoin::address::{NetworkChecked, NetworkUnchecked};
10use bitcoin::consensus::encode;
11use bitcoin::hashes::hex::FromHex;
12use bitcoin::hex::DisplayHex;
13use bitcoin::secp256k1::ecdsa::Signature;
14use bitcoin::{Address, Amount, Block, OutPoint, PrivateKey, PublicKey, Script, Transaction};
15use http::{HeaderMap, HeaderValue, header};
16use jsonrpsee::core::client::ClientT;
17use jsonrpsee::core::params::ArrayParams;
18use serde::{self, Deserialize, Serialize};
19
20use crate::error::*;
21use crate::queryable;
22
23const NOPARAMS: &[serde_json::Value] = &[];
24
25pub type Result<T> = result::Result<T, Error>;
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct JsonOutPoint {
33 pub txid: bitcoin::Txid,
34 pub vout: u32,
35}
36
37impl From<OutPoint> for JsonOutPoint {
38 fn from(o: OutPoint) -> JsonOutPoint {
39 JsonOutPoint {
40 txid: o.txid,
41 vout: o.vout,
42 }
43 }
44}
45
46impl From<JsonOutPoint> for OutPoint {
47 fn from(val: JsonOutPoint) -> Self {
48 OutPoint {
49 txid: val.txid,
50 vout: val.vout,
51 }
52 }
53}
54
55fn into_json<T>(val: T) -> Result<serde_json::Value>
57where
58 T: serde::ser::Serialize,
59{
60 Ok(serde_json::to_value(val)?)
61}
62
63fn opt_into_json<T>(opt: Option<T>) -> Result<serde_json::Value>
65where
66 T: serde::ser::Serialize,
67{
68 match opt {
69 Some(val) => Ok(into_json(val)?),
70 None => Ok(serde_json::Value::Null),
71 }
72}
73
74fn null() -> serde_json::Value {
76 serde_json::Value::Null
77}
78
79fn empty_arr() -> serde_json::Value {
81 serde_json::Value::Array(vec![])
82}
83
84fn empty_obj() -> serde_json::Value {
86 serde_json::Value::Object(Default::default())
87}
88
89fn handle_defaults<'a>(
105 args: &'a mut [serde_json::Value],
106 defaults: &[serde_json::Value],
107) -> &'a [serde_json::Value] {
108 assert!(args.len() >= defaults.len());
109
110 let mut first_non_null_optional_idx = None;
113 for i in 0..defaults.len() {
114 let args_i = args.len() - 1 - i;
115 let defaults_i = defaults.len() - 1 - i;
116 if args[args_i] == serde_json::Value::Null {
117 if first_non_null_optional_idx.is_some() {
118 if defaults[defaults_i] == serde_json::Value::Null {
119 panic!("Missing `default` for argument idx {args_i}");
120 }
121 args[args_i] = defaults[defaults_i].clone();
122 }
123 } else if first_non_null_optional_idx.is_none() {
124 first_non_null_optional_idx = Some(args_i);
125 }
126 }
127
128 let required_num = args.len() - defaults.len();
129
130 if let Some(i) = first_non_null_optional_idx {
131 &args[..i + 1]
132 } else {
133 &args[..required_num]
134 }
135}
136
137fn opt_result<T: for<'a> serde::de::Deserialize<'a>>(
139 result: serde_json::Value,
140) -> Result<Option<T>> {
141 if result == serde_json::Value::Null {
142 Ok(None)
143 } else {
144 Ok(serde_json::from_value(result)?)
145 }
146}
147
148pub trait RawTx: Sized + Clone {
150 fn raw_hex(self) -> String;
151}
152
153impl RawTx for &Transaction {
154 fn raw_hex(self) -> String {
155 encode::serialize_hex(self)
156 }
157}
158
159impl RawTx for &[u8] {
160 fn raw_hex(self) -> String {
161 self.to_lower_hex_string()
162 }
163}
164
165impl RawTx for &Vec<u8> {
166 fn raw_hex(self) -> String {
167 self.to_lower_hex_string()
168 }
169}
170
171impl RawTx for &str {
172 fn raw_hex(self) -> String {
173 self.to_owned()
174 }
175}
176
177impl RawTx for String {
178 fn raw_hex(self) -> String {
179 self
180 }
181}
182
183#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
185pub enum Auth {
186 None,
187 Basic {
188 username: String,
189 password: String,
190 },
191 CookieFile(PathBuf),
192 Bearer(String),
193}
194
195impl Auth {
196 pub fn auth(self, headers: &mut HeaderMap) -> Result<()> {
198 match self {
199 Auth::None => Ok(()), Auth::Basic {
201 username,
202 password,
203 } => {
204 let encoded = general_purpose::STANDARD.encode(format!("{username}:{password}"));
205 let auth_value = format!("Basic {encoded}");
206 headers.insert(
207 header::AUTHORIZATION,
208 HeaderValue::from_str(&auth_value).unwrap(),
210 );
211 Ok(())
212 }
213 Auth::CookieFile(path) => {
214 let line = BufReader::new(File::open(path)?)
215 .lines()
216 .next()
217 .ok_or(Error::InvalidCookieFile)??;
218 let colon = line.find(':').ok_or(Error::InvalidCookieFile)?;
219 let username = &line[..colon];
220 let password = &line[colon + 1..];
221 let encoded = general_purpose::STANDARD.encode(format!("{username}:{password}",));
222 let auth_value = format!("Basic {encoded}");
223 headers.insert(header::AUTHORIZATION, HeaderValue::from_str(&auth_value).unwrap());
225 Ok(())
226 }
227 Auth::Bearer(token) => {
228 let auth_value = format!("Bearer {token}");
229 headers.insert(header::AUTHORIZATION, HeaderValue::from_str(&auth_value).unwrap());
231 Ok(())
232 }
233 }
234 }
235}
236
237#[async_trait::async_trait]
238#[allow(clippy::too_many_arguments)]
239pub trait RpcApi: Sized {
240 async fn call<T: for<'de> serde::de::Deserialize<'de>>(
242 &self,
243 method: &str,
244 params: &[serde_json::Value],
245 ) -> Result<T>;
246
247 async fn get_by_id<T: queryable::Queryable<Self>>(
249 &self,
250 id: &<T as queryable::Queryable<Self>>::Id,
251 ) -> Result<T>
252 where
253 <T as queryable::Queryable<Self>>::Id: Sync,
254 {
255 T::query(self, id).await
256 }
257
258 async fn get_network_info(&self) -> Result<bitcoin_json::GetNetworkInfoResult> {
259 self.call("getnetworkinfo", NOPARAMS).await
260 }
261
262 async fn get_index_info(&self) -> Result<bitcoin_json::GetIndexInfoResult> {
263 self.call("getindexinfo", NOPARAMS).await
264 }
265
266 async fn version(&self) -> Result<usize> {
267 #[derive(Deserialize)]
268 struct Response {
269 pub version: usize,
270 }
271 let res: Response = self.call("getnetworkinfo", NOPARAMS).await?;
272 Ok(res.version)
273 }
274
275 async fn add_multisig_address(
276 &self,
277 nrequired: usize,
278 keys: &[bitcoin_json::PubKeyOrAddress],
279 label: Option<&str>,
280 address_type: Option<bitcoin_json::AddressType>,
281 ) -> Result<bitcoin_json::AddMultiSigAddressResult> {
282 let mut args = [
283 into_json(nrequired)?,
284 into_json(keys)?,
285 opt_into_json(label)?,
286 opt_into_json(address_type)?,
287 ];
288 self.call(
289 "addmultisigaddress",
290 handle_defaults(&mut args, [into_json("")?, null()].as_slice()),
291 )
292 .await
293 }
294
295 async fn load_wallet(&self, wallet: &str) -> Result<bitcoin_json::LoadWalletResult> {
296 self.call("loadwallet", [wallet.into()].as_slice()).await
297 }
298
299 async fn unload_wallet(
300 &self,
301 wallet: Option<&str>,
302 ) -> Result<Option<bitcoin_json::UnloadWalletResult>> {
303 let mut args = [opt_into_json(wallet)?];
304 self.call("unloadwallet", handle_defaults(&mut args, [null()].as_slice())).await
305 }
306
307 async fn create_wallet(
308 &self,
309 wallet: &str,
310 disable_private_keys: Option<bool>,
311 blank: Option<bool>,
312 passphrase: Option<&str>,
313 avoid_reuse: Option<bool>,
314 ) -> Result<bitcoin_json::LoadWalletResult> {
315 let mut args = [
316 wallet.into(),
317 opt_into_json(disable_private_keys)?,
318 opt_into_json(blank)?,
319 opt_into_json(passphrase)?,
320 opt_into_json(avoid_reuse)?,
321 ];
322 self.call(
323 "createwallet",
324 handle_defaults(
325 &mut args,
326 [false.into(), false.into(), into_json("")?, false.into()].as_slice(),
327 ),
328 )
329 .await
330 }
331
332 async fn list_wallets(&self) -> Result<Vec<String>> {
333 self.call("listwallets", NOPARAMS).await
334 }
335
336 async fn list_wallet_dir(&self) -> Result<Vec<String>> {
337 let result: bitcoin_json::ListWalletDirResult =
338 self.call("listwalletdir", NOPARAMS).await?;
339 let names = result.wallets.into_iter().map(|x| x.name).collect();
340 Ok(names)
341 }
342
343 async fn get_wallet_info(&self) -> Result<bitcoin_json::GetWalletInfoResult> {
344 self.call("getwalletinfo", NOPARAMS).await
345 }
346
347 async fn backup_wallet(&self, destination: Option<&str>) -> Result<()> {
348 let mut args = [opt_into_json(destination)?];
349 self.call("backupwallet", handle_defaults(&mut args, [null()].as_slice())).await
350 }
351
352 async fn dump_private_key(&self, address: &Address) -> Result<PrivateKey> {
353 self.call("dumpprivkey", [address.to_string().into()].as_slice()).await
354 }
355
356 async fn encrypt_wallet(&self, passphrase: &str) -> Result<()> {
357 self.call("encryptwallet", [into_json(passphrase)?].as_slice()).await
358 }
359
360 async fn get_difficulty(&self) -> Result<f64> {
361 self.call("getdifficulty", NOPARAMS).await
362 }
363
364 async fn get_connection_count(&self) -> Result<usize> {
365 self.call("getconnectioncount", NOPARAMS).await
366 }
367
368 async fn get_block(&self, hash: &bitcoin::BlockHash) -> Result<Block> {
369 let hex: String = self.call("getblock", [into_json(hash)?, 0.into()].as_slice()).await?;
370 Ok(encode::deserialize_hex(&hex)?)
371 }
372
373 async fn get_block_hex(&self, hash: &bitcoin::BlockHash) -> Result<String> {
374 self.call("getblock", [into_json(hash)?, 0.into()].as_slice()).await
375 }
376
377 async fn get_block_info(
378 &self,
379 hash: &bitcoin::BlockHash,
380 ) -> Result<bitcoin_json::GetBlockResult> {
381 self.call("getblock", [into_json(hash)?, 1.into()].as_slice()).await
382 }
383
384 async fn get_block_header(&self, hash: &bitcoin::BlockHash) -> Result<bitcoin::block::Header> {
387 let hex: String =
388 self.call("getblockheader", [into_json(hash)?, false.into()].as_slice()).await?;
389 Ok(encode::deserialize_hex(&hex)?)
390 }
391
392 async fn get_block_header_info(
393 &self,
394 hash: &bitcoin::BlockHash,
395 ) -> Result<bitcoin_json::GetBlockHeaderResult> {
396 self.call("getblockheader", [into_json(hash)?, true.into()].as_slice()).await
397 }
398
399 async fn get_mining_info(&self) -> Result<bitcoin_json::GetMiningInfoResult> {
400 self.call("getmininginfo", NOPARAMS).await
401 }
402
403 async fn get_block_template(
404 &self,
405 mode: bitcoin_json::GetBlockTemplateModes,
406 rules: &[bitcoin_json::GetBlockTemplateRules],
407 capabilities: &[bitcoin_json::GetBlockTemplateCapabilities],
408 ) -> Result<bitcoin_json::GetBlockTemplateResult> {
409 #[derive(Serialize)]
410 struct Argument<'a> {
411 mode: bitcoin_json::GetBlockTemplateModes,
412 rules: &'a [bitcoin_json::GetBlockTemplateRules],
413 capabilities: &'a [bitcoin_json::GetBlockTemplateCapabilities],
414 }
415
416 self.call(
417 "getblocktemplate",
418 [into_json(Argument {
419 mode,
420 rules,
421 capabilities,
422 })?]
423 .as_slice(),
424 )
425 .await
426 }
427
428 async fn get_blockchain_info(&self) -> Result<bitcoin_json::GetBlockchainInfoResult> {
431 let mut raw: serde_json::Value = self.call("getblockchaininfo", NOPARAMS).await?;
432 Ok(if self.version().await? < 190000 {
436 use crate::Error::UnexpectedStructure as err;
437
438 let (bip9_softforks, old_softforks) = {
441 let map = raw.as_object_mut().ok_or(err)?;
442 let bip9_softforks = map.remove("bip9_softforks").ok_or(err)?;
443 let old_softforks = map.remove("softforks").ok_or(err)?;
444 map.insert("softforks".into(), serde_json::Map::new().into());
446 (bip9_softforks, old_softforks)
447 };
448 let mut ret: bitcoin_json::GetBlockchainInfoResult = serde_json::from_value(raw)?;
449
450 for sf in old_softforks.as_array().ok_or(err)?.iter() {
452 let json = sf.as_object().ok_or(err)?;
453 let id = json.get("id").ok_or(err)?.as_str().ok_or(err)?;
454 let reject = json.get("reject").ok_or(err)?.as_object().ok_or(err)?;
455 let active = reject.get("status").ok_or(err)?.as_bool().ok_or(err)?;
456 ret.softforks.insert(
457 id.into(),
458 bitcoin_json::Softfork {
459 type_: bitcoin_json::SoftforkType::Buried,
460 bip9: None,
461 height: None,
462 active,
463 },
464 );
465 }
466 for (id, sf) in bip9_softforks.as_object().ok_or(err)?.iter() {
467 #[derive(Deserialize)]
468 struct OldBip9SoftFork {
469 pub status: bitcoin_json::Bip9SoftforkStatus,
470 pub bit: Option<u8>,
471 #[serde(rename = "startTime")]
472 pub start_time: i64,
473 pub timeout: u64,
474 pub since: u32,
475 pub statistics: Option<bitcoin_json::Bip9SoftforkStatistics>,
476 }
477 let sf: OldBip9SoftFork = serde_json::from_value(sf.clone())?;
478 ret.softforks.insert(
479 id.clone(),
480 bitcoin_json::Softfork {
481 type_: bitcoin_json::SoftforkType::Bip9,
482 bip9: Some(bitcoin_json::Bip9SoftforkInfo {
483 status: sf.status,
484 bit: sf.bit,
485 start_time: sf.start_time,
486 timeout: sf.timeout,
487 since: sf.since,
488 statistics: sf.statistics,
489 }),
490 height: None,
491 active: sf.status == bitcoin_json::Bip9SoftforkStatus::Active,
492 },
493 );
494 }
495 ret
496 } else {
497 serde_json::from_value(raw)?
498 })
499 }
500
501 async fn get_block_count(&self) -> Result<u64> {
503 self.call("getblockcount", NOPARAMS).await
504 }
505
506 async fn get_best_block_hash(&self) -> Result<bitcoin::BlockHash> {
508 self.call("getbestblockhash", NOPARAMS).await
509 }
510
511 async fn get_block_hash(&self, height: u64) -> Result<bitcoin::BlockHash> {
513 self.call("getblockhash", [height.into()].as_slice()).await
514 }
515
516 async fn get_block_stats(&self, height: u64) -> Result<bitcoin_json::GetBlockStatsResult> {
517 self.call("getblockstats", [height.into()].as_slice()).await
518 }
519
520 async fn get_block_stats_fields(
521 &self,
522 height: u64,
523 fields: &[bitcoin_json::BlockStatsFields],
524 ) -> Result<bitcoin_json::GetBlockStatsResultPartial> {
525 self.call("getblockstats", [height.into(), fields.into()].as_slice()).await
526 }
527
528 async fn get_raw_transaction(
529 &self,
530 txid: &bitcoin::Txid,
531 block_hash: Option<&bitcoin::BlockHash>,
532 ) -> Result<Transaction> {
533 let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
534 let hex: String =
535 self.call("getrawtransaction", handle_defaults(&mut args, [null()].as_slice())).await?;
536 Ok(encode::deserialize_hex(&hex)?)
537 }
538
539 async fn get_raw_transaction_hex(
540 &self,
541 txid: &bitcoin::Txid,
542 block_hash: Option<&bitcoin::BlockHash>,
543 ) -> Result<String> {
544 let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
545 self.call("getrawtransaction", handle_defaults(&mut args, [null()].as_slice())).await
546 }
547
548 async fn get_raw_transaction_info(
549 &self,
550 txid: &bitcoin::Txid,
551 block_hash: Option<&bitcoin::BlockHash>,
552 ) -> Result<bitcoin_json::GetRawTransactionResult> {
553 let mut args = [into_json(txid)?, into_json(true)?, opt_into_json(block_hash)?];
554 self.call("getrawtransaction", handle_defaults(&mut args, [null()].as_slice())).await
555 }
556
557 async fn get_block_filter(
558 &self,
559 block_hash: &bitcoin::BlockHash,
560 ) -> Result<bitcoin_json::GetBlockFilterResult> {
561 self.call("getblockfilter", [into_json(block_hash)?].as_slice()).await
562 }
563
564 async fn get_balance(
565 &self,
566 minconf: Option<usize>,
567 include_watchonly: Option<bool>,
568 ) -> Result<Amount> {
569 let mut args = ["*".into(), opt_into_json(minconf)?, opt_into_json(include_watchonly)?];
570 Ok(Amount::from_btc(
571 self.call("getbalance", handle_defaults(&mut args, [0.into(), null()].as_slice()))
572 .await?,
573 )?)
574 }
575
576 async fn get_balances(&self) -> Result<bitcoin_json::GetBalancesResult> {
577 self.call("getbalances", NOPARAMS).await
578 }
579
580 async fn get_received_by_address(
581 &self,
582 address: &Address,
583 minconf: Option<u32>,
584 ) -> Result<Amount> {
585 let mut args = [address.to_string().into(), opt_into_json(minconf)?];
586 Ok(Amount::from_btc(
587 self.call("getreceivedbyaddress", handle_defaults(&mut args, [null()].as_slice()))
588 .await?,
589 )?)
590 }
591
592 async fn get_transaction(
593 &self,
594 txid: &bitcoin::Txid,
595 include_watchonly: Option<bool>,
596 ) -> Result<bitcoin_json::GetTransactionResult> {
597 let mut args = [into_json(txid)?, opt_into_json(include_watchonly)?];
598 self.call("gettransaction", handle_defaults(&mut args, [null()].as_slice())).await
599 }
600
601 async fn list_transactions(
602 &self,
603 label: Option<&str>,
604 count: Option<usize>,
605 skip: Option<usize>,
606 include_watchonly: Option<bool>,
607 ) -> Result<Vec<bitcoin_json::ListTransactionResult>> {
608 let mut args = [
609 label.unwrap_or("*").into(),
610 opt_into_json(count)?,
611 opt_into_json(skip)?,
612 opt_into_json(include_watchonly)?,
613 ];
614 self.call(
615 "listtransactions",
616 handle_defaults(&mut args, [10.into(), 0.into(), null()].as_slice()),
617 )
618 .await
619 }
620
621 async fn list_since_block(
622 &self,
623 blockhash: Option<&bitcoin::BlockHash>,
624 target_confirmations: Option<usize>,
625 include_watchonly: Option<bool>,
626 include_removed: Option<bool>,
627 ) -> Result<bitcoin_json::ListSinceBlockResult> {
628 let mut args = [
629 opt_into_json(blockhash)?,
630 opt_into_json(target_confirmations)?,
631 opt_into_json(include_watchonly)?,
632 opt_into_json(include_removed)?,
633 ];
634 self.call("listsinceblock", handle_defaults(&mut args, [null()].as_slice())).await
635 }
636
637 async fn get_tx_out(
638 &self,
639 txid: &bitcoin::Txid,
640 vout: u32,
641 include_mempool: Option<bool>,
642 ) -> Result<Option<bitcoin_json::GetTxOutResult>> {
643 let mut args = [into_json(txid)?, into_json(vout)?, opt_into_json(include_mempool)?];
644 opt_result(self.call("gettxout", handle_defaults(&mut args, [null()].as_slice())).await?)
645 }
646
647 async fn get_tx_out_proof(
648 &self,
649 txids: &[bitcoin::Txid],
650 block_hash: Option<&bitcoin::BlockHash>,
651 ) -> Result<Vec<u8>> {
652 let mut args = [into_json(txids)?, opt_into_json(block_hash)?];
653 let hex: String =
654 self.call("gettxoutproof", handle_defaults(&mut args, [null()].as_slice())).await?;
655 Ok(FromHex::from_hex(&hex)?)
657 }
658
659 async fn import_public_key(
660 &self,
661 pubkey: &PublicKey,
662 label: Option<&str>,
663 rescan: Option<bool>,
664 ) -> Result<()> {
665 let mut args = [pubkey.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
666 self.call("importpubkey", handle_defaults(&mut args, [into_json("")?, null()].as_slice()))
667 .await
668 }
669
670 async fn import_private_key(
671 &self,
672 privkey: &PrivateKey,
673 label: Option<&str>,
674 rescan: Option<bool>,
675 ) -> Result<()> {
676 let mut args = [privkey.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
677 self.call("importprivkey", handle_defaults(&mut args, [into_json("")?, null()].as_slice()))
678 .await
679 }
680
681 async fn import_address(
682 &self,
683 address: &Address,
684 label: Option<&str>,
685 rescan: Option<bool>,
686 ) -> Result<()> {
687 let mut args = [address.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
688 self.call("importaddress", handle_defaults(&mut args, [into_json("")?, null()].as_slice()))
689 .await
690 }
691
692 async fn import_address_script(
693 &self,
694 script: &Script,
695 label: Option<&str>,
696 rescan: Option<bool>,
697 p2sh: Option<bool>,
698 ) -> Result<()> {
699 let mut args = [
700 script.to_hex_string().into(),
701 opt_into_json(label)?,
702 opt_into_json(rescan)?,
703 opt_into_json(p2sh)?,
704 ];
705 self.call(
706 "importaddress",
707 handle_defaults(&mut args, [into_json("")?, true.into(), null()].as_slice()),
708 )
709 .await
710 }
711
712 async fn import_multi(
713 &self,
714 requests: &[bitcoin_json::ImportMultiRequest],
715 options: Option<&bitcoin_json::ImportMultiOptions>,
716 ) -> Result<Vec<bitcoin_json::ImportMultiResult>> {
717 let mut json_requests = Vec::with_capacity(requests.len());
718 for req in requests {
719 json_requests.push(serde_json::to_value(req)?);
720 }
721 let mut args = [json_requests.into(), opt_into_json(options)?];
722 self.call("importmulti", handle_defaults(&mut args, [null()].as_slice())).await
723 }
724
725 async fn import_descriptors(
726 &self,
727 req: bitcoin_json::ImportDescriptors,
728 ) -> Result<Vec<bitcoin_json::ImportMultiResult>> {
729 let json_request = vec![serde_json::to_value(req)?];
730 self.call(
731 "importdescriptors",
732 handle_defaults(&mut [json_request.into()], [null()].as_slice()),
733 )
734 .await
735 }
736
737 async fn set_label(&self, address: &Address, label: &str) -> Result<()> {
738 self.call("setlabel", [address.to_string().into(), label.into()].as_slice()).await
739 }
740
741 async fn key_pool_refill(&self, new_size: Option<usize>) -> Result<()> {
742 let mut args = [opt_into_json(new_size)?];
743 self.call("keypoolrefill", handle_defaults(&mut args, [null()].as_slice())).await
744 }
745
746 async fn list_unspent(
747 &self,
748 minconf: Option<usize>,
749 maxconf: Option<usize>,
750 addresses: Option<&[&Address<NetworkChecked>]>,
751 include_unsafe: Option<bool>,
752 query_options: Option<bitcoin_json::ListUnspentQueryOptions>,
753 ) -> Result<Vec<bitcoin_json::ListUnspentResultEntry>> {
754 let mut args = [
755 opt_into_json(minconf)?,
756 opt_into_json(maxconf)?,
757 opt_into_json(addresses)?,
758 opt_into_json(include_unsafe)?,
759 opt_into_json(query_options)?,
760 ];
761 let defaults = [into_json(0)?, into_json(9999999)?, empty_arr(), into_json(true)?, null()];
762 self.call("listunspent", handle_defaults(&mut args, defaults.as_slice())).await
763 }
764
765 async fn lock_unspent(&self, outputs: &[OutPoint]) -> Result<bool> {
767 let outputs: Vec<_> =
768 outputs.iter().map(|o| serde_json::to_value(JsonOutPoint::from(*o)).unwrap()).collect();
769 self.call("lockunspent", [false.into(), outputs.into()].as_slice()).await
770 }
771
772 async fn unlock_unspent(&self, outputs: &[OutPoint]) -> Result<bool> {
773 let outputs: Vec<_> =
774 outputs.iter().map(|o| serde_json::to_value(JsonOutPoint::from(*o)).unwrap()).collect();
775 self.call("lockunspent", [true.into(), outputs.into()].as_slice()).await
776 }
777
778 async fn unlock_unspent_all(&self) -> Result<bool> {
780 self.call("lockunspent", [true.into()].as_slice()).await
781 }
782
783 async fn list_received_by_address(
784 &self,
785 address_filter: Option<&Address>,
786 minconf: Option<u32>,
787 include_empty: Option<bool>,
788 include_watchonly: Option<bool>,
789 ) -> Result<Vec<bitcoin_json::ListReceivedByAddressResult>> {
790 let mut args = [
791 opt_into_json(minconf)?,
792 opt_into_json(include_empty)?,
793 opt_into_json(include_watchonly)?,
794 opt_into_json(address_filter)?,
795 ];
796 let defaults = [1.into(), false.into(), false.into(), null()];
797 self.call("listreceivedbyaddress", handle_defaults(&mut args, defaults.as_slice())).await
798 }
799
800 async fn create_psbt(
801 &self,
802 inputs: &[bitcoin_json::CreateRawTransactionInput],
803 outputs: &HashMap<String, Amount>,
804 locktime: Option<i64>,
805 replaceable: Option<bool>,
806 ) -> Result<String> {
807 let outs_converted = serde_json::Map::from_iter(
808 outputs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
809 );
810 self.call(
811 "createpsbt",
812 [
813 into_json(inputs)?,
814 into_json(outs_converted)?,
815 into_json(locktime)?,
816 into_json(replaceable)?,
817 ]
818 .as_slice(),
819 )
820 .await
821 }
822
823 async fn create_raw_transaction_hex(
824 &self,
825 utxos: &[bitcoin_json::CreateRawTransactionInput],
826 outs: &HashMap<String, Amount>,
827 locktime: Option<i64>,
828 replaceable: Option<bool>,
829 ) -> Result<String> {
830 let outs_converted = serde_json::Map::from_iter(
831 outs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
832 );
833 let mut args = [
834 into_json(utxos)?,
835 into_json(outs_converted)?,
836 opt_into_json(locktime)?,
837 opt_into_json(replaceable)?,
838 ];
839 let defaults = [into_json(0i64)?, null()];
840 self.call("createrawtransaction", handle_defaults(&mut args, defaults.as_slice())).await
841 }
842
843 async fn create_raw_transaction(
844 &self,
845 utxos: &[bitcoin_json::CreateRawTransactionInput],
846 outs: &HashMap<String, Amount>,
847 locktime: Option<i64>,
848 replaceable: Option<bool>,
849 ) -> Result<Transaction> {
850 let hex: String =
851 self.create_raw_transaction_hex(utxos, outs, locktime, replaceable).await?;
852 Ok(encode::deserialize_hex(&hex)?)
853 }
854
855 async fn decode_raw_transaction<R: RawTx + Send>(
856 &self,
857 tx: R,
858 is_witness: Option<bool>,
859 ) -> Result<bitcoin_json::DecodeRawTransactionResult> {
860 let mut args = [tx.raw_hex().into(), opt_into_json(is_witness)?];
861 let defaults = [null()];
862 self.call("decoderawtransaction", handle_defaults(&mut args, defaults.as_slice())).await
863 }
864
865 async fn fund_raw_transaction<R: RawTx + Send>(
866 &self,
867 tx: R,
868 options: Option<&bitcoin_json::FundRawTransactionOptions>,
869 is_witness: Option<bool>,
870 ) -> Result<bitcoin_json::FundRawTransactionResult> {
871 let mut args = [tx.raw_hex().into(), opt_into_json(options)?, opt_into_json(is_witness)?];
872 let defaults = [empty_obj(), null()];
873 self.call("fundrawtransaction", handle_defaults(&mut args, defaults.as_slice())).await
874 }
875
876 #[deprecated]
877 async fn sign_raw_transaction<R: RawTx + Send>(
878 &self,
879 tx: R,
880 utxos: Option<&[bitcoin_json::SignRawTransactionInput]>,
881 private_keys: Option<&[PrivateKey]>,
882 sighash_type: Option<bitcoin_json::SigHashType>,
883 ) -> Result<bitcoin_json::SignRawTransactionResult> {
884 let mut args = [
885 tx.raw_hex().into(),
886 opt_into_json(utxos)?,
887 opt_into_json(private_keys)?,
888 opt_into_json(sighash_type)?,
889 ];
890 let defaults = [empty_arr(), empty_arr(), null()];
891 self.call("signrawtransaction", handle_defaults(&mut args, defaults.as_slice())).await
892 }
893
894 async fn sign_raw_transaction_with_wallet<R: RawTx + Send>(
895 &self,
896 tx: R,
897 utxos: Option<&[bitcoin_json::SignRawTransactionInput]>,
898 sighash_type: Option<bitcoin_json::SigHashType>,
899 ) -> Result<bitcoin_json::SignRawTransactionResult> {
900 let mut args = [tx.raw_hex().into(), opt_into_json(utxos)?, opt_into_json(sighash_type)?];
901 let defaults = [empty_arr(), null()];
902 self.call("signrawtransactionwithwallet", handle_defaults(&mut args, defaults.as_slice()))
903 .await
904 }
905
906 async fn sign_raw_transaction_with_key<R: RawTx + Send>(
907 &self,
908 tx: R,
909 privkeys: &[PrivateKey],
910 prevtxs: Option<&[bitcoin_json::SignRawTransactionInput]>,
911 sighash_type: Option<bitcoin_json::SigHashType>,
912 ) -> Result<bitcoin_json::SignRawTransactionResult> {
913 let mut args = [
914 tx.raw_hex().into(),
915 into_json(privkeys)?,
916 opt_into_json(prevtxs)?,
917 opt_into_json(sighash_type)?,
918 ];
919 let defaults = [empty_arr(), null()];
920 self.call("signrawtransactionwithkey", handle_defaults(&mut args, defaults.as_slice()))
921 .await
922 }
923
924 async fn test_mempool_accept<R: RawTx + Sync>(
925 &self,
926 rawtxs: &[R],
927 ) -> Result<Vec<bitcoin_json::TestMempoolAcceptResult>> {
928 let hexes: Vec<serde_json::Value> =
929 rawtxs.iter().cloned().map(|r| r.raw_hex().into()).collect();
930 self.call("testmempoolaccept", [hexes.into()].as_slice()).await
931 }
932
933 async fn stop(&self) -> Result<String> {
934 self.call("stop", NOPARAMS).await
935 }
936
937 async fn verify_message(
938 &self,
939 address: &Address,
940 signature: &Signature,
941 message: &str,
942 ) -> Result<bool> {
943 let args = [address.to_string().into(), signature.to_string().into(), into_json(message)?];
944 self.call("verifymessage", args.as_slice()).await
945 }
946
947 async fn get_new_address(
949 &self,
950 label: Option<&str>,
951 address_type: Option<bitcoin_json::AddressType>,
952 ) -> Result<Address<NetworkUnchecked>> {
953 self.call("getnewaddress", [opt_into_json(label)?, opt_into_json(address_type)?].as_slice())
954 .await
955 }
956
957 async fn get_raw_change_address(
959 &self,
960 address_type: Option<bitcoin_json::AddressType>,
961 ) -> Result<Address<NetworkUnchecked>> {
962 self.call("getrawchangeaddress", [opt_into_json(address_type)?].as_slice()).await
963 }
964
965 async fn get_address_info(
966 &self,
967 address: &Address,
968 ) -> Result<bitcoin_json::GetAddressInfoResult> {
969 self.call("getaddressinfo", [address.to_string().into()].as_slice()).await
970 }
971
972 async fn generate_to_address(
976 &self,
977 block_num: u64,
978 address: &Address<NetworkChecked>,
979 ) -> Result<Vec<bitcoin::BlockHash>> {
980 self.call("generatetoaddress", [block_num.into(), address.to_string().into()].as_slice())
981 .await
982 }
983
984 async fn generate(
987 &self,
988 block_num: u64,
989 maxtries: Option<u64>,
990 ) -> Result<Vec<bitcoin::BlockHash>> {
991 self.call("generate", [block_num.into(), opt_into_json(maxtries)?].as_slice()).await
992 }
993
994 async fn invalidate_block(&self, block_hash: &bitcoin::BlockHash) -> Result<()> {
996 self.call("invalidateblock", [into_json(block_hash)?].as_slice()).await
997 }
998
999 async fn reconsider_block(&self, block_hash: &bitcoin::BlockHash) -> Result<()> {
1001 self.call("reconsiderblock", [into_json(block_hash)?].as_slice()).await
1002 }
1003
1004 async fn get_mempool_info(&self) -> Result<bitcoin_json::GetMempoolInfoResult> {
1006 self.call("getmempoolinfo", NOPARAMS).await
1007 }
1008
1009 async fn get_raw_mempool(&self) -> Result<Vec<bitcoin::Txid>> {
1011 self.call("getrawmempool", NOPARAMS).await
1012 }
1013
1014 async fn get_raw_mempool_verbose(
1016 &self,
1017 ) -> Result<HashMap<bitcoin::Txid, bitcoin_json::GetMempoolEntryResult>> {
1018 self.call("getrawmempool", [into_json(true)?].as_slice()).await
1019 }
1020
1021 async fn get_mempool_entry(
1023 &self,
1024 txid: &bitcoin::Txid,
1025 ) -> Result<bitcoin_json::GetMempoolEntryResult> {
1026 self.call("getmempoolentry", [into_json(txid)?].as_slice()).await
1027 }
1028
1029 async fn get_chain_tips(&self) -> Result<bitcoin_json::GetChainTipsResult> {
1032 self.call("getchaintips", NOPARAMS).await
1033 }
1034
1035 async fn send_to_address(
1036 &self,
1037 address: &Address<NetworkChecked>,
1038 amount: Amount,
1039 comment: Option<&str>,
1040 comment_to: Option<&str>,
1041 subtract_fee: Option<bool>,
1042 replaceable: Option<bool>,
1043 confirmation_target: Option<u32>,
1044 estimate_mode: Option<bitcoin_json::EstimateMode>,
1045 ) -> Result<bitcoin::Txid> {
1046 let mut args = [
1047 address.to_string().into(),
1048 into_json(amount.to_btc())?,
1049 opt_into_json(comment)?,
1050 opt_into_json(comment_to)?,
1051 opt_into_json(subtract_fee)?,
1052 opt_into_json(replaceable)?,
1053 opt_into_json(confirmation_target)?,
1054 opt_into_json(estimate_mode)?,
1055 ];
1056 self.call(
1057 "sendtoaddress",
1058 handle_defaults(
1059 &mut args,
1060 ["".into(), "".into(), false.into(), false.into(), 6.into(), null()].as_slice(),
1061 ),
1062 )
1063 .await
1064 }
1065
1066 async fn add_node(&self, addr: &str) -> Result<()> {
1069 self.call("addnode", [into_json(addr)?, into_json("add")?].as_slice()).await
1070 }
1071
1072 async fn remove_node(&self, addr: &str) -> Result<()> {
1074 self.call("addnode", [into_json(addr)?, into_json("remove")?].as_slice()).await
1075 }
1076
1077 async fn onetry_node(&self, addr: &str) -> Result<()> {
1079 self.call("addnode", [into_json(addr)?, into_json("onetry")?].as_slice()).await
1080 }
1081
1082 async fn disconnect_node(&self, addr: &str) -> Result<()> {
1084 self.call("disconnectnode", [into_json(addr)?].as_slice()).await
1085 }
1086
1087 async fn disconnect_node_by_id(&self, node_id: u32) -> Result<()> {
1088 self.call("disconnectnode", [into_json("")?, into_json(node_id)?].as_slice()).await
1089 }
1090
1091 async fn get_added_node_info(
1093 &self,
1094 node: Option<&str>,
1095 ) -> Result<Vec<bitcoin_json::GetAddedNodeInfoResult>> {
1096 if let Some(addr) = node {
1097 self.call("getaddednodeinfo", [into_json(addr)?].as_slice()).await
1098 } else {
1099 self.call("getaddednodeinfo", NOPARAMS).await
1100 }
1101 }
1102
1103 async fn get_node_addresses(
1105 &self,
1106 count: Option<usize>,
1107 ) -> Result<Vec<bitcoin_json::GetNodeAddressesResult>> {
1108 let cnt = count.unwrap_or(1);
1109 self.call("getnodeaddresses", [into_json(cnt)?].as_slice()).await
1110 }
1111
1112 async fn list_banned(&self) -> Result<Vec<bitcoin_json::ListBannedResult>> {
1114 self.call("listbanned", NOPARAMS).await
1115 }
1116
1117 async fn clear_banned(&self) -> Result<()> {
1119 self.call("clearbanned", NOPARAMS).await
1120 }
1121
1122 async fn add_ban(&self, subnet: &str, bantime: u64, absolute: bool) -> Result<()> {
1124 self.call(
1125 "setban",
1126 [into_json(subnet)?, into_json("add")?, into_json(bantime)?, into_json(absolute)?]
1127 .as_slice(),
1128 )
1129 .await
1130 }
1131
1132 async fn remove_ban(&self, subnet: &str) -> Result<()> {
1134 self.call("setban", [into_json(subnet)?, into_json("remove")?].as_slice()).await
1135 }
1136
1137 async fn set_network_active(&self, state: bool) -> Result<bool> {
1139 self.call("setnetworkactive", [into_json(state)?].as_slice()).await
1140 }
1141
1142 async fn get_peer_info(&self) -> Result<Vec<bitcoin_json::GetPeerInfoResult>> {
1147 self.call("getpeerinfo", NOPARAMS).await
1148 }
1149
1150 async fn ping(&self) -> Result<()> {
1159 self.call("ping", NOPARAMS).await
1160 }
1161
1162 async fn send_raw_transaction<R: RawTx + Send>(&self, tx: R) -> Result<bitcoin::Txid> {
1163 self.call("sendrawtransaction", [tx.raw_hex().into()].as_slice()).await
1164 }
1165
1166 async fn estimate_smart_fee(
1167 &self,
1168 conf_target: u16,
1169 estimate_mode: Option<bitcoin_json::EstimateMode>,
1170 ) -> Result<bitcoin_json::EstimateSmartFeeResult> {
1171 let mut args = [into_json(conf_target)?, opt_into_json(estimate_mode)?];
1172 self.call("estimatesmartfee", handle_defaults(&mut args, [null()].as_slice())).await
1173 }
1174
1175 async fn wait_for_new_block(&self, timeout: u64) -> Result<bitcoin_json::BlockRef> {
1183 self.call("waitfornewblock", [into_json(timeout)?].as_slice()).await
1184 }
1185
1186 async fn wait_for_block(
1195 &self,
1196 blockhash: &bitcoin::BlockHash,
1197 timeout: u64,
1198 ) -> Result<bitcoin_json::BlockRef> {
1199 let args = [into_json(blockhash)?, into_json(timeout)?];
1200 self.call("waitforblock", args.as_slice()).await
1201 }
1202
1203 async fn wallet_create_funded_psbt(
1204 &self,
1205 inputs: &[bitcoin_json::CreateRawTransactionInput],
1206 outputs: &HashMap<String, Amount>,
1207 locktime: Option<i64>,
1208 options: Option<bitcoin_json::WalletCreateFundedPsbtOptions>,
1209 bip32derivs: Option<bool>,
1210 ) -> Result<bitcoin_json::WalletCreateFundedPsbtResult> {
1211 let outputs_converted = serde_json::Map::from_iter(
1212 outputs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
1213 );
1214 let mut args = [
1215 into_json(inputs)?,
1216 into_json(outputs_converted)?,
1217 opt_into_json(locktime)?,
1218 opt_into_json(options)?,
1219 opt_into_json(bip32derivs)?,
1220 ];
1221 self.call(
1222 "walletcreatefundedpsbt",
1223 handle_defaults(
1224 &mut args,
1225 [0.into(), serde_json::Map::new().into(), false.into()].as_slice(),
1226 ),
1227 )
1228 .await
1229 }
1230
1231 async fn wallet_process_psbt(
1232 &self,
1233 psbt: &str,
1234 sign: Option<bool>,
1235 sighash_type: Option<bitcoin_json::SigHashType>,
1236 bip32derivs: Option<bool>,
1237 ) -> Result<bitcoin_json::WalletProcessPsbtResult> {
1238 let mut args = [
1239 into_json(psbt)?,
1240 opt_into_json(sign)?,
1241 opt_into_json(sighash_type)?,
1242 opt_into_json(bip32derivs)?,
1243 ];
1244 let defaults = [
1245 true.into(),
1246 into_json(bitcoin_json::SigHashType::from(
1247 bitcoin::sighash::EcdsaSighashType::All,
1248 ))?,
1249 true.into(),
1250 ];
1251 self.call("walletprocesspsbt", handle_defaults(&mut args, defaults.as_slice())).await
1252 }
1253
1254 async fn get_descriptor_info(
1255 &self,
1256 desc: &str,
1257 ) -> Result<bitcoin_json::GetDescriptorInfoResult> {
1258 self.call("getdescriptorinfo", [desc.to_string().into()].as_slice()).await
1259 }
1260
1261 async fn join_psbt(&self, psbts: &[String]) -> Result<String> {
1262 self.call("joinpsbts", [into_json(psbts)?].as_slice()).await
1263 }
1264
1265 async fn combine_psbt(&self, psbts: &[String]) -> Result<String> {
1266 self.call("combinepsbt", [into_json(psbts)?].as_slice()).await
1267 }
1268
1269 async fn combine_raw_transaction(&self, hex_strings: &[String]) -> Result<String> {
1270 self.call("combinerawtransaction", [into_json(hex_strings)?].as_slice()).await
1271 }
1272
1273 async fn finalize_psbt(
1274 &self,
1275 psbt: &str,
1276 extract: Option<bool>,
1277 ) -> Result<bitcoin_json::FinalizePsbtResult> {
1278 let mut args = [into_json(psbt)?, opt_into_json(extract)?];
1279 self.call("finalizepsbt", handle_defaults(&mut args, [true.into()].as_slice())).await
1280 }
1281
1282 async fn derive_addresses(
1283 &self,
1284 descriptor: &str,
1285 range: Option<[u32; 2]>,
1286 ) -> Result<Vec<Address<NetworkUnchecked>>> {
1287 let mut args = [into_json(descriptor)?, opt_into_json(range)?];
1288 self.call("deriveaddresses", handle_defaults(&mut args, [null()].as_slice())).await
1289 }
1290
1291 async fn rescan_blockchain(
1292 &self,
1293 start_from: Option<usize>,
1294 stop_height: Option<usize>,
1295 ) -> Result<(usize, Option<usize>)> {
1296 let mut args = [opt_into_json(start_from)?, opt_into_json(stop_height)?];
1297
1298 #[derive(Deserialize)]
1299 struct Response {
1300 pub start_height: usize,
1301 pub stop_height: Option<usize>,
1302 }
1303 let res: Response = self
1304 .call("rescanblockchain", handle_defaults(&mut args, [0.into(), null()].as_slice()))
1305 .await?;
1306 Ok((res.start_height, res.stop_height))
1307 }
1308
1309 async fn get_tx_out_set_info(
1312 &self,
1313 hash_type: Option<bitcoin_json::TxOutSetHashType>,
1314 hash_or_height: Option<bitcoin_json::HashOrHeight>,
1315 use_index: Option<bool>,
1316 ) -> Result<bitcoin_json::GetTxOutSetInfoResult> {
1317 let mut args =
1318 [opt_into_json(hash_type)?, opt_into_json(hash_or_height)?, opt_into_json(use_index)?];
1319 self.call(
1320 "gettxoutsetinfo",
1321 handle_defaults(&mut args, [null(), null(), null()].as_slice()),
1322 )
1323 .await
1324 }
1325
1326 async fn get_net_totals(&self) -> Result<bitcoin_json::GetNetTotalsResult> {
1329 self.call("getnettotals", NOPARAMS).await
1330 }
1331
1332 async fn get_network_hash_ps(&self, nblocks: Option<u64>, height: Option<u64>) -> Result<f64> {
1334 let mut args = [opt_into_json(nblocks)?, opt_into_json(height)?];
1335 self.call("getnetworkhashps", handle_defaults(&mut args, [null(), null()].as_slice())).await
1336 }
1337
1338 async fn uptime(&self) -> Result<u64> {
1340 self.call("uptime", NOPARAMS).await
1341 }
1342
1343 async fn submit_block(&self, block: &bitcoin::Block) -> Result<()> {
1345 let block_hex: String = bitcoin::consensus::encode::serialize_hex(block);
1346 self.submit_block_hex(&block_hex).await
1347 }
1348
1349 async fn submit_block_bytes(&self, block_bytes: &[u8]) -> Result<()> {
1351 let block_hex: String = block_bytes.to_lower_hex_string();
1352 self.submit_block_hex(&block_hex).await
1353 }
1354
1355 async fn submit_block_hex(&self, block_hex: &str) -> Result<()> {
1357 match self.call("submitblock", [into_json(block_hex)?].as_slice()).await {
1358 Ok(serde_json::Value::Null) => Ok(()),
1359 Ok(res) => Err(Error::ReturnedError(res.to_string())),
1360 Err(err) => Err(err),
1361 }
1362 }
1363
1364 async fn scan_tx_out_set_blocking(
1365 &self,
1366 descriptors: &[bitcoin_json::ScanTxOutRequest],
1367 ) -> Result<bitcoin_json::ScanTxOutResult> {
1368 self.call("scantxoutset", ["start".into(), into_json(descriptors)?].as_slice()).await
1369 }
1370
1371 async fn get_zmq_notifications(
1373 &self,
1374 ) -> Result<Vec<bitcoin_json::GetZmqNotificationsResult>> {
1375 self.call("getzmqnotifications", NOPARAMS).await
1376 }
1377}
1378
1379#[derive(Clone)]
1381pub struct Client {
1382 client: jsonrpsee::http_client::HttpClient,
1383}
1384
1385impl fmt::Debug for Client {
1386 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1387 write!(f, "bitcoincore_rpc::Client(HttpClient)")
1388 }
1389}
1390
1391impl Client {
1392 pub fn new(url: &str, auth: Option<Auth>) -> Result<Self> {
1394 let mut builder = jsonrpsee::http_client::HttpClientBuilder::default();
1395
1396 if let Some(auth) = auth {
1397 let mut headers = HeaderMap::new();
1398 auth.auth(&mut headers)?;
1399 builder = builder.set_headers(headers);
1400 }
1401
1402 let client = builder.build(url)?;
1403 Ok(Client {
1404 client,
1405 })
1406 }
1407}
1408
1409#[async_trait::async_trait]
1410impl RpcApi for Client {
1411 async fn call<T: for<'de> serde::de::Deserialize<'de>>(
1412 &self,
1413 method: &str,
1414 params: &[serde_json::Value],
1415 ) -> Result<T> {
1416 let mut params_arr = ArrayParams::new();
1417 for p in params {
1418 params_arr.insert(p)?;
1419 }
1420 let response = self.client.request(method, params_arr).await?;
1421 Ok(response)
1422 }
1423}
1424
1425#[cfg(test)]
1450mod tests {
1451 }