bitcoinsv_rpc_json/
lib.rs

1//! # Rust Client for Bitcoin SV API
2//!
3//! This is a client library for the Bitcoin SV JSON-RPC API.
4//!
5//! This library is not expected to be used directly, it is a sub-component of the bitcoinsv-rpc crate.
6//! You probably want the bitcoinsv-rpc crate.
7
8#![crate_name = "bitcoinsv_rpc_json"]
9#![crate_type = "rlib"]
10
11extern crate alloc;
12extern crate serde;
13extern crate serde_json;
14use bitcoinsv::bitcoin::{BlockHash, BlockchainId, MerkleRoot, Tx, TxHash};
15use bitcoinsv::util::Amount;
16use hex::FromHex;
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19use std::fmt;
20
21/// A module used for serde serialization of bytes in hexadecimal format.
22///
23/// The module is compatible with the serde attribute.
24pub mod serde_hex {
25    use hex::FromHex;
26    use serde::de::Error;
27    use serde::{Deserializer, Serializer};
28
29    pub fn serialize<S: Serializer>(b: &Vec<u8>, s: S) -> Result<S::Ok, S::Error> {
30        s.serialize_str(&hex::encode(b))
31    }
32
33    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<u8>, D::Error> {
34        let hex_str: String = ::serde::Deserialize::deserialize(d)?;
35        FromHex::from_hex(&hex_str).map_err(D::Error::custom)
36    }
37
38    pub mod opt {
39        use hex::FromHex;
40        use serde::de::Error;
41        use serde::{Deserializer, Serializer};
42
43        pub fn serialize<S: Serializer>(b: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error> {
44            match *b {
45                None => s.serialize_none(),
46                Some(ref b) => s.serialize_str(&hex::encode(b)),
47            }
48        }
49
50        pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Vec<u8>>, D::Error> {
51            let hex_str: String = ::serde::Deserialize::deserialize(d)?;
52            Ok(Some(FromHex::from_hex(&hex_str).map_err(D::Error::custom)?))
53        }
54    }
55}
56
57#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
58pub struct GetNetworkInfoResultNetwork {
59    pub name: String,
60    pub limited: bool,
61    pub reachable: bool,
62    pub proxy: String,
63    pub proxy_randomize_credentials: bool,
64}
65
66#[cfg(test)]
67mod ninfo_network_tests {
68    use super::*;
69    
70
71    #[test]
72    fn test_deserialize_get_network_info_result_network() {
73        let json_data = r#"
74            {
75              "name": "ipv4",
76              "limited": false,
77              "reachable": true,
78              "proxy": "",
79              "proxy_randomize_credentials": false
80            }
81        "#;
82
83        let result: GetNetworkInfoResultNetwork = serde_json::from_str(json_data).unwrap();
84
85        assert_eq!(result.name, "ipv4");
86        assert!(!result.limited);
87        assert!(result.reachable);
88        assert_eq!(result.proxy, "");
89        assert!(!result.proxy_randomize_credentials);
90    }
91}
92
93#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
94pub struct GetNetworkInfoResultAddress {
95    pub address: String,
96    pub port: u64,
97    pub score: u64,
98}
99
100#[cfg(test)]
101mod ninfo_address_tests {
102    use super::*;
103    
104
105    #[test]
106    fn test_deserialize_get_network_info_result_address() {
107        let json_data = r#"
108            {
109              "address": "192.168.32.145",
110              "port": 8333,
111              "score": 13436
112            }
113        "#;
114
115        let result: GetNetworkInfoResultAddress = serde_json::from_str(json_data).unwrap();
116
117        assert_eq!(result.address, "192.168.32.145");
118        assert_eq!(result.port, 8333);
119        assert_eq!(result.score, 13436);
120    }
121}
122
123#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
124pub struct GetNetworkInfoResult {
125    pub version: u32,
126    pub subversion: String,
127    #[serde(rename = "protocolversion")]
128    pub protocol_version: usize,
129    #[serde(rename = "localservices")]
130    pub local_services: String,
131    #[serde(rename = "localrelay")]
132    pub local_relay: bool,
133    #[serde(rename = "timeoffset")]
134    pub time_offset: isize,
135    #[serde(rename = "txnpropagationfreq")]
136    pub txn_propagation_freq: i64,
137    #[serde(rename = "txnpropagationqlen")]
138    pub txn_propagation_qlen: u64,
139    #[serde(rename = "networkactive")]
140    pub network_active: bool,
141    pub connections: usize,
142    #[serde(rename = "addresscount")]
143    pub address_count: u64,
144    #[serde(rename = "streampolicies")]
145    pub stream_policies: String,
146    pub networks: Vec<GetNetworkInfoResultNetwork>,
147    #[serde(rename = "relayfee")]
148    pub relay_fee: f64,
149    #[serde(rename = "minconsolidationfactor")]
150    pub min_consolidation_factor: u64,
151    #[serde(rename = "maxconsolidationinputscriptsize")]
152    pub max_consolidation_input_script_size: u64,
153    #[serde(rename = "minconfconsolidationinput")]
154    pub min_conf_consolidation_input: u64,
155    #[serde(rename = "minconsolidationinputmaturity")]
156    pub min_consolidation_input_maturity: u64,
157    #[serde(rename = "acceptnonstdconsolidationinput")]
158    pub accept_non_std_consolidation_input: bool,
159    #[serde(rename = "localaddresses")]
160    pub local_addresses: Vec<GetNetworkInfoResultAddress>,
161    pub warnings: String,
162}
163
164#[cfg(test)]
165mod ninfo_tests {
166    use super::*;
167    
168
169    #[test]
170    fn test_deserialize_get_network_info_result() {
171        let json_data = r#"
172            {
173              "version": 101001600,
174              "subversion": "/Bitcoin SV:1.0.16/",
175              "protocolversion": 70016,
176              "localservices": "0000000000000021",
177              "localrelay": true,
178              "timeoffset": 0,
179              "txnpropagationfreq": 250,
180              "txnpropagationqlen": 0,
181              "networkactive": true,
182              "connections": 129,
183              "addresscount": 38071,
184              "streampolicies": "BlockPriority,Default",
185              "networks": [
186                {
187                  "name": "ipv4",
188                  "limited": false,
189                  "reachable": true,
190                  "proxy": "",
191                  "proxy_randomize_credentials": false
192                },
193                {
194                  "name": "ipv6",
195                  "limited": false,
196                  "reachable": true,
197                  "proxy": "",
198                  "proxy_randomize_credentials": false
199                }
200              ],
201              "relayfee": 0.00000000,
202              "minconsolidationfactor": 20,
203              "maxconsolidationinputscriptsize": 150,
204              "minconfconsolidationinput": 6,
205              "minconsolidationinputmaturity": 6,
206              "acceptnonstdconsolidationinput": false,
207              "localaddresses": [
208                {
209                  "address": "192.168.78.4",
210                  "port": 8333,
211                  "score": 16651
212                }
213              ],
214              "warnings": ""
215            }
216        "#;
217        let result: GetNetworkInfoResult = serde_json::from_str(json_data).unwrap();
218
219        assert_eq!(result.version, 101001600);
220    }
221}
222
223#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
224pub struct GetBlockResultStatus {
225    pub validity: String,
226    pub data: bool,
227    pub undo: bool,
228    pub failed: bool,
229    #[serde(rename = "parent failed")]
230    pub parent_failed: bool,
231    #[serde(rename = "disk meta")]
232    pub disk_meta: bool,
233    #[serde(rename = "soft reject")]
234    pub soft_reject: bool,
235    #[serde(rename = "double spend")]
236    pub double_spend: bool,
237    #[serde(rename = "soft consensus frozen")]
238    pub soft_consensus_frozen: bool,
239}
240
241#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
242pub struct GetBlockResult {
243    pub tx: Vec<TxHash>,
244    pub hash: BlockHash,
245    pub confirmations: i32,
246    pub size: usize,
247    pub height: usize,
248    pub version: i32,
249    #[serde(default, rename = "versionHex", with = "crate::serde_hex")]
250    pub version_hex: Vec<u8>,
251    pub merkleroot: MerkleRoot,
252    pub num_tx: u64,
253    pub time: u64,
254    pub mediantime: Option<u64>,
255    pub nonce: u32,
256    pub bits: String,
257    pub difficulty: f64,
258    #[serde(with = "crate::serde_hex")]
259    #[serde(rename = "chainwork")]
260    pub chain_work: Vec<u8>,
261    #[serde(rename = "previousblockhash")]
262    pub previous_block_hash: Option<BlockHash>,
263    // todo: isnt this a problem? couldn't there be multiple next blocks in the case of a fork?
264    #[serde(rename = "nextblockhash")]
265    pub next_block_hash: Option<BlockHash>,
266    pub status: GetBlockResultStatus,
267}
268
269#[cfg(test)]
270mod getblock_tests {
271    use super::*;
272    use approx::assert_relative_eq;
273
274    #[test]
275    fn test_deserialize_get_block_result() {
276        let json_data = r#"
277            {
278              "tx": [
279                "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
280              ],
281              "hash": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
282              "confirmations": 1,
283              "size": 285,
284              "height": 0,
285              "version": 1,
286              "versionHex": "00000001",
287              "merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
288              "num_tx": 1,
289              "time": 1296688602,
290              "mediantime": 1296688602,
291              "nonce": 2,
292              "bits": "207fffff",
293              "difficulty": 4.656542373906925e-10,
294              "chainwork": "0000000000000000000000000000000000000000000000000000000000000002",
295              "status": {
296                "validity": "transactions",
297                "data": true,
298                "undo": false,
299                "failed": false,
300                "parent failed": false,
301                "disk meta": true,
302                "soft reject": false,
303                "double spend": false,
304                "soft consensus frozen": false
305              }
306            }
307        "#;
308
309        let result: GetBlockResult = serde_json::from_str(json_data).unwrap();
310
311        assert_eq!(result.confirmations, 1);
312        assert_relative_eq!(result.difficulty, 4.656542373906925e-10, epsilon = 1e-8);
313    }
314}
315
316#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
317pub struct GetBlockHeaderResult {
318    pub hash: BlockHash,
319    pub confirmations: i32,
320    pub size: u64,
321    pub height: u64,
322    pub version: u32,
323    #[serde(default, rename = "versionHex", with = "crate::serde_hex::opt")]
324    pub version_hex: Option<Vec<u8>>,
325    #[serde(rename = "merkleroot")]
326    pub merkle_root: MerkleRoot,
327    pub num_tx: usize,
328    pub time: u64,
329    #[serde(rename = "mediantime")]
330    pub median_time: Option<u64>,
331    pub nonce: u32,
332    pub bits: String,
333    pub difficulty: f64,
334    #[serde(with = "crate::serde_hex")]
335    pub chainwork: Vec<u8>,
336    #[serde(rename = "previousblockhash")]
337    pub previous_block_hash: Option<BlockHash>,
338    // todo: is this a problem? won't it return multiple hashe's if there is a fork?
339    #[serde(rename = "nextblockhash")]
340    pub next_block_hash: Option<BlockHash>,
341    pub status: GetBlockResultStatus,
342    #[serde(rename = "tx")]
343    pub coinbase_tx: Option<Vec<GetRawTransactionResult>>, // its a vector but it only has one value
344    #[serde(rename = "merkleproof")]
345    pub coinbase_merkle_proof: Option<Vec<MerkleRoot>>,
346}
347
348#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
349pub struct GetBlockStatsResult {
350    #[serde(rename = "avgfee")]
351    pub avg_fee: Amount,
352    #[serde(rename = "avgfeerate")]
353    pub avg_fee_rate: Amount,
354    #[serde(rename = "avgtxsize")]
355    pub avg_tx_size: u32,
356    #[serde(rename = "blockhash")]
357    pub block_hash: BlockHash,
358    pub height: u64,
359    pub ins: u64,
360    #[serde(rename = "maxfee")]
361    pub max_fee: Amount,
362    #[serde(rename = "maxfeerate")]
363    pub max_fee_rate: Amount,
364    #[serde(rename = "maxtxsize")]
365    pub max_tx_size: u32,
366    #[serde(rename = "medianfee")]
367    pub median_fee: Amount,
368    #[serde(rename = "mediantime")]
369    pub median_time: u64,
370    #[serde(rename = "mediantxsize")]
371    pub median_tx_size: u32,
372    #[serde(rename = "minfee")]
373    pub min_fee: Amount,
374    #[serde(rename = "minfeerate")]
375    pub min_fee_rate: Amount,
376    #[serde(rename = "mintxsize")]
377    pub min_tx_size: u32,
378    pub outs: usize,
379    pub subsidy: Amount,
380    pub time: u64,
381    pub total_out: Amount,
382    pub total_size: usize,
383    #[serde(rename = "totalfee")]
384    pub total_fee: Amount,
385    pub txs: usize,
386    pub utxo_increase: i32,
387    pub utxo_size_inc: i32,
388}
389
390#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
391pub struct GetBlockStatsResultPartial {
392    #[serde(default, rename = "avgfee", skip_serializing_if = "Option::is_none")]
393    pub avg_fee: Option<Amount>,
394    #[serde(default, rename = "avgfeerate", skip_serializing_if = "Option::is_none")]
395    pub avg_fee_rate: Option<Amount>,
396    #[serde(default, rename = "avgtxsize", skip_serializing_if = "Option::is_none")]
397    pub avg_tx_size: Option<u32>,
398    #[serde(default, rename = "blockhash", skip_serializing_if = "Option::is_none")]
399    pub block_hash: Option<BlockHash>,
400    #[serde(default, skip_serializing_if = "Option::is_none")]
401    pub height: Option<u64>,
402    #[serde(default, skip_serializing_if = "Option::is_none")]
403    pub ins: Option<usize>,
404    #[serde(default, rename = "maxfee", skip_serializing_if = "Option::is_none")]
405    pub max_fee: Option<Amount>,
406    #[serde(default, rename = "maxfeerate", skip_serializing_if = "Option::is_none")]
407    pub max_fee_rate: Option<Amount>,
408    #[serde(default, rename = "maxtxsize", skip_serializing_if = "Option::is_none")]
409    pub max_tx_size: Option<u32>,
410    #[serde(default, rename = "medianfee", skip_serializing_if = "Option::is_none")]
411    pub median_fee: Option<Amount>,
412    #[serde(default, rename = "mediantime", skip_serializing_if = "Option::is_none")]
413    pub median_time: Option<u64>,
414    #[serde(default, rename = "mediantxsize", skip_serializing_if = "Option::is_none")]
415    pub median_tx_size: Option<u32>,
416    #[serde(default, rename = "minfee", skip_serializing_if = "Option::is_none")]
417    pub min_fee: Option<Amount>,
418    #[serde(default, rename = "minfeerate", skip_serializing_if = "Option::is_none")]
419    pub min_fee_rate: Option<Amount>,
420    #[serde(default, rename = "mintxsize", skip_serializing_if = "Option::is_none")]
421    pub min_tx_size: Option<u32>,
422    #[serde(default, skip_serializing_if = "Option::is_none")]
423    pub outs: Option<usize>,
424    #[serde(default, skip_serializing_if = "Option::is_none")]
425    pub subsidy: Option<Amount>,
426    #[serde(default, skip_serializing_if = "Option::is_none")]
427    pub time: Option<u64>,
428    #[serde(default, skip_serializing_if = "Option::is_none")]
429    pub total_out: Option<Amount>,
430    #[serde(default, skip_serializing_if = "Option::is_none")]
431    pub total_size: Option<usize>,
432    #[serde(default, rename = "totalfee", skip_serializing_if = "Option::is_none")]
433    pub total_fee: Option<Amount>,
434    #[serde(default, skip_serializing_if = "Option::is_none")]
435    pub txs: Option<usize>,
436    #[serde(default, skip_serializing_if = "Option::is_none")]
437    pub utxo_increase: Option<i32>,
438    #[serde(default, skip_serializing_if = "Option::is_none")]
439    pub utxo_size_inc: Option<i32>,
440}
441
442#[derive(Clone)]
443pub enum BlockStatsFields {
444    AverageFee,
445    AverageFeeRate,
446    AverageTxSize,
447    BlockHash,
448    Height,
449    Ins,
450    MaxFee,
451    MaxFeeRate,
452    MaxTxSize,
453    MedianFee,
454    MedianTime,
455    MedianTxSize,
456    MinFee,
457    MinFeeRate,
458    MinTxSize,
459    Outs,
460    Subsidy,
461    Time,
462    TotalOut,
463    TotalSize,
464    TotalFee,
465    Txs,
466    UtxoIncrease,
467    UtxoSizeIncrease,
468}
469
470impl BlockStatsFields {
471    fn get_rpc_keyword(&self) -> &str {
472        match *self {
473            BlockStatsFields::AverageFee => "avgfee",
474            BlockStatsFields::AverageFeeRate => "avgfeerate",
475            BlockStatsFields::AverageTxSize => "avgtxsize",
476            BlockStatsFields::BlockHash => "blockhash",
477            BlockStatsFields::Height => "height",
478            BlockStatsFields::Ins => "ins",
479            BlockStatsFields::MaxFee => "maxfee",
480            BlockStatsFields::MaxFeeRate => "maxfeerate",
481            BlockStatsFields::MaxTxSize => "maxtxsize",
482            BlockStatsFields::MedianFee => "medianfee",
483            BlockStatsFields::MedianTime => "mediantime",
484            BlockStatsFields::MedianTxSize => "mediantxsize",
485            BlockStatsFields::MinFee => "minfee",
486            BlockStatsFields::MinFeeRate => "minfeerate",
487            BlockStatsFields::MinTxSize => "minfeerate",
488            BlockStatsFields::Outs => "outs",
489            BlockStatsFields::Subsidy => "subsidy",
490            BlockStatsFields::Time => "time",
491            BlockStatsFields::TotalOut => "total_out",
492            BlockStatsFields::TotalSize => "total_size",
493            BlockStatsFields::TotalFee => "totalfee",
494            BlockStatsFields::Txs => "txs",
495            BlockStatsFields::UtxoIncrease => "utxo_increase",
496            BlockStatsFields::UtxoSizeIncrease => "utxo_size_inc",
497        }
498    }
499}
500
501impl fmt::Display for BlockStatsFields {
502    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503        write!(f, "{}", self.get_rpc_keyword())
504    }
505}
506
507impl From<BlockStatsFields> for serde_json::Value {
508    fn from(bsf: BlockStatsFields) -> Self {
509        Self::from(bsf.to_string())
510    }
511}
512
513#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
514#[serde(rename_all = "camelCase")]
515pub struct GetMiningInfoResult {
516    pub blocks: u32,
517    #[serde(rename = "currentblocksize")]
518    pub current_block_size: u64,
519    #[serde(rename = "currentblocktx")]
520    pub current_block_tx: u64,
521    pub difficulty: f64,
522    pub errors: String,
523    #[serde(rename = "networkhashps")]
524    pub network_hash_ps: f64,
525    #[serde(rename = "pooledtx")]
526    pub pooled_tx: u64,
527    pub chain: BlockchainId,
528}
529
530#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
531#[serde(rename_all = "camelCase")]
532pub struct GetRawTransactionResultVinScriptSig {
533    pub asm: String,
534    #[serde(with = "crate::serde_hex")]
535    pub hex: Vec<u8>,
536}
537
538#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
539#[serde(rename_all = "camelCase")]
540pub struct GetRawTransactionResultVin {
541    pub sequence: u32,
542    /// The raw scriptSig in case of a coinbase tx.
543    #[serde(default, with = "crate::serde_hex::opt")]
544    pub coinbase: Option<Vec<u8>>,
545    /// Not provided for coinbase txs.
546    pub txid: Option<TxHash>,
547    /// Not provided for coinbase txs.
548    pub vout: Option<u32>,
549    /// The scriptSig in case of a non-coinbase tx.
550    pub script_sig: Option<GetRawTransactionResultVinScriptSig>,
551}
552
553impl GetRawTransactionResultVin {
554    /// Whether this input is from a coinbase tx.
555    /// The [txid], [vout] and [script_sig] fields are not provided
556    /// for coinbase transactions.
557    pub fn is_coinbase(&self) -> bool {
558        self.coinbase.is_some()
559    }
560}
561
562#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
563#[serde(rename_all = "camelCase")]
564pub struct GetRawTransactionResultVoutScriptPubKey {
565    pub asm: String,
566    #[serde(with = "crate::serde_hex")]
567    pub hex: Vec<u8>,
568    #[serde(rename = "type")]
569    pub type_: Option<ScriptPubkeyType>,
570}
571
572#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
573#[serde(rename_all = "camelCase")]
574pub struct GetRawTransactionResultVout {
575    pub value: Amount,
576    pub n: u32,
577    pub script_pub_key: GetRawTransactionResultVoutScriptPubKey,
578}
579
580#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
581#[serde(rename_all = "camelCase")]
582pub struct GetRawTransactionResult {
583    #[serde(with = "crate::serde_hex")]
584    pub hex: Vec<u8>,
585    pub txid: TxHash,
586    pub hash: TxHash,
587    pub version: u32,
588    pub size: usize,
589    pub locktime: u32,
590    pub vin: Vec<GetRawTransactionResultVin>,
591    pub vout: Vec<GetRawTransactionResultVout>,
592    #[serde(rename = "blockhash")]
593    pub block_hash: Option<BlockHash>,
594    pub confirmations: Option<u32>,
595    pub time: Option<usize>,
596    #[serde(rename = "blocktime")]
597    pub block_time: Option<usize>,
598    #[serde(rename = "blockheight")]
599    pub block_height: Option<u32>,
600}
601
602impl GetRawTransactionResult {
603    /// Whether this tx is a coinbase tx.
604    pub fn is_coinbase(&self) -> bool {
605        self.vin.len() == 1 && self.vin[0].is_coinbase()
606    }
607
608    pub fn transaction(&self) -> Result<Tx, bitcoinsv::Error> {
609        let tx = Tx::from_hex(&self.hex)?;
610        Ok(tx)
611    }
612}
613
614#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
615#[serde(rename_all = "camelCase")]
616pub struct GetTxOutResult {
617    pub bestblock: BlockHash,
618    pub confirmations: u32,
619    pub value: Amount,
620    pub script_pub_key: GetRawTransactionResultVoutScriptPubKey,
621    pub coinbase: bool,
622}
623
624#[allow(non_camel_case_types)]
625#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
626#[serde(rename_all = "lowercase")]
627pub enum ScriptPubkeyType {
628    Nonstandard,
629    Pubkey,
630    PubkeyHash,
631    ScriptHash,
632    MultiSig,
633    NullData,
634}
635
636/// Models the result of "getblockchaininfo"
637#[derive(Clone, Debug, Deserialize, Serialize)]
638pub struct GetBlockchainInfoResult {
639    /// Current network name as defined in BIP70 (main, test, signet, regtest)
640    pub chain: BlockchainId,
641    /// The current number of blocks processed in the server
642    pub blocks: u64,
643    /// The current number of headers we have validated
644    pub headers: u64,
645    /// The hash of the currently best block
646    #[serde(rename = "bestblockhash")]
647    pub best_block_hash: BlockHash,
648    /// The current difficulty
649    pub difficulty: f64,
650    /// Median time for the current best block
651    #[serde(rename = "mediantime")]
652    pub median_time: u64,
653    /// Estimate of verification progress [0..1]
654    #[serde(rename = "verificationprogress")]
655    pub verification_progress: f64,
656    /// Total amount of work in active chain, in hexadecimal
657    #[serde(rename = "chainwork", with = "crate::serde_hex")]
658    pub chain_work: Vec<u8>,
659    /// If the blocks are subject to pruning
660    pub pruned: bool,
661}
662
663#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
664pub struct GetMempoolInfoResult {
665    /// Current tx count
666    pub size: u64,
667    #[serde(rename = "journalsize")]
668    pub journal_size: u64,
669    #[serde(rename = "nonfinalsize")]
670    pub non_final_size: u64,
671    pub bytes: u64,
672    /// Total memory usage for the mempool
673    pub usage: usize,
674    #[serde(rename = "usagedisk")]
675    pub usage_disk: u64,
676    #[serde(rename = "usagecpfp")]
677    pub usage_cpfp: u64,
678    #[serde(rename = "nonfinalusage")]
679    pub non_final_usage: u64,
680    /// Maximum memory usage for the mempool
681    #[serde(rename = "maxmempool")]
682    pub max_mempool: usize,
683    #[serde(rename = "maxmempoolsizedisk")]
684    pub max_mempool_size_disk: u64,
685    #[serde(rename = "maxmempoolsizecpfp")]
686    pub max_mempool_size_cpfp: u64,
687    #[serde(rename = "mempoolminfee")]
688    pub mempool_min_fee: Amount,
689}
690
691#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
692pub struct GetMempoolEntryResult {
693    pub size: u64,
694    /// Transaction fee in BSV
695    pub fee: Amount,
696    #[serde(rename = "modifiedfee")]
697    pub modified_fee: Amount,
698    /// Local time transaction entered pool in seconds since 1 Jan 1970 GMT
699    pub time: u64,
700    /// Block height when transaction entered pool
701    pub height: u64,
702    /// Unconfirmed transactions used as inputs for this transaction
703    pub depends: Vec<TxHash>,
704}
705
706#[derive(Clone, Debug, Deserialize, Serialize)]
707pub struct GetPeerInfoResultStream {
708    #[serde(rename = "streamtype")]
709    pub stream_type: String,
710    /// The time of the last send
711    #[serde(rename = "lastsend")]
712    pub last_send: u64,
713    /// The time of the last receive
714    #[serde(rename = "lastrecv")]
715    pub last_recv: u64,
716    /// The total bytes sent
717    #[serde(rename = "bytessent")]
718    pub bytes_sent: u64,
719    /// The total bytes received
720    #[serde(rename = "bytesrecv")]
721    pub bytes_recv: u64,
722    #[serde(rename = "sendsize")]
723    pub send_size: u64,
724    #[serde(rename = "recvsize")]
725    pub recv_size: u64,
726    #[serde(rename = "sendmemory")]
727    pub send_memory: u64,
728    #[serde(rename = "spotrecvbw")]
729    pub spot_recv_bw: u64,
730    #[serde(rename = "minuterecvbw")]
731    pub minute_recv_bw: u64,
732    #[serde(rename = "pauserecv")]
733    pub pause_recv: bool,
734}
735
736/// Models the result of "getpeerinfo"
737#[derive(Clone, Debug, Deserialize, Serialize)]
738pub struct GetPeerInfoResult {
739    /// Peer index
740    pub id: u64,
741    /// The IP address and port of the peer
742    pub addr: String,
743    /// Local address as reported by the peer
744    #[serde(rename = "addrlocal")]
745    pub addr_local: Option<String>,
746    /// The services offered
747    pub services: String,
748    /// Whether peer has asked us to relay transactions to it
749    #[serde(rename = "relaytxes")]
750    pub relay_txes: bool,
751    /// The time of the last send
752    #[serde(rename = "lastsend")]
753    pub last_send: u64,
754    /// The time of the last receive
755    #[serde(rename = "lastrecv")]
756    pub last_recv: u64,
757    #[serde(rename = "sendsize")]
758    pub send_size: u64,
759    #[serde(rename = "recvsize")]
760    pub recv_size: u64,
761    #[serde(rename = "sendmemory")]
762    pub send_memory: u64,
763    #[serde(rename = "pausesend")]
764    pub pause_send: bool,
765    #[serde(rename = "unpausesend")]
766    pub unpause_send: bool,
767    /// The total bytes sent
768    #[serde(rename = "bytessent")]
769    pub bytes_sent: u64,
770    /// The total bytes received
771    #[serde(rename = "bytesrecv")]
772    pub bytes_recv: u64,
773    #[serde(rename = "avgrecvbw")]
774    pub avg_recv_bw: u64,
775    #[serde(rename = "associd")]
776    pub assoc_id: String,
777    #[serde(rename = "streampolicy")]
778    pub stream_policy: String,
779    pub streams: Vec<GetPeerInfoResultStream>,
780    #[serde(rename = "authconn")]
781    pub auth_conn: bool,
782    /// The connection time
783    #[serde(rename = "conntime")]
784    pub conn_time: u64,
785    /// The time offset in seconds
786    #[serde(rename = "timeoffset")]
787    pub time_offset: i64,
788    /// ping time (if available)
789    #[serde(rename = "pingtime")]
790    pub ping_time: Option<f64>,
791    /// minimum observed ping time (if any at all)
792    #[serde(rename = "minping")]
793    pub min_ping: Option<f64>,
794    /// ping wait (if non-zero)
795    #[serde(rename = "pingwait")]
796    pub ping_wait: Option<f64>,
797    /// The peer version, such as 70001
798    pub version: u64,
799    /// The string version
800    pub subver: String,
801    /// Inbound (true) or Outbound (false)
802    pub inbound: bool,
803    /// Whether connection was due to `addnode`/`-connect` or if it was an
804    /// automatic/inbound connection
805    #[serde(rename = "addnode")]
806    pub add_node: Option<bool>,
807    /// The starting height (block) of the peer
808    #[serde(rename = "startingheight")]
809    pub starting_height: i64,
810    /// The ban score
811    #[serde(rename = "banscore")]
812    pub ban_score: Option<i64>,
813    /// The last header we have in common with this peer
814    pub synced_headers: i64,
815    /// The last block we have in common with this peer
816    pub synced_blocks: i64,
817    /// The heights of blocks we're currently asking from this peer
818    #[serde(rename = "inflight")]
819    pub in_flight: Vec<u64>,
820    /// Whether the peer is whitelisted
821    #[serde(rename = "whitelisted")]
822    pub white_listed: Option<bool>,
823    /// The total bytes sent aggregated by message type
824    #[serde(rename = "bytessent_per_msg")]
825    pub bytes_sent_per_msg: HashMap<String, u64>,
826    /// The total bytes received aggregated by message type
827    #[serde(rename = "bytesrecv_per_msg")]
828    pub bytes_recv_per_msg: HashMap<String, u64>,
829}
830
831#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
832pub struct GetAddedNodeInfoResult {
833    /// The node IP address or name (as provided to addnode)
834    #[serde(rename = "addednode")]
835    pub added_node: String,
836    ///  If connected
837    pub connected: bool,
838    /// Only when connected = true
839    pub addresses: Vec<GetAddedNodeInfoResultAddress>,
840}
841
842#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
843pub struct GetAddedNodeInfoResultAddress {
844    /// The bitcoin server IP and port we're connected to
845    pub address: String,
846    /// connection, inbound or outbound
847    pub connected: GetAddedNodeInfoResultAddressType,
848}
849
850#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
851#[serde(rename_all = "lowercase")]
852pub enum GetAddedNodeInfoResultAddressType {
853    Inbound,
854    Outbound,
855}
856
857#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
858pub struct ListBannedResult {
859    pub address: String,
860    pub banned_until: u64,
861    pub ban_created: u64,
862    pub ban_reason: String,
863}
864
865/// Model for decode transaction
866#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
867pub struct DecodeRawTransactionResult {
868    pub txid: TxHash,
869    pub hash: TxHash,
870    pub size: u32,
871    pub version: u32,
872    pub locktime: u32,
873    pub vin: Vec<GetRawTransactionResultVin>,
874    pub vout: Vec<GetRawTransactionResultVout>,
875}
876
877/// Models the result of "getchaintips"
878pub type GetChainTipsResult = Vec<GetChainTipsResultTip>;
879
880/// Models a single chain tip for the result of "getchaintips"
881#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
882pub struct GetChainTipsResultTip {
883    /// Block height of the chain tip
884    pub height: u64,
885    /// Header hash of the chain tip
886    pub hash: BlockHash,
887    /// Length of the branch (number of blocks since the last common block)
888    #[serde(rename = "branchlen")]
889    pub branch_length: u32,
890    /// Status of the tip as seen by the node
891    pub status: GetChainTipsResultStatus,
892}
893
894#[derive(Copy, Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
895#[serde(rename_all = "lowercase")]
896pub enum GetChainTipsResultStatus {
897    /// The branch contains at least one invalid block
898    Invalid,
899    /// Not all blocks for this branch are available, but the headers are valid
900    #[serde(rename = "headers-only")]
901    HeadersOnly,
902    /// All blocks are available for this branch, but they were never fully validated
903    #[serde(rename = "valid-headers")]
904    ValidHeaders,
905    /// This branch is not part of the active chain, but is fully validated
906    #[serde(rename = "valid-fork")]
907    ValidFork,
908    /// This is the tip of the active main chain, which is certainly valid
909    Active,
910}
911
912// Used for createrawtransaction argument.
913#[derive(Serialize, Clone, PartialEq, Eq, Debug)]
914#[serde(rename_all = "camelCase")]
915pub struct CreateRawTransactionInput {
916    pub txid: TxHash,
917    pub vout: u32,
918    #[serde(skip_serializing_if = "Option::is_none")]
919    pub sequence: Option<u32>,
920}
921
922/// Used to represent UTXO set hash type
923#[derive(Clone, Serialize, PartialEq, Eq, Debug)]
924#[serde(rename_all = "snake_case")]
925pub enum TxOutSetHashType {
926    HashSerialized2,
927    Muhash,
928    None,
929}
930
931/// Used to specify a block hash or a height
932#[derive(Clone, Serialize, PartialEq, Eq, Debug)]
933#[serde(untagged)]
934pub enum HashOrHeight {
935    BlockHash(BlockHash),
936    Height(u64),
937}
938
939#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
940pub struct GetTxOutSetInfoResult {
941    /// The block height (index) of the returned statistics
942    pub height: u64,
943    /// The hash of the block at which these statistics are calculated
944    #[serde(rename = "bestblock")]
945    pub best_block: BlockHash,
946    /// The number of transactions with unspent outputs
947    pub transactions: u64,
948    /// The number of unspent transaction outputs
949    #[serde(rename = "txouts")]
950    pub tx_outs: u64,
951    /// A meaningless metric for UTXO set size
952    pub bogosize: u64,
953    /// The serialized hash
954    pub hash_serialized: BlockHash,
955    /// The estimated size of the chainstate on disk
956    pub disk_size: u64,
957    /// The total amount
958    pub total_amount: Amount,
959}
960
961#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
962pub struct GetNetTotalsResult {
963    /// Total bytes received
964    #[serde(rename = "totalbytesrecv")]
965    pub total_bytes_recv: u64,
966    /// Total bytes sent
967    #[serde(rename = "totalbytessent")]
968    pub total_bytes_sent: u64,
969    /// Current UNIX time in milliseconds
970    #[serde(rename = "timemillis")]
971    pub time_millis: u64,
972    /// Upload target statistics
973    #[serde(rename = "uploadtarget")]
974    pub upload_target: GetNetTotalsResultUploadTarget,
975}
976
977#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
978pub struct GetNetTotalsResultUploadTarget {
979    /// Length of the measuring timeframe in seconds
980    #[serde(rename = "timeframe")]
981    pub time_frame: u64,
982    /// Target in bytes
983    pub target: u64,
984    /// True if target is reached
985    pub target_reached: bool,
986    /// True if serving historical blocks
987    pub serve_historical_blocks: bool,
988    /// Bytes left in current time cycle
989    pub bytes_left_in_cycle: u64,
990    /// Seconds left in current time cycle
991    pub time_left_in_cycle: u64,
992}