chia_protocol/
block_record.rs1use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary};
2use crate::{calculate_ip_iters, calculate_sp_iters};
3use chia_streamable_macro::streamable;
4use chia_traits::chia_error::Result;
5#[cfg(feature = "py-bindings")]
6use pyo3::exceptions::PyValueError;
7
8#[cfg(feature = "py-bindings")]
9use pyo3::prelude::*;
10
11#[streamable]
15pub struct BlockRecord {
16 header_hash: Bytes32,
17 prev_hash: Bytes32,
19 height: u32,
20 weight: u128,
22 total_iters: u128,
24 signage_point_index: u8,
25 challenge_vdf_output: ClassgroupElement,
27 infused_challenge_vdf_output: Option<ClassgroupElement>,
29 reward_infusion_new_challenge: Bytes32,
31 challenge_block_info_hash: Bytes32,
33 sub_slot_iters: u64,
35 pool_puzzle_hash: Bytes32,
37 farmer_puzzle_hash: Bytes32,
38 required_iters: u64,
40 deficit: u8,
42 overflow: bool,
43 prev_transaction_block_height: u32,
44
45 timestamp: Option<u64>,
47 prev_transaction_block_hash: Option<Bytes32>,
49 fees: Option<u64>,
50 reward_claims_incorporated: Option<Vec<Coin>>,
51
52 finished_challenge_slot_hashes: Option<Vec<Bytes32>>,
54 finished_infused_challenge_slot_hashes: Option<Vec<Bytes32>>,
55 finished_reward_slot_hashes: Option<Vec<Bytes32>>,
56
57 sub_epoch_summary_included: Option<SubEpochSummary>,
59}
60
61impl BlockRecord {
62 pub fn is_transaction_block(&self) -> bool {
63 self.timestamp.is_some()
64 }
65
66 pub fn first_in_sub_slot(&self) -> bool {
67 self.finished_challenge_slot_hashes.is_some()
68 }
69
70 pub fn is_challenge_block(&self, min_blocks_per_challenge_block: u8) -> bool {
71 self.deficit == min_blocks_per_challenge_block - 1
72 }
73
74 pub fn sp_iters_impl(&self, num_sps_sub_slot: u8) -> Result<u64> {
75 calculate_sp_iters(
76 num_sps_sub_slot,
77 self.sub_slot_iters,
78 self.signage_point_index,
79 )
80 }
81
82 pub fn ip_iters_impl(&self, num_sps_sub_slot: u8, num_sp_intervals_extra: u8) -> Result<u64> {
83 calculate_ip_iters(
84 num_sps_sub_slot,
85 num_sp_intervals_extra,
86 self.sub_slot_iters,
87 self.signage_point_index,
88 self.required_iters,
89 )
90 }
91}
92
93#[cfg(feature = "py-bindings")]
94#[pymethods]
95impl BlockRecord {
96 #[getter]
97 #[pyo3(name = "is_transaction_block")]
98 fn py_is_transaction_block(&self) -> bool {
99 self.is_transaction_block()
100 }
101
102 #[getter]
103 #[pyo3(name = "first_in_sub_slot")]
104 fn py_first_in_sub_slot(&self) -> bool {
105 self.first_in_sub_slot()
106 }
107
108 #[pyo3(name = "is_challenge_block")]
109 fn py_is_challenge_block(&self, constants: &Bound<'_, PyAny>) -> PyResult<bool> {
110 Ok(self.is_challenge_block(
111 constants
112 .getattr("MIN_BLOCKS_PER_CHALLENGE_BLOCK")?
113 .extract::<u8>()?,
114 ))
115 }
116
117 #[pyo3(name = "ip_sub_slot_total_iters")]
118 fn ip_sub_slot_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult<u128> {
119 self.total_iters
120 .checked_sub(self.py_ip_iters_impl(constants)? as u128)
121 .ok_or(PyValueError::new_err("uint128 overflow"))
122 }
123
124 #[pyo3(name = "sp_iters")]
125 fn py_sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult<u64> {
126 let num_sps_sub_slot = constants.getattr("NUM_SPS_SUB_SLOT")?.extract::<u8>()?;
127 self.sp_iters_impl(num_sps_sub_slot).map_err(Into::into)
128 }
129
130 #[pyo3(name = "ip_iters")]
131 fn py_ip_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult<u64> {
132 let num_sps_sub_slot = constants.getattr("NUM_SPS_SUB_SLOT")?.extract::<u8>()?;
133 let num_sp_intervals_extra = constants
134 .getattr("NUM_SP_INTERVALS_EXTRA")?
135 .extract::<u8>()?;
136 self.ip_iters_impl(num_sps_sub_slot, num_sp_intervals_extra)
137 .map_err(Into::into)
138 }
139
140 #[pyo3(name = "sp_sub_slot_total_iters")]
141 fn sp_sub_slot_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult<u128> {
142 let ret = self
143 .total_iters
144 .checked_sub(self.py_ip_iters_impl(constants)? as u128)
145 .ok_or(PyValueError::new_err("uint128 overflow"))?;
146 if self.overflow {
147 ret.checked_sub(self.sub_slot_iters as u128)
148 .ok_or(PyValueError::new_err("uint128 overflow"))
149 } else {
150 Ok(ret)
151 }
152 }
153
154 #[pyo3(name = "sp_total_iters")]
155 fn sp_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult<u128> {
156 self.sp_sub_slot_total_iters_impl(constants)?
157 .checked_add(self.py_sp_iters_impl(constants)? as u128)
158 .ok_or(PyValueError::new_err("uint128 overflow"))
159 }
160}