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