Skip to content
This repository was archived by the owner on Nov 26, 2024. It is now read-only.

Commit af6db57

Browse files
authored
json: Use i64 where possible (#40)
The Bitcoin Core JSONRPC API has fields marked as 'numeric'. It is not obvious what Rust type these fields should be. We want the version specific JSON types to just work (TM). 1. We use an `i64` because its the biggest signed integer on "common" machines. 2. We use a signed integer because Core sometimes returns -1. Some fields are then converted to `rust-bitcoin` types that expect a `u64` (eg sats), these are left as `u64` and we just hope Core never returns -1 for any of them.
2 parents d007f78 + 23d38ff commit af6db57

File tree

4 files changed

+418
-177
lines changed

4 files changed

+418
-177
lines changed

json/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,49 @@ pub mod v27;
2222

2323
// JSON types that model _all_ `bitcoind` versions.
2424
pub mod model;
25+
26+
use std::fmt;
27+
28+
/// Converts an `i64` numeric type to a `u32`.
29+
///
30+
/// The Bitcoin Core JSONRPC API has fields marked as 'numeric'. It is not obvious what Rust
31+
/// type these fields should be.
32+
///
33+
/// We want the version specific JSON types to just work (TM).
34+
///
35+
/// 1. We use an `i64` because its the biggest signed integer on "common" machines.
36+
/// 2. We use a signed integer because Core sometimes returns -1.
37+
///
38+
/// (2) was discovered in the wild but is hard to test for.
39+
pub fn to_u32(value: i64, field: &str) -> Result<u32, NumericError> {
40+
if value.is_negative() {
41+
return Err(NumericError::Negative { value, field: field.to_owned() });
42+
}
43+
u32::try_from(value).map_err(|_| NumericError::Overflow { value, field: field.to_owned() })
44+
}
45+
46+
/// Error converting an `i64` to a `u32`.
47+
///
48+
/// If we expect a numeric value to sanely fit inside a `u32` we use that type in the `model`
49+
/// module, this requires converting the `i64` returned by the JSONRPC API into a `u32`, if our
50+
/// expectations are not met this error will be encountered.
51+
#[derive(Debug)]
52+
pub enum NumericError {
53+
/// Expected an unsigned numeric value however the value was negative.
54+
Negative { field: String, value: i64 },
55+
/// A value larger than `u32::MAX` was unexpectedly encountered.
56+
Overflow { field: String, value: i64 },
57+
}
58+
59+
impl fmt::Display for NumericError {
60+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61+
use NumericError::*;
62+
63+
match *self {
64+
Negative{ ref field, value } => write!(f, "expected an unsigned numeric value however the value was negative (field name: {} value: {})", field, value),
65+
Overflow { ref field, value } => write!(f, "a value larger than `u32::MAX` was unexpectedly encountered (field name: {} Value: {})", field, value),
66+
}
67+
}
68+
}
69+
70+
impl std::error::Error for NumericError {}

