bitcoind_request/command/get_block_stats.rs
1/*
2getblockstats hash_or_height ( stats )
3
4Compute per block statistics for a given window. All amounts are in satoshis.
5It won't work for some heights with pruning.
6
7Arguments:
81. hash_or_height (string or numeric, required) The block hash or height of the target block
92. stats (json array, optional, default=all values) Values to plot (see result below)
10 [
11 "height", (string) Selected statistic
12 "time", (string) Selected statistic
13 ...
14 ]
15
16Result:
17{ (json object)
18 "avgfee" : n, (numeric) Average fee in the block
19 "avgfeerate" : n, (numeric) Average feerate (in satoshis per virtual byte)
20 "avgtxsize" : n, (numeric) Average transaction size
21 "blockhash" : "hex", (string) The block hash (to check for potential reorgs)
22 "feerate_percentiles" : [ (json array) Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)
23 n, (numeric) The 10th percentile feerate
24 n, (numeric) The 25th percentile feerate
25 n, (numeric) The 50th percentile feerate
26 n, (numeric) The 75th percentile feerate
27 n (numeric) The 90th percentile feerate
28 ],
29 "height" : n, (numeric) The height of the block
30 "ins" : n, (numeric) The number of inputs (excluding coinbase)
31 "maxfee" : n, (numeric) Maximum fee in the block
32 "maxfeerate" : n, (numeric) Maximum feerate (in satoshis per virtual byte)
33 "maxtxsize" : n, (numeric) Maximum transaction size
34 "medianfee" : n, (numeric) Truncated median fee in the block
35 "mediantime" : n, (numeric) The block median time past
36 "mediantxsize" : n, (numeric) Truncated median transaction size
37 "minfee" : n, (numeric) Minimum fee in the block
38 "minfeerate" : n, (numeric) Minimum feerate (in satoshis per virtual byte)
39 "mintxsize" : n, (numeric) Minimum transaction size
40 "outs" : n, (numeric) The number of outputs
41 "subsidy" : n, (numeric) The block subsidy
42 "swtotal_size" : n, (numeric) Total size of all segwit transactions
43 "swtotal_weight" : n, (numeric) Total weight of all segwit transactions
44 "swtxs" : n, (numeric) The number of segwit transactions
45 "time" : n, (numeric) The block time
46 "total_out" : n, (numeric) Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])
47 "total_size" : n, (numeric) Total size of all non-coinbase transactions
48 "total_weight" : n, (numeric) Total weight of all non-coinbase transactions
49 "totalfee" : n, (numeric) The fee total
50 "txs" : n, (numeric) The number of transactions (including coinbase)
51 "utxo_increase" : n, (numeric) The increase/decrease in the number of unspent outputs
52 "utxo_size_inc" : n (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)
53}
54
55Examples:
56> bitcoin-cli getblockstats '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]'
57> bitcoin-cli getblockstats 1000 '["minfeerate","avgfeerate"]'
58> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockstats", "params": ["00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"]]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
59> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockstats", "params": [1000, ["minfeerate","avgfeerate"]]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
60 */
61use serde::{Deserialize, Serialize};
62use serde_json::value::to_raw_value;
63use std::fmt;
64
65use crate::{client::Client, command::CallableCommand, Blockhash};
66
67use super::request::request;
68
69type BlockHeight = u64;
70pub enum TargetBlockArgument {
71 Hash(Blockhash),
72 Height(BlockHeight),
73}
74// TODO: Fill in all of these:
75// https://bitcoincore.org/en/doc/0.21.0/rpc/blockchain/getblockstats/
76#[derive(Serialize, Deserialize, Debug)]
77pub enum StatsArgumentChoices {
78 AvgFee,
79 AvgTxSize,
80 Blockhash,
81 FeeRatePercentiles,
82 Height,
83 Ins,
84 MaxFee,
85 MaxFeeRate,
86 MaxTxSize,
87 MedianFee,
88 MedianTime,
89 MedianTxSize,
90 MinFee,
91 MinFeeRate,
92 MinTxSize,
93 Outs,
94 Subsidy,
95 SwTotalSize,
96 SwTotalWeight,
97 SwTxs,
98 Time,
99 TotalOut,
100 TotalSize,
101 TotalWeight,
102 TotalFee,
103 Txs,
104 UtxoIncrease,
105 UtxoSizeInc,
106}
107impl fmt::Display for StatsArgumentChoices {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 match self {
110 StatsArgumentChoices::AvgFee => write!(f, "avgfee"),
111 StatsArgumentChoices::AvgTxSize => write!(f, "avgtxsize"),
112 StatsArgumentChoices::Blockhash => write!(f, "blockhash"),
113 StatsArgumentChoices::FeeRatePercentiles => write!(f, "feerate_percentiles"),
114 StatsArgumentChoices::Height => write!(f, "height"),
115 StatsArgumentChoices::Ins => write!(f, "ins"),
116 StatsArgumentChoices::MaxFee => write!(f, "maxfee"),
117 StatsArgumentChoices::MaxFeeRate => write!(f, "maxfeerate"),
118 StatsArgumentChoices::MaxTxSize => write!(f, "maxtxsize"),
119 StatsArgumentChoices::MedianFee => write!(f, "medianfee"),
120 StatsArgumentChoices::MedianTime => write!(f, "mediantime"),
121 StatsArgumentChoices::MedianTxSize => write!(f, "mediantxsize"),
122 StatsArgumentChoices::MinFee => write!(f, "minfee"),
123 StatsArgumentChoices::MinFeeRate => write!(f, "minfeerate"),
124 StatsArgumentChoices::MinTxSize => write!(f, "mintxsize"),
125 StatsArgumentChoices::Outs => write!(f, "outs"),
126 StatsArgumentChoices::Subsidy => write!(f, "subsidy"),
127 StatsArgumentChoices::SwTotalSize => write!(f, "swtotal_size"),
128 StatsArgumentChoices::SwTotalWeight => write!(f, "swtotal_weight"),
129 StatsArgumentChoices::SwTxs => write!(f, "swtxs"),
130 StatsArgumentChoices::Time => write!(f, "time"),
131 StatsArgumentChoices::TotalOut => write!(f, "total_out"),
132 StatsArgumentChoices::TotalSize => write!(f, "total_size"),
133 StatsArgumentChoices::TotalWeight => write!(f, "total_weight"),
134 StatsArgumentChoices::TotalFee => write!(f, "totalfee"),
135 StatsArgumentChoices::Txs => write!(f, "txs"),
136 StatsArgumentChoices::UtxoIncrease => write!(f, "utxo_increase"),
137 StatsArgumentChoices::UtxoSizeInc => write!(f, "utxo_size_inc"),
138 }
139 }
140}
141pub struct GetBlockStatsCommand {
142 target_block: TargetBlockArgument,
143 stats: Vec<StatsArgumentChoices>,
144}
145
146impl GetBlockStatsCommand {
147 pub fn new(target_block: TargetBlockArgument) -> Self {
148 GetBlockStatsCommand {
149 target_block,
150 stats: vec![],
151 }
152 }
153 pub fn add_selective_stats(
154 &mut self,
155 stats_argument_choices: Vec<StatsArgumentChoices>,
156 ) -> &Self {
157 self.stats = stats_argument_choices;
158 self
159 }
160}
161#[derive(Serialize, Deserialize, Debug)]
162pub struct GetBlockStatsCommandWithSelectiveStatsResponse {
163 pub avgfee: Option<u64>, // Average fee in the block
164 pub avgfeerate: Option<u64>, // Average feerate (in satoshis per virtual byte)
165 pub avgtxsize: Option<u64>, // Average transaction size
166 pub blockhash: Option<String>, // "hex" The block hash (to check for potential reorgs)
167 pub feerate_percentiles: Option<[u64; 5]>, // Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)
168 // index 0, (numeric) The 10th percentile feerate
169 // index 1 (numeric) The 25th percentile feerate
170 // index 2 (numeric) The 50th percentile feerate
171 // index 3, (numeric) The 75th percentile feerate
172 // index 4 (numeric) The 90th percentile feerate
173 pub height: Option<u64>, // The height of the block
174 pub ins: Option<u64>, // The number of inputs (excluding coinbase)
175 pub maxfee: Option<u64>, // Maximum fee in the block
176 pub maxfeerate: Option<u64>, // Maximum feerate (in satoshis per virtual byte)
177 pub maxtxsize: Option<u64>, // Maximum transaction size
178 pub medianfee: Option<u64>, //Truncated median fee in the block
179 pub mediantime: Option<u64>, // The block median time past
180 pub mediantxsize: Option<u64>, // Truncated median transaction size
181 pub minfee: Option<u64>, // Minimum fee in the block
182 pub minfeerate: Option<u64>, // Minimum feerate (in satoshis per virtual byte)
183 pub mintxsize: Option<u64>, // Minimum transaction size
184 pub outs: Option<u64>, // The number of outputs
185 pub subsidy: Option<u64>, // The block subsidy
186 pub swtotal_size: Option<u64>, // Total size of all segwit transactions
187 pub swtotal_weight: Option<u64>, // Total weight of all segwit transactions
188 pub swtxs: Option<u64>, // The number of segwit transactions
189 pub time: Option<u64>, // The block time
190 pub total_out: Option<u64>, // Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])
191 pub total_size: Option<u64>, // Total size of all non-coinbase transactions
192 pub total_weight: Option<u64>, // Total weight of all non-coinbase transactions
193 pub totalfee: Option<u64>, // The fee total
194 pub txs: Option<u64>, // The number of transactions (including coinbase)
195 pub utxo_increase: Option<u64>, // The increase/decrease in the number of unspent outputs
196 pub utxo_size_inc: Option<u64>, // The increase/decrease in size for the utxo index (not discounting op_return and similar)
197}
198
199#[derive(Serialize, Deserialize, Debug)]
200pub struct GetBlockStatsCommandWithAllStatsResponse {
201 pub avgfee: u64, // Average fee in the block
202 pub avgfeerate: u64, // Average feerate (in satoshis per virtual byte)
203 pub avgtxsize: u64, // Average transaction size
204 pub blockhash: String, // "hex" The block hash (to check for potential reorgs)
205 pub feerate_percentiles: [u64; 5], // Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)
206 // index 0, (numeric) The 10th percentile feerate
207 // index 1 (numeric) The 25th percentile feerate
208 // index 2 (numeric) The 50th percentile feerate
209 // index 3, (numeric) The 75th percentile feerate
210 // index 4 (numeric) The 90th percentile feerate
211 pub height: u64, // The height of the block
212 pub ins: u64, // The number of inputs (excluding coinbase)
213 pub maxfee: u64, // Maximum fee in the block
214 pub maxfeerate: u64, // Maximum feerate (in satoshis per virtual byte)
215 pub maxtxsize: u64, // Maximum transaction size
216 pub medianfee: u64, //Truncated median fee in the block
217 pub mediantime: u64, // The block median time past
218 pub mediantxsize: u64, // Truncated median transaction size
219 pub minfee: u64, // Minimum fee in the block
220 pub minfeerate: u64, // Minimum feerate (in satoshis per virtual byte)
221 pub mintxsize: u64, // Minimum transaction size
222 pub outs: u64, // The number of outputs
223 pub subsidy: u64, // The block subsidy
224 pub swtotal_size: u64, // Total size of all segwit transactions
225 pub swtotal_weight: u64, // Total weight of all segwit transactions
226 pub swtxs: u64, // The number of segwit transactions
227 pub time: u64, // The block time
228 pub total_out: u64, // Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])
229 pub total_size: u64, // Total size of all non-coinbase transactions
230 pub total_weight: u64, // Total weight of all non-coinbase transactions
231 pub totalfee: u64, // The fee total
232 pub txs: u64, // The number of transactions (including coinbase)
233 pub utxo_increase: i64, // The increase/decrease in the number of unspent outputs
234 pub utxo_size_inc: i64, // The increase/decrease in size for the utxo index (not discounting op_return and similar)
235}
236
237#[derive(Serialize, Deserialize, Debug)]
238#[serde(rename_all = "camelCase")]
239#[serde(untagged)]
240pub enum GetBlockStatsCommandResponse {
241 SelectiveStats(GetBlockStatsCommandWithSelectiveStatsResponse),
242 AllStats(GetBlockStatsCommandWithAllStatsResponse),
243}
244
245impl CallableCommand for GetBlockStatsCommand {
246 type Response = GetBlockStatsCommandResponse;
247 fn call(&self, client: &Client) -> Result<Self::Response, jsonrpc::Error> {
248 let target_block = &self.target_block;
249 let hash_or_height_arg_raw_value = match target_block {
250 TargetBlockArgument::Hash(hash) => to_raw_value(&hash).unwrap(),
251 TargetBlockArgument::Height(height) => to_raw_value(&height).unwrap(),
252 };
253
254 // TODO: Add stats param!
255 let stats_arg: Vec<String> = self.stats.iter().map(|stat| stat.to_string()).collect();
256 let stats_arg_raw_value = to_raw_value(&stats_arg).unwrap();
257 let command = "getblockstats";
258 let params = vec![hash_or_height_arg_raw_value, stats_arg_raw_value];
259 let r = request(client, command, params);
260 let response: GetBlockStatsCommandResponse = if stats_arg.is_empty() {
261 GetBlockStatsCommandResponse::AllStats(r.result()?)
262 } else {
263 GetBlockStatsCommandResponse::SelectiveStats(r.result()?)
264 };
265 Ok(response)
266 }
267}