groestlcoincore_rpc/
client.rs

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