json/src/model/blockchain.rs

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,25 @@ pub struct GetBlockVerbosityOne {
2828
/// The block hash (same as provided) in RPC call.
2929
pub hash: BlockHash,
3030
/// The number of confirmations, or -1 if the block is not on the main chain.
31-
pub confirmations: i32,
31+
pub confirmations: i64,
3232
/// The block size.
33-
pub size: usize,
33+
pub size: u32,
3434
/// The block size excluding witness data.
35-
pub stripped_size: Option<usize>, // Weight?
35+
pub stripped_size: Option<u32>,
3636
/// The block weight as defined in BIP-141.
3737
pub weight: Weight,
3838
/// The block height or index.
39-
pub height: usize,
39+
pub height: u32,
4040
/// The block version.
4141
pub version: block::Version,
42-
/// The block version formatted in hexadecimal.
43-
pub version_hex: String,
4442
/// The merkle root.
4543
pub merkle_root: String,
4644
/// The transaction ids.
4745
pub tx: Vec<Txid>,
4846
/// The block time expressed in UNIX epoch time.
49-
pub time: usize,
47+
pub time: u32,
5048
/// The median block time expressed in UNIX epoch time.
51-
pub median_time: Option<usize>,
49+
pub median_time: Option<u32>,
5250
/// The nonce.
5351
pub nonce: u32,
5452
/// The bits.
@@ -71,15 +69,15 @@ pub struct GetBlockchainInfo {
7169
/// Current network name as defined in BIP70 (main, test, signet, regtest).
7270
pub chain: Network,
7371
/// The current number of blocks processed in the server.
74-
pub blocks: u64,
72+
pub blocks: u32,
7573
/// The current number of headers we have validated.
76-
pub headers: u64,
74+
pub headers: u32,
7775
/// The hash of the currently best block.
7876
pub best_block_hash: BlockHash,
7977
/// The current difficulty.
8078
pub difficulty: f64,
8179
/// Median time for the current best block.
82-
pub median_time: u64,
80+
pub median_time: u32,
8381
/// Estimate of verification progress (between 0 and 1).
8482
pub verification_progress: f64,
8583
/// Estimate of whether this node is in Initial Block Download (IBD) mode.
@@ -91,11 +89,11 @@ pub struct GetBlockchainInfo {
9189
/// If the blocks are subject to pruning.
9290
pub pruned: bool,
9391
/// Lowest-height complete block stored (only present if pruning is enabled)
94-
pub prune_height: Option<u64>,
92+
pub prune_height: Option<u32>,
9593
/// Whether automatic pruning is enabled (only present if pruning is enabled).
9694
pub automatic_pruning: Option<bool>,
9795
/// The target size used by pruning (only present if automatic pruning is enabled).
98-
pub prune_target_size: Option<u64>,
96+
pub prune_target_size: Option<u32>,
9997
/// Status of softforks in progress, maps softfork name -> [`Softfork`].
10098
pub softforks: BTreeMap<String, Softfork>,
10199
/// Any network and blockchain warnings.
@@ -111,7 +109,7 @@ pub struct Softfork {
111109
/// The status of bip9 softforks (only for "bip9" type).
112110
pub bip9: Option<Bip9SoftforkInfo>,
113111
/// Height of the first block which the rules are or will be enforced (only for "buried" type, or "bip9" type with "active" status).
114-
pub height: Option<u64>,
112+
pub height: Option<u32>,
115113
/// `true` if the rules are enforced for the mempool and the next block.
116114
pub active: bool,
117115
}
@@ -138,9 +136,9 @@ pub struct Bip9SoftforkInfo {
138136
/// The bit (0-28) in the block version field used to signal this softfork (only for "started" status).
139137
pub bit: Option<u8>,
140138
/// The minimum median time past of a block at which the bit gains its meaning.
141-
pub start_time: i64,
139+
pub start_time: u32,
142140
/// The median time past of a block at which the deployment is considered failed if not yet locked in.
143-
pub timeout: u64,
141+
pub timeout: u32,
144142
/// Height of the first block to which the status applies.
145143
pub since: u32,
146144
/// Numeric statistics about BIP-9 signalling for a softfork (only for "started" status).
@@ -197,17 +195,17 @@ pub struct GetBlockHeaderVerbose {
197195
/// The number of confirmations, or -1 if the block is not on the main chain.
198196
pub confirmations: i64,
199197
/// The block height or index.
200-
pub height: u64,
198+
pub height: u32,
201199
/// Block version, now repurposed for soft fork signalling.
202200
pub version: block::Version,
203201
/// The root hash of the Merkle tree of transactions in the block.
204202
pub merkle_root: TxMerkleNode,
205203
/// The timestamp of the block, as claimed by the miner (seconds since epoch (Jan 1 1970 GMT).
206-
pub time: u64,
204+
pub time: u32,
207205
/// The median block time in seconds since epoch (Jan 1 1970 GMT).
208-
pub median_time: u64,
206+
pub median_time: u32,
209207
/// The nonce.
210-
pub nonce: u64,
208+
pub nonce: u32,
211209
/// The target value below which the blockhash must lie.
212210
pub bits: CompactTarget,
213211
/// The difficulty.
@@ -223,66 +221,65 @@ pub struct GetBlockHeaderVerbose {
223221
}
224222

225223
/// Models the result of JSON-RPC method `getblockstats`.
226-
// FIXME: Should all the sizes be u32, u64, or usize?
227224
pub struct GetBlockStats {
228225
/// Average fee in the block.
229226
pub average_fee: Amount,
230227
/// Average feerate.
231228
pub average_fee_rate: Option<FeeRate>,
232229
/// Average transaction size.
233-
pub average_tx_size: u64,
230+
pub average_tx_size: u32,
234231
/// The block hash (to check for potential reorgs).
235232
pub block_hash: BlockHash,
236233
/// Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte).
237234
pub fee_rate_percentiles: Vec<Option<FeeRate>>,
238235
/// The height of the block.
239-
pub height: u64,
236+
pub height: u32,
240237
/// The number of inputs (excluding coinbase).
241-
pub inputs: u64,
238+
pub inputs: u32,
242239
/// Maximum fee in the block.
243240
pub max_fee: Amount,
244241
/// Maximum feerate (in satoshis per virtual byte).
245242
pub max_fee_rate: Option<FeeRate>,
246243
/// Maximum transaction size.
247-
pub max_tx_size: u64,
244+
pub max_tx_size: u32,
248245
/// Truncated median fee in the block.
249246
pub median_fee: Amount,
250247
/// The block median time past.
251248
pub median_time: u32,
252249
/// Truncated median transaction size
253-
pub median_tx_size: u64,
250+
pub median_tx_size: u32,
254251
/// Minimum fee in the block.
255252
pub minimum_fee: Amount,
256253
/// Minimum feerate (in satoshis per virtual byte).
257254
pub minimum_fee_rate: Option<FeeRate>,
258255
/// Minimum transaction size.
259-
pub minimum_tx_size: u64,
256+
pub minimum_tx_size: u32,
260257
/// The number of outputs.
261-
pub outputs: u64,
258+
pub outputs: u32,
262259
/// The block subsidy.
263260
pub subsidy: Amount,
264261
/// Total size of all segwit transactions.
265-
pub segwit_total_size: u64,
262+
pub segwit_total_size: u32,
266263
/// Total weight of all segwit transactions divided by segwit scale factor (4).
267264
pub segwit_total_weight: Option<Weight>,
268265
/// The number of segwit transactions.
269-
pub segwit_txs: u64,
266+
pub segwit_txs: u32,
270267
/// The block time.
271268
pub time: u32,
272269
/// Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee]).
273270
pub total_out: Amount,
274271
/// Total size of all non-coinbase transactions.
275-
pub total_size: u64,
272+
pub total_size: u32,
276273
/// Total weight of all non-coinbase transactions divided by segwit scale factor (4).
277274
pub total_weight: Option<Weight>,
278275
/// The fee total.
279276
pub total_fee: Amount,
280277
/// The number of transactions (excluding coinbase).
281-
pub txs: u64,
278+
pub txs: u32,
282279
/// The increase/decrease in the number of unspent outputs.
283-
pub utxo_increase: u64,
280+
pub utxo_increase: i32,
284281
/// The increase/decrease in size for the utxo index (not discounting op_return and similar).
285-
pub utxo_size_increase: u64,
282+
pub utxo_size_increase: i32,
286283
}
287284

288285
/// Result of JSON-RPC method `getchaintips`.
@@ -293,11 +290,11 @@ pub struct GetChainTips(pub Vec<ChainTips>);
293290
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
294291
pub struct ChainTips {
295292
/// Height of the chain tip.
296-
pub height: u64,
293+
pub height: u32,
297294
/// Block hash of the tip.
298295
pub hash: BlockHash,
299296
/// Zero for main chain.
300-
pub branch_length: u64,
297+
pub branch_length: u32,
301298
/// "active" for the main chain.
302299
pub status: ChainTipsStatus,
303300
}
@@ -324,17 +321,17 @@ pub struct GetChainTxStats {
324321
/// The timestamp for the final block in the window in UNIX format.
325322
pub time: u32,
326323
/// The total number of transactions in the chain up to that point.
327-
pub tx_count: u64,
324+
pub tx_count: u32,
328325
/// The hash of the final block in the window.
329326
pub window_final_block_hash: BlockHash,
330327
/// Size of the window in number of blocks.
331-
pub window_block_count: u64,
328+
pub window_block_count: u32,
332329
/// The number of transactions in the window. Only returned if "window_block_count" is > 0.
333-
pub window_tx_count: Option<u64>,
330+
pub window_tx_count: Option<u32>,
334331
/// The elapsed time in the window in seconds. Only returned if "window_block_count" is > 0.
335-
pub window_interval: Option<u64>,
332+
pub window_interval: Option<u32>,
336333
/// The average rate of transactions per second in the window. Only returned if "window_interval" is > 0.
337-
pub tx_rate: Option<u64>,
334+
pub tx_rate: Option<u32>,
338335
}
339336

340337
/// Result of JSON-RPC method `getdifficulty`.
@@ -354,8 +351,8 @@ pub struct GetMempoolAncestorsVerbose {}
354351
pub struct GetTxOut {
355352
/// The hash of the block at the tip of the chain.
356353
pub best_block: BlockHash,
357-
/// The number of confirmations.
358-
pub confirmations: u32,
354+
/// The number of confirmations (signed to match other types with the same field name).
355+
pub confirmations: i64,
359356
/// The returned `TxOut` (strongly typed).
360357
pub tx_out: TxOut,
361358
/// Address that `tx_out` spends to.

0 commit comments

Comments
 (0)