1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Coin {
9 pub parent_coin_info: String,
10 pub puzzle_hash: String,
11 pub amount: u64,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct CoinRecord {
16 pub coin: Coin,
17 pub confirmed_block_index: u32,
18 pub spent_block_index: u32,
19 pub spent: bool,
20 pub coinbase: bool,
21 pub timestamp: u64,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct CoinSpend {
26 pub coin: Coin,
27 pub puzzle_reveal: String,
28 pub solution: String,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Condition {
33 pub opcode: serde_json::Value,
34 pub vars: Vec<String>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CoinSpendWithConditions {
39 pub coin_spend: CoinSpend,
40 pub conditions: Vec<Condition>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct SpendBundle {
45 pub coin_spends: Vec<CoinSpend>,
46 pub aggregated_signature: String,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct TxStatus {
55 pub status: String,
56 pub success: bool,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct AdditionsAndRemovals {
65 pub additions: Vec<CoinRecord>,
66 pub removals: Vec<CoinRecord>,
67}
68
69#[derive(Debug, Clone, Default, Serialize, Deserialize)]
71pub struct BlockRecord {
72 #[serde(default)]
73 pub header_hash: String,
74 #[serde(default)]
75 pub height: u32,
76 #[serde(default)]
77 pub weight: u64,
78 #[serde(default)]
79 pub prev_hash: String,
80 #[serde(default)]
81 pub total_iters: u64,
82 #[serde(default)]
83 pub signage_point_index: u8,
84 #[serde(default)]
85 pub farmer_puzzle_hash: String,
86 #[serde(default)]
87 pub pool_puzzle_hash: String,
88 #[serde(default)]
89 pub timestamp: Option<u64>,
90 #[serde(default)]
91 pub fees: Option<u64>,
92 #[serde(flatten)]
94 pub extra: serde_json::Value,
95}
96
97pub type FullBlock = serde_json::Value;
100
101pub type UnfinishedBlockHeader = serde_json::Value;
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct BlockCountMetrics {
106 pub compact_blocks: u64,
107 pub uncompact_blocks: u64,
108 pub hint_count: u64,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct FeeEstimate {
117 pub estimates: Vec<f64>,
118 pub target_times: Vec<u64>,
119 pub current_fee_rate: f64,
120 #[serde(default)]
121 pub mempool_size: u64,
122 #[serde(default)]
123 pub mempool_fees: u64,
124 #[serde(default)]
125 pub mempool_max_size: u64,
126 #[serde(default)]
127 pub num_spends: u64,
128 #[serde(default)]
129 pub full_node_synced: bool,
130 #[serde(default)]
131 pub peak_height: u32,
132 #[serde(default)]
133 pub last_peak_timestamp: u64,
134 #[serde(default)]
135 pub last_block_cost: u64,
136 #[serde(default)]
137 pub fees_last_block: u64,
138 #[serde(default)]
139 pub fee_rate_last_block: f64,
140 #[serde(default)]
141 pub last_tx_block_height: u32,
142 #[serde(default)]
143 pub node_time_utc: u64,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct NetworkInfo {
152 pub network_name: String,
153 pub network_prefix: String,
154 #[serde(default)]
155 pub genesis_challenge: String,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct SyncState {
160 pub sync_mode: bool,
161 pub sync_progress_height: u32,
162 pub sync_tip_height: u32,
163 pub synced: bool,
164}
165
166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
167pub struct BlockchainState {
168 #[serde(default)]
169 pub node_id: String,
170 #[serde(default)]
171 pub difficulty: u64,
172 #[serde(default)]
173 pub genesis_challenge_initialized: bool,
174 #[serde(default)]
175 pub mempool_size: u64,
176 #[serde(default)]
177 pub mempool_cost: u64,
178 #[serde(default)]
179 pub mempool_fees: u64,
180 #[serde(default)]
181 pub mempool_min_fees: serde_json::Value,
182 #[serde(default)]
183 pub mempool_max_total_cost: u64,
184 #[serde(default)]
185 pub block_max_cost: u64,
186 #[serde(default)]
187 pub peak: Option<BlockRecord>,
188 #[serde(default)]
189 pub space: u64,
190 #[serde(default)]
191 pub sub_slot_iters: u64,
192 #[serde(default)]
193 pub average_block_time: Option<f64>,
194 #[serde(default)]
195 pub sync: Option<SyncState>,
196}
197
198pub type MempoolItem = serde_json::Value;
204
205#[cfg(feature = "native")]
212impl Coin {
213 pub fn from_protocol(c: &chia_protocol::Coin) -> Self {
215 Self {
216 parent_coin_info: format!("0x{}", hex::encode(c.parent_coin_info)),
217 puzzle_hash: format!("0x{}", hex::encode(c.puzzle_hash)),
218 amount: c.amount,
219 }
220 }
221}
222
223#[cfg(test)]
228mod tests {
229 use super::*;
230
231 const PEAK_NEW_SHAPE: &str = r#"{
237 "peak": {
238 "header_hash": "0xabc",
239 "height": 9035425,
240 "weight": 123,
241 "prev_hash": "0xdef",
242 "total_iters": 456,
243 "signage_point_index": 7,
244 "farmer_puzzle_hash": "0xfarmer",
245 "pool_puzzle_hash": "0xpool",
246 "fees": 3000000000,
247 "timestamp": 1770000000,
248 "prev_transaction_block_hash": "0xprevtx",
249 "reward_claims_incorporated": [
250 { "parent_coin_info": "0x11", "puzzle_hash": "0x22", "amount": 1750000000000 },
251 { "parent_coin_info": "0x33", "puzzle_hash": "0x44", "amount": 250000000000 }
252 ]
253 }
254 }"#;
255
256 const PEAK_OLD_SHAPE: &str = r#"{
258 "peak": {
259 "header_hash": "0xabc",
260 "height": 9035424,
261 "fees": null,
262 "timestamp": null,
263 "prev_transaction_block_hash": null,
264 "reward_claims_incorporated": null
265 }
266 }"#;
267
268 #[test]
274 fn decodes_new_peak_shape_into_tolerant_fields() {
275 let state: BlockchainState =
276 serde_json::from_str(PEAK_NEW_SHAPE).expect("new peak shape must deserialize");
277 let peak = state.peak.expect("peak present");
278
279 assert_eq!(peak.height, 9035425);
281
282 assert_eq!(peak.fees, Some(3_000_000_000));
284 assert_eq!(peak.timestamp, Some(1_770_000_000));
285
286 assert_eq!(peak.extra["prev_transaction_block_hash"], "0xprevtx");
288 assert!(peak.extra["reward_claims_incorporated"].is_array());
289 assert_eq!(
290 peak.extra["reward_claims_incorporated"][0]["amount"],
291 1_750_000_000_000u64
292 );
293 }
294
295 #[test]
298 fn still_decodes_old_null_peak_shape() {
299 let state: BlockchainState =
300 serde_json::from_str(PEAK_OLD_SHAPE).expect("old peak shape must deserialize");
301 let peak = state.peak.expect("peak present");
302
303 assert_eq!(peak.height, 9035424);
304 assert_eq!(peak.fees, None);
305 assert_eq!(peak.timestamp, None);
306 assert!(peak.extra["prev_transaction_block_hash"].is_null());
307 assert!(peak.extra["reward_claims_incorporated"].is_null());
308 }
309}