1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
getblockchaininfo

Returns an object containing various state info regarding blockchain processing.

Result:
{                                         (json object)
  "chain" : "str",                        (string) current network name (main, test, regtest)
  "blocks" : n,                           (numeric) the height of the most-work fully-validated chain. The genesis block has height 0
  "headers" : n,                          (numeric) the current number of headers we have validated
  "bestblockhash" : "str",                (string) the hash of the currently best block
  "difficulty" : n,                       (numeric) the current difficulty
  "mediantime" : n,                       (numeric) median time for the current best block
  "verificationprogress" : n,             (numeric) estimate of verification progress [0..1]
  "initialblockdownload" : true|false,    (boolean) (debug information) estimate of whether this node is in Initial Block Download mode
  "chainwork" : "hex",                    (string) total amount of work in active chain, in hexadecimal
  "size_on_disk" : n,                     (numeric) the estimated size of the block and undo files on disk
  "pruned" : true|false,                  (boolean) if the blocks are subject to pruning
  "pruneheight" : n,                      (numeric) lowest-height complete block stored (only present if pruning is enabled)
  "automatic_pruning" : true|false,       (boolean) whether automatic pruning is enabled (only present if pruning is enabled)
  "prune_target_size" : n,                (numeric) the target size used by pruning (only present if automatic pruning is enabled)
  "softforks" : {                         (json object) status of softforks
    "xxxx" : {                            (json object) name of the softfork
      "type" : "str",                     (string) one of "buried", "bip9"
      "bip9" : {                          (json object) status of bip9 softforks (only for "bip9" type)
        "status" : "str",                 (string) one of "defined", "started", "locked_in", "active", "failed"
        "bit" : n,                        (numeric) the bit (0-28) in the block version field used to signal this softfork (only for "started" status)
        "start_time" : xxx,               (numeric) the minimum median time past of a block at which the bit gains its meaning
        "timeout" : xxx,                  (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in
        "since" : n,                      (numeric) height of the first block to which the status applies
        "statistics" : {                  (json object) numeric statistics about BIP9 signalling for a softfork (only for "started" status)
          "period" : n,                   (numeric) the length in blocks of the BIP9 signalling period
          "threshold" : n,                (numeric) the number of blocks with the version bit set required to activate the feature
          "elapsed" : n,                  (numeric) the number of blocks elapsed since the beginning of the current period
          "count" : n,                    (numeric) the number of blocks with the version bit set in the current period
          "possible" : true|false         (boolean) returns false if there are not enough blocks left in this period to pass activation threshold
        }
      },
      "height" : n,                       (numeric) height of the first block which the rules are or will be enforced (only for "buried" type, or "bip9" type with "active" status)
      "active" : true|false               (boolean) true if the rules are enforced for the mempool and the next block
    },
    ...
  },
  "warnings" : "str"                      (string) any network and blockchain warnings
}

Examples:
> bitcoin-cli getblockchaininfo
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockchaininfo", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
*/
use std::collections::HashMap;

use crate::client::Client;
use crate::command::request::request;
use crate::command::CallableCommand;
use serde::Deserialize;
use serde::Serialize;
use serde_json::value::RawValue;

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Statistics {
    pub period: u64,    // the length in blocks of the BIP9 signalling period
    pub threshold: u64, // the number of blocks with the version bit set required to activate the feature
    pub elapsed: u64,   // the number of blocks elapsed since the beginning of the current period
    pub count: u64,     //  the number of blocks with the version bit set in the current period
    pub possible: bool, // returns false if there are not enough blocks left in this period to pass activation threshold
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Bip9 {
    // TODO: can only be a couple strings
    pub status: String, // one of "defined", "started", "locked_in", "active", "failed"
    pub bit: u64, // the bit (0-28) in the block version field used to signal this softfork (only for "started" status)
    pub start_time: u64, //the minimum median time past of a block at which the bit gains its meaning
    pub timeout: u64, // the median time past of a block at which the deployment is considered failed if not yet locked in
    pub since: u64,   // height of the first block to which the status applies
    pub statistics: Statistics, // numeric statistics about BIP9 signalling for a softfork (only for "started" status)
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct SoftforkBip9Response {
    #[serde(rename = "type")]
    pub type_: String, // one of "buried", "bip9"
    pub bip9: Bip9,   // status of bip9 softforks (only for "bip9" type)
    pub height: u64, // height of the first block which the rules are or will be enforced (only for "buried" type, or "bip9" type with "active" status)
    pub active: bool, // true if the rules are enforced for the mempool and the next block
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
pub enum SoftFork {
    Bip9(SoftforkBip9Response),
    NonBip9(NonBip9SoftforkResponse),
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NonBip9SoftforkResponse {
    #[serde(rename = "type")]
    pub type_: String, // one of "buried", "bip9"
    pub height: u64, // height of the first block which the rules are or will be enforced (only for "buried" type, or "bip9" type with "active" status)
    pub active: bool, // true if the rules are enforced for the mempool and the next block
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockchainInfoCommandResponse {
    pub chain: String,         // current network name (main, test, regtest)
    pub blocks: u64, //the height of the most-work fully-validated chain. The genesis block has height 0
    pub headers: u64, // the current number of headers we have validated
    pub bestblockhash: String, //the hash of the currently best block
    pub difficulty: f64, //  the current difficulty
    pub mediantime: u64, //  median time for the current best block
    //  TODO: is only between 0-1
    pub verificationprogress: f64, //  estimate of verification progress [0..1]
    pub initialblockdownload: bool, // (debug information) estimate of whether this node is in Initial Block Download mode
    pub chainwork: String,          // "hex" total amount of work in active chain, in hexadecimal
    pub size_on_disk: u64,          // the estimated size of the block and undo files on disk
    pub pruned: bool,               // if the blocks are subject to pruning
    pub pruneheight: Option<u64>, // lowest-height complete block stored (only present if pruning is enabled)
    pub automatic_pruning: Option<bool>, // whether automatic pruning is enabled (only present if pruning is enabled)
    pub prune_target_size: Option<u64>, //the target size used by pruning (only present if automatic pruning is enabled)
    pub softforks: HashMap<String, SoftFork>, // status of softforks
    pub warnings: String,               // any network and blockchain warnings
}

pub struct GetBlockchainInfoCommand {}

impl GetBlockchainInfoCommand {
    pub fn new() -> Self {
        GetBlockchainInfoCommand {}
    }
}

impl CallableCommand for GetBlockchainInfoCommand {
    type Response = GetBlockchainInfoCommandResponse;
    fn call(&self, client: &Client) -> Result<Self::Response, jsonrpc::Error> {
        let command = "getblockchaininfo";
        let params: Vec<Box<RawValue>> = vec![];
        let r = request(client, command, params);
        let response: GetBlockchainInfoCommandResponse = r.result()?;
        Ok(response)
    }
}