From fe7819a05f84f5da139181b1d58082d9bf77aa8b Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 14:10:51 +0000 Subject: [PATCH 01/28] remove imports from test_blscache and delete test_program_fidelity --- tests/test_blscache.py | 13 +--- tests/test_program_fidelity.py | 133 --------------------------------- 2 files changed, 3 insertions(+), 143 deletions(-) delete mode 100644 tests/test_program_fidelity.py diff --git a/tests/test_blscache.py b/tests/test_blscache.py index 44fb7cb7c..d16e5d13c 100644 --- a/tests/test_blscache.py +++ b/tests/test_blscache.py @@ -14,9 +14,6 @@ ) from chia_rs.sized_bytes import bytes32 from chia_rs.sized_ints import uint8, uint16, uint32, uint64, uint128 -from chia.util.hash import std_hash -from chia.util.lru_cache import LRUCache -from chia.types.blockchain_format.program import Program as ChiaProgram import pytest @@ -174,7 +171,6 @@ def test_cached_bls(): # Use a small cache which can not accommodate all pairings bls_cache = BLSCache(n_keys // 2) - local_cache = LRUCache(n_keys // 2) # Verify signatures and cache pairings one at a time for pk, msg, sig in zip(pks_half, msgs_half, sigs_half): assert bls_cache.aggregate_verify([pk], [msg], sig) @@ -221,13 +217,10 @@ def test_cached_bls_repeat_pk(): cached_bls = BLSCache() n_keys = 400 seed = b"a" * 32 - sks = [AugSchemeMPL.key_gen(seed) for i in range(n_keys)] + [ - AugSchemeMPL.key_gen(std_hash(seed)) - ] + sks = [AugSchemeMPL.key_gen(seed) for _ in range(n_keys)] pks = [sk.get_g1() for sk in sks] - pks_bytes = [bytes(sk.get_g1()) for sk in sks] - msgs = [("msg-%d" % (i,)).encode() for i in range(n_keys + 1)] + msgs = [("msg-%d" % (i,)).encode() for i in range(n_keys)] sigs = [AugSchemeMPL.sign(sk, msg) for sk, msg in zip(sks, msgs)] agg_sig = AugSchemeMPL.aggregate(sigs) @@ -305,7 +298,7 @@ def test_validate_clvm_and_sig(): sig = AugSchemeMPL.sign( sk, ( - ChiaProgram.to("hello").as_atom() + b'hello' + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA ), # noqa diff --git a/tests/test_program_fidelity.py b/tests/test_program_fidelity.py deleted file mode 100644 index b8753aefe..000000000 --- a/tests/test_program_fidelity.py +++ /dev/null @@ -1,133 +0,0 @@ -from typing import Optional - -import string -import chia_rs -from chia.types.blockchain_format.program import Program as ChiaProgram -from chia.types.blockchain_format.serialized_program import SerializedProgram -from random import Random - - -def rand_bytes(rnd: Random) -> bytes: - size = rnd.randint(0, 4) - ret = bytearray() - for _ in range(size): - ret.append(rnd.getrandbits(8)) - return bytes(ret) - - -def rand_string(rnd: Random) -> str: - size = rnd.randint(1, 10) - return "".join(rnd.choices(string.ascii_uppercase + string.digits, k=size)) - - -def rand_int(rnd: Random) -> int: - return rnd.randint(0, 100000000000000) - - -def rand_list(rnd: Random) -> list: - size = rnd.randint(0, 3) - ret = [] - for _ in range(size): - ret.append(rand_object(rnd)) - return ret - - -def rand_program(rnd: Random) -> ChiaProgram: - return ChiaProgram.from_bytes(b"\xff\x01\xff\x04\x01") - - -def rand_rust_program(rnd: Random) -> chia_rs.Program: - return chia_rs.Program.from_bytes(b"\xff\x01\xff\x04\x01") - - -def rand_optional(rnd: Random) -> Optional[object]: - if rnd.randint(0, 1) == 0: - return None - return rand_object(rnd) - - -def rand_object(rnd: Random) -> object: - types = [ - rand_optional, - rand_int, - rand_string, - rand_bytes, - rand_program, - rand_list, - rand_rust_program, - ] - return rnd.sample(types, 1)[0](rnd) - - -def recursive_replace(o: object) -> object: - if isinstance(o, list): - ret = [] - for i in o: - ret.append(recursive_replace(i)) - return ret - elif isinstance(o, chia_rs.Program): - return SerializedProgram.from_bytes(o.to_bytes()) - else: - return o - - -def test_run_program() -> None: - - rust_identity = chia_rs.Program.from_bytes(b"\x01") - py_identity = SerializedProgram.from_bytes(b"\x01") - - rnd = Random() - for _ in range(10000): - args = rand_object(rnd) - - # the python SerializedProgram treats itself specially, the rust - # Program treats itself specially, but they don't recognize each other, - # so they will produce different results in this regard - rust_ret = rust_identity._run(10000, 0, args) - - # Replace rust Program with the python SerializedProgram. - args = recursive_replace(args) - - py_ret = py_identity._run(10000, 0, args) - - assert rust_ret == py_ret - - -def test_tree_hash() -> None: - - rnd = Random() - for _ in range(10000): - py_prg = ChiaProgram.to(rand_object(rnd)) - rust_prg = chia_rs.Program.from_bytes(bytes(py_prg)) - - assert py_prg.get_tree_hash() == rust_prg.get_tree_hash() - - -def test_uncurry() -> None: - - rnd = Random() - for _ in range(10000): - py_prg = ChiaProgram.to(rand_object(rnd)) - py_prg = py_prg.curry(rand_object(rnd)) - rust_prg = chia_rs.Program.from_program(py_prg) - assert py_prg.uncurry() == rust_prg.uncurry() - - py_prg = py_prg.curry(rand_object(rnd), rand_object(rnd)) - rust_prg = chia_rs.Program.from_program(py_prg) - assert py_prg.uncurry() == rust_prg.uncurry() - - -def test_round_trip() -> None: - - rnd = Random() - for _ in range(10000): - obj = rand_object(rnd) - py_prg = ChiaProgram.to(obj) - rust_prg = chia_rs.Program.from_program(py_prg) - rust_prg2 = chia_rs.Program.to(obj) - - assert py_prg == rust_prg.to_program() - assert py_prg == rust_prg2.to_program() - - assert bytes(py_prg) == bytes(rust_prg) - assert bytes(py_prg) == bytes(rust_prg2) From 315fab07a5bf14b632462085e06af6112000e68c Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 15:03:43 +0000 Subject: [PATCH 02/28] remove imports from block_record by implement pot_iterations --- crates/chia-protocol/src/block_record.rs | 131 +++++++++++++---------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index c90e0d77b..51567b176 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,6 +1,5 @@ -use chia_streamable_macro::streamable; - use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; +use chia_streamable_macro::streamable; #[cfg(feature = "py-bindings")] use pyo3::prelude::*; @@ -69,9 +68,6 @@ impl BlockRecord { } } -#[cfg(feature = "py-bindings")] -use pyo3::types::PyDict; - #[cfg(feature = "py-bindings")] use pyo3::exceptions::PyValueError; @@ -102,16 +98,11 @@ impl BlockRecord { )) } - // TODO: at some point it would be nice to port - // chia.consensus.pot_iterations to rust, and make this less hacky - fn sp_sub_slot_total_iters_impl( - &self, - py: Python<'_>, - constants: &Bound<'_, PyAny>, - ) -> PyResult { + // TODO: these could be implemented as a total port of pot iterations + fn sp_sub_slot_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { let ret = self .total_iters - .checked_sub(self.ip_iters_impl(py, constants)? as u128) + .checked_sub(self.ip_iters_impl(constants)? as u128) .ok_or(PyValueError::new_err("uint128 overflow"))?; if self.overflow { ret.checked_sub(self.sub_slot_iters as u128) @@ -121,48 +112,76 @@ impl BlockRecord { } } - fn ip_sub_slot_total_iters_impl( - &self, - py: Python<'_>, - constants: &Bound<'_, PyAny>, - ) -> PyResult { + fn ip_sub_slot_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { self.total_iters - .checked_sub(self.ip_iters_impl(py, constants)? as u128) + .checked_sub(self.ip_iters_impl(constants)? as u128) .ok_or(PyValueError::new_err("uint128 overflow")) } - fn sp_iters_impl(&self, py: Python<'_>, constants: &Bound<'_, PyAny>) -> PyResult { - let ctx = PyDict::new(py); - ctx.set_item("sub_slot_iters", self.sub_slot_iters)?; - ctx.set_item("signage_point_index", self.signage_point_index)?; - ctx.set_item("constants", constants)?; - py.run( - c"from chia.consensus.pot_iterations import calculate_ip_iters, calculate_sp_iters\n\ - ret = calculate_sp_iters(constants, sub_slot_iters, signage_point_index)\n", - None, - Some(&ctx), - )?; - ctx.get_item("ret").unwrap().unwrap().extract::() - } - - fn ip_iters_impl(&self, py: Python<'_>, constants: &Bound<'_, PyAny>) -> PyResult { - let ctx = PyDict::new(py); - ctx.set_item("sub_slot_iters", self.sub_slot_iters)?; - ctx.set_item("signage_point_index", self.signage_point_index)?; - ctx.set_item("required_iters", self.required_iters)?; - ctx.set_item("constants", constants)?; - py.run( - c"from chia.consensus.pot_iterations import calculate_ip_iters, calculate_sp_iters\n\ - ret = calculate_ip_iters(constants, sub_slot_iters, signage_point_index, required_iters)\n", - None, - Some(&ctx), - )?; - ctx.get_item("ret").unwrap().unwrap().extract::() - } - - fn sp_total_iters_impl(&self, py: Python<'_>, constants: &Bound<'_, PyAny>) -> PyResult { - self.sp_sub_slot_total_iters_impl(py, constants)? - .checked_add(self.sp_iters_impl(py, constants)? as u128) + fn calculate_sp_interval_iters( + &self, + num_sps_sub_slot: u64, + sub_slot_iters: u64, + ) -> PyResult { + if sub_slot_iters % num_sps_sub_slot != 0 { + return Err(PyValueError::new_err( + "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", + )); + } + return Ok(sub_slot_iters / num_sps_sub_slot); + } + + fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { + if self.signage_point_index as u32 >= num_sps_sub_slot { + return Err(PyValueError::new_err("SP index too high")); + } + return Ok(self + .calculate_sp_interval_iters(num_sps_sub_slot as u64, self.sub_slot_iters)? + * self.signage_point_index as u64); + } + + fn calculate_ip_iters( + &self, + num_sps_sub_slot: u32, + num_sp_intervals_extra: u8, + ) -> PyResult { + let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; + let sp_interval_iters = + self.calculate_sp_interval_iters(num_sps_sub_slot as u64, self.sub_slot_iters)?; + if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { + return Err(PyValueError::new_err(format!( + "Invalid sp iters {} for this ssi {}", + sp_iters, sp_interval_iters + ))); + } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { + return Err(PyValueError::new_err(format!( + "Required iters {} is not below the sp interval iters {} {} or not >=0", + self.required_iters, sp_interval_iters, self.sub_slot_iters + ))); + } else { + return Ok((sp_iters + + num_sp_intervals_extra as u64 * sp_interval_iters + + self.required_iters) + % self.sub_slot_iters); + } + } + + fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { + let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; + self.calculate_sp_iters(num_sps_sub_slot) + } + + fn ip_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { + let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; + let num_sp_intervals_extra = constants + .get_item("NUM_SP_INTERVALS_EXTRA")? + .extract::()?; + self.calculate_ip_iters(num_sps_sub_slot, num_sp_intervals_extra) + } + + fn sp_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { + self.sp_sub_slot_total_iters_impl(constants)? + .checked_add(self.sp_iters_impl(constants)? as u128) .ok_or(PyValueError::new_err("uint128 overflow")) } @@ -171,7 +190,7 @@ impl BlockRecord { py: Python<'a>, constants: &Bound<'_, PyAny>, ) -> PyResult> { - ChiaToPython::to_python(&self.sp_sub_slot_total_iters_impl(py, constants)?, py) + ChiaToPython::to_python(&self.sp_sub_slot_total_iters_impl(constants)?, py) } fn ip_sub_slot_total_iters<'a>( @@ -179,7 +198,7 @@ impl BlockRecord { py: Python<'a>, constants: &Bound<'_, PyAny>, ) -> PyResult> { - ChiaToPython::to_python(&self.ip_sub_slot_total_iters_impl(py, constants)?, py) + ChiaToPython::to_python(&self.ip_sub_slot_total_iters_impl(constants)?, py) } fn sp_iters<'a>( @@ -187,7 +206,7 @@ impl BlockRecord { py: Python<'a>, constants: &Bound<'_, PyAny>, ) -> PyResult> { - ChiaToPython::to_python(&self.sp_iters_impl(py, constants)?, py) + ChiaToPython::to_python(&self.sp_iters_impl(constants)?, py) } fn ip_iters<'a>( @@ -195,7 +214,7 @@ impl BlockRecord { py: Python<'a>, constants: &Bound<'_, PyAny>, ) -> PyResult> { - ChiaToPython::to_python(&self.ip_iters_impl(py, constants)?, py) + ChiaToPython::to_python(&self.ip_iters_impl(constants)?, py) } fn sp_total_iters<'a>( @@ -203,6 +222,6 @@ impl BlockRecord { py: Python<'a>, constants: &Bound<'_, PyAny>, ) -> PyResult> { - ChiaToPython::to_python(&self.sp_total_iters_impl(py, constants)?, py) + ChiaToPython::to_python(&self.sp_total_iters_impl(constants)?, py) } } From 0d406e77dd210a57447de8ffe306bd923d05991d Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 15:15:51 +0000 Subject: [PATCH 03/28] clippy and fmt --- crates/chia-protocol/src/block_record.rs | 31 +++++++++--------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index 51567b176..640da0541 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -118,26 +118,21 @@ impl BlockRecord { .ok_or(PyValueError::new_err("uint128 overflow")) } - fn calculate_sp_interval_iters( - &self, - num_sps_sub_slot: u64, - sub_slot_iters: u64, - ) -> PyResult { - if sub_slot_iters % num_sps_sub_slot != 0 { + fn calculate_sp_interval_iters(&self, num_sps_sub_slot: u64) -> PyResult { + if self.sub_slot_iters % num_sps_sub_slot != 0 { return Err(PyValueError::new_err( "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", )); } - return Ok(sub_slot_iters / num_sps_sub_slot); + Ok(self.sub_slot_iters / num_sps_sub_slot) } fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { if self.signage_point_index as u32 >= num_sps_sub_slot { return Err(PyValueError::new_err("SP index too high")); } - return Ok(self - .calculate_sp_interval_iters(num_sps_sub_slot as u64, self.sub_slot_iters)? - * self.signage_point_index as u64); + Ok(self.calculate_sp_interval_iters(num_sps_sub_slot as u64)? + * self.signage_point_index as u64) } fn calculate_ip_iters( @@ -146,24 +141,22 @@ impl BlockRecord { num_sp_intervals_extra: u8, ) -> PyResult { let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; - let sp_interval_iters = - self.calculate_sp_interval_iters(num_sps_sub_slot as u64, self.sub_slot_iters)?; + let sp_interval_iters = self.calculate_sp_interval_iters(num_sps_sub_slot as u64)?; if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { return Err(PyValueError::new_err(format!( - "Invalid sp iters {} for this ssi {}", - sp_iters, sp_interval_iters + "Invalid sp iters {sp_iters} for this ssi {}", + self.sub_slot_iters ))); } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { return Err(PyValueError::new_err(format!( "Required iters {} is not below the sp interval iters {} {} or not >=0", self.required_iters, sp_interval_iters, self.sub_slot_iters ))); - } else { - return Ok((sp_iters - + num_sp_intervals_extra as u64 * sp_interval_iters - + self.required_iters) - % self.sub_slot_iters); } + Ok( + (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + self.required_iters) + % self.sub_slot_iters, + ) } fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { From d27c1a5f7560e9f6f37035823a142530b6d4c93c Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 15:39:33 +0000 Subject: [PATCH 04/28] don't export new functions --- crates/chia-protocol/src/block_record.rs | 82 ++++++++++++------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index 640da0541..c9eea8528 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -66,6 +66,47 @@ impl BlockRecord { pub fn is_challenge_block(&self, min_blocks_per_challenge_block: u8) -> bool { self.deficit == min_blocks_per_challenge_block - 1 } + + fn calculate_sp_interval_iters(&self, num_sps_sub_slot: u64) -> PyResult { + if self.sub_slot_iters % num_sps_sub_slot != 0 { + return Err(PyValueError::new_err( + "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", + )); + } + Ok(self.sub_slot_iters / num_sps_sub_slot) + } + + fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { + if self.signage_point_index as u32 >= num_sps_sub_slot { + return Err(PyValueError::new_err("SP index too high")); + } + Ok(self.calculate_sp_interval_iters(num_sps_sub_slot as u64)? + * self.signage_point_index as u64) + } + + fn calculate_ip_iters( + &self, + num_sps_sub_slot: u32, + num_sp_intervals_extra: u8, + ) -> PyResult { + let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; + let sp_interval_iters = self.calculate_sp_interval_iters(num_sps_sub_slot as u64)?; + if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { + return Err(PyValueError::new_err(format!( + "Invalid sp iters {sp_iters} for this ssi {}", + self.sub_slot_iters + ))); + } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { + return Err(PyValueError::new_err(format!( + "Required iters {} is not below the sp interval iters {} {} or not >=0", + self.required_iters, sp_interval_iters, self.sub_slot_iters + ))); + } + Ok( + (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + self.required_iters) + % self.sub_slot_iters, + ) + } } #[cfg(feature = "py-bindings")] @@ -118,47 +159,6 @@ impl BlockRecord { .ok_or(PyValueError::new_err("uint128 overflow")) } - fn calculate_sp_interval_iters(&self, num_sps_sub_slot: u64) -> PyResult { - if self.sub_slot_iters % num_sps_sub_slot != 0 { - return Err(PyValueError::new_err( - "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", - )); - } - Ok(self.sub_slot_iters / num_sps_sub_slot) - } - - fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { - if self.signage_point_index as u32 >= num_sps_sub_slot { - return Err(PyValueError::new_err("SP index too high")); - } - Ok(self.calculate_sp_interval_iters(num_sps_sub_slot as u64)? - * self.signage_point_index as u64) - } - - fn calculate_ip_iters( - &self, - num_sps_sub_slot: u32, - num_sp_intervals_extra: u8, - ) -> PyResult { - let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; - let sp_interval_iters = self.calculate_sp_interval_iters(num_sps_sub_slot as u64)?; - if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { - return Err(PyValueError::new_err(format!( - "Invalid sp iters {sp_iters} for this ssi {}", - self.sub_slot_iters - ))); - } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { - return Err(PyValueError::new_err(format!( - "Required iters {} is not below the sp interval iters {} {} or not >=0", - self.required_iters, sp_interval_iters, self.sub_slot_iters - ))); - } - Ok( - (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + self.required_iters) - % self.sub_slot_iters, - ) - } - fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; self.calculate_sp_iters(num_sps_sub_slot) From 19ca4233518f47bcfb50246f4d8a444ef637f677 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 15:46:13 +0000 Subject: [PATCH 05/28] black tests --- tests/test_blscache.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_blscache.py b/tests/test_blscache.py index d16e5d13c..edd8f2450 100644 --- a/tests/test_blscache.py +++ b/tests/test_blscache.py @@ -297,11 +297,7 @@ def test_validate_clvm_and_sig(): ) sig = AugSchemeMPL.sign( sk, - ( - b'hello' - + coin.name() - + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA - ), # noqa + (b"hello" + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), # noqa ) new_spend = SpendBundle(coin_spends, sig) From 264058d762d2c9b808df8baf20644b88b9c65741 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 17 Jan 2025 16:08:13 +0000 Subject: [PATCH 06/28] import PyValueError at top of file --- crates/chia-protocol/src/block_record.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index c9eea8528..439a16c9d 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,5 +1,6 @@ use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; use chia_streamable_macro::streamable; +use pyo3::exceptions::PyValueError; #[cfg(feature = "py-bindings")] use pyo3::prelude::*; @@ -109,9 +110,6 @@ impl BlockRecord { } } -#[cfg(feature = "py-bindings")] -use pyo3::exceptions::PyValueError; - #[cfg(feature = "py-bindings")] use chia_traits::ChiaToPython; From 719b8a2255627a41800ab369ae1754e0ea27af76 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 10:58:17 +0000 Subject: [PATCH 07/28] add pot_iterations and pos_quality modules; refactor block_record to use new functions --- crates/chia-consensus/src/lib.rs | 2 + crates/chia-consensus/src/pos_quality.rs | 17 ++++ crates/chia-consensus/src/pot_iterations.rs | 91 +++++++++++++++++++++ crates/chia-protocol/src/block_record.rs | 85 +++++++++---------- tests/test_block_record_fidelity.py | 11 ++- 5 files changed, 163 insertions(+), 43 deletions(-) create mode 100644 crates/chia-consensus/src/pos_quality.rs create mode 100644 crates/chia-consensus/src/pot_iterations.rs diff --git a/crates/chia-consensus/src/lib.rs b/crates/chia-consensus/src/lib.rs index 141d777c6..3a002dde6 100644 --- a/crates/chia-consensus/src/lib.rs +++ b/crates/chia-consensus/src/lib.rs @@ -11,3 +11,5 @@ pub mod merkle_set; pub mod merkle_tree; pub mod spendbundle_conditions; pub mod spendbundle_validation; +pub mod pot_iterations; +pub mod pos_quality; \ No newline at end of file diff --git a/crates/chia-consensus/src/pos_quality.rs b/crates/chia-consensus/src/pos_quality.rs new file mode 100644 index 000000000..4d72203ba --- /dev/null +++ b/crates/chia-consensus/src/pos_quality.rs @@ -0,0 +1,17 @@ +// The actual space in bytes of a plot, is _expected_plot_size(k) * UI_ACTUAL_SPACE_CONSTANT_FACTO +// This is not used in consensus, only for display purposes + +pub const UI_ACTUAL_SPACE_CONSTANT_FACTOR: f32 = 0.78; + +// TODO: Update this when new plot format releases +pub fn expected_plot_size(k: u32) -> u64 { + // """ + // Given the plot size parameter k (which is between 32 and 59), computes the + // expected size of the plot in bytes (times a constant factor). This is based on efficient encoding + // of the plot, and aims to be scale agnostic, so larger plots don't + // necessarily get more rewards per byte. The +1 is added to give half a bit more space per entry, which + // is necessary to store the entries in the plot. + // """ + + ((2 * k as u64 + 1) * (1_u64 << (k - 1))) +} \ No newline at end of file diff --git a/crates/chia-consensus/src/pot_iterations.rs b/crates/chia-consensus/src/pot_iterations.rs new file mode 100644 index 000000000..3b58655a4 --- /dev/null +++ b/crates/chia-consensus/src/pot_iterations.rs @@ -0,0 +1,91 @@ + +use chia_protocol::Bytes32; +use chia_sha2::Sha256; +use std::convert::TryInto; +use crate::pos_quality::expected_plot_size; + + +#[cfg(feature = "py-bindings")] +#[pyo3::pyfunction] +pub fn is_overflow_block(num_sps_sub_slot: u32, num_sp_intervals_extra: u8, signage_point_index: u8) -> pyo3::PyResult { + if signage_point_index as u32 >= num_sps_sub_slot { + return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); + } else { + return Ok(signage_point_index as u32 >= num_sps_sub_slot - num_sp_intervals_extra as u32) + } +} + +#[cfg(feature = "py-bindings")] +#[pyo3::pyfunction] +pub fn calculate_sp_interval_iters(num_sps_sub_slot: u32, sub_slot_iters: u64) -> pyo3::PyResult { + if sub_slot_iters % num_sps_sub_slot as u64 == 0 { + return Err(pyo3::exceptions::PyValueError::new_err("ssi % num_sps_sub_slot == 0")); + } + Ok(sub_slot_iters / num_sps_sub_slot as u64) +} + +#[cfg(feature = "py-bindings")] +#[pyo3::pyfunction] +pub fn calculate_sp_iters(num_sps_sub_slot: u32, signage_point_index: u8, sub_slot_iters: u64) -> pyo3::PyResult { + if signage_point_index as u32 >= num_sps_sub_slot { + return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); + } + Ok(calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)? * signage_point_index as u64) +} + +#[cfg(feature = "py-bindings")] +#[pyo3::pyfunction] +pub fn calculate_ip_iters( + num_sps_sub_slot: u32, + signage_point_index: u8, + num_sp_intervals_extra: u8, + sub_slot_iters: u64, + required_iters: u64, +) -> pyo3::PyResult { + let sp_interval_iters = calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)?; + let sp_iters = calculate_sp_iters(num_sps_sub_slot, signage_point_index, sub_slot_iters)?; + if sp_iters % sp_interval_iters != 0 || sp_iters > sub_slot_iters { + return Err(pyo3::exceptions::PyValueError::new_err(format!( + "Invalid sp iters {sp_iters} for this ssi {sub_slot_iters}", + ))); + } else if required_iters >= sp_interval_iters || required_iters == 0 { + return Err(pyo3::exceptions::PyValueError::new_err(format!( + "Required iters {} is not below the sp interval iters {} {} or not >=0", + required_iters, sp_interval_iters, sub_slot_iters + ))); + } + Ok( + (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + required_iters) + % sub_slot_iters, + ) +} + +// TODO: enable and fix below + +// #[cfg(feature = "py-bindings")] +// #[pyo3::pyfunction] +// pub fn calculate_iterations_quality( +// difficulty_constant_factor: u128, +// quality_string: Bytes32, +// size: u32, +// difficulty: u64, +// cc_sp_output_hash: Bytes32, +// ) -> pyo3::PyResult { +// // Hash the concatenation of `quality_string` and `cc_sp_output_hash` +// let mut hasher = Sha256::new(); +// hasher.update(quality_string); +// hasher.update(cc_sp_output_hash); +// let sp_quality_string = hasher.finalize(); + +// // Convert the hash bytes to a big-endian u128 integer +// let sp_quality_value = u128::from_be_bytes(sp_quality_string[..16]); + +// // Expected plot size calculation function +// let plot_size = expected_plot_size(size); + +// // Calculate the number of iterations +// let iters = (difficulty as u128 * difficulty_constant_factor * sp_quality_value) +// / ((1_u128 << 256) * plot_size as u128); + +// Ok(iters.max(1) as u64) +// } \ No newline at end of file diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index 439a16c9d..c5e2774f3 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,5 +1,6 @@ use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; use chia_streamable_macro::streamable; +use chia_consensus::pot_iterations::{calculate_sp_iters, calculate_ip_iters}; use pyo3::exceptions::PyValueError; #[cfg(feature = "py-bindings")] @@ -68,46 +69,46 @@ impl BlockRecord { self.deficit == min_blocks_per_challenge_block - 1 } - fn calculate_sp_interval_iters(&self, num_sps_sub_slot: u64) -> PyResult { - if self.sub_slot_iters % num_sps_sub_slot != 0 { - return Err(PyValueError::new_err( - "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", - )); - } - Ok(self.sub_slot_iters / num_sps_sub_slot) - } - - fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { - if self.signage_point_index as u32 >= num_sps_sub_slot { - return Err(PyValueError::new_err("SP index too high")); - } - Ok(self.calculate_sp_interval_iters(num_sps_sub_slot as u64)? - * self.signage_point_index as u64) - } - - fn calculate_ip_iters( - &self, - num_sps_sub_slot: u32, - num_sp_intervals_extra: u8, - ) -> PyResult { - let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; - let sp_interval_iters = self.calculate_sp_interval_iters(num_sps_sub_slot as u64)?; - if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { - return Err(PyValueError::new_err(format!( - "Invalid sp iters {sp_iters} for this ssi {}", - self.sub_slot_iters - ))); - } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { - return Err(PyValueError::new_err(format!( - "Required iters {} is not below the sp interval iters {} {} or not >=0", - self.required_iters, sp_interval_iters, self.sub_slot_iters - ))); - } - Ok( - (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + self.required_iters) - % self.sub_slot_iters, - ) - } + // fn calculate_sp_interval_iters(&self, num_sps_sub_slot: u64) -> PyResult { + // if self.sub_slot_iters % num_sps_sub_slot != 0 { + // return Err(PyValueError::new_err( + // "sub_slot_iters % constants.NUM_SPS_SUB_SLOT != 0", + // )); + // } + // Ok(self.sub_slot_iters / num_sps_sub_slot) + // } + + // fn calculate_sp_iters(&self, num_sps_sub_slot: u32) -> PyResult { + // if self.signage_point_index as u32 >= num_sps_sub_slot { + // return Err(PyValueError::new_err("SP index too high")); + // } + // Ok(self.calculate_sp_interval_iters(num_sps_sub_slot as u64)? + // * self.signage_point_index as u64) + // } + + // fn calculate_ip_iters( + // &self, + // num_sps_sub_slot: u32, + // num_sp_intervals_extra: u8, + // ) -> PyResult { + // let sp_iters = self.calculate_sp_iters(num_sps_sub_slot)?; + // let sp_interval_iters = self.calculate_sp_interval_iters(num_sps_sub_slot as u64)?; + // if sp_iters % sp_interval_iters != 0 || sp_iters >= self.sub_slot_iters { + // return Err(PyValueError::new_err(format!( + // "Invalid sp iters {sp_iters} for this ssi {}", + // self.sub_slot_iters + // ))); + // } else if self.required_iters >= sp_interval_iters || self.required_iters == 0 { + // return Err(PyValueError::new_err(format!( + // "Required iters {} is not below the sp interval iters {} {} or not >=0", + // self.required_iters, sp_interval_iters, self.sub_slot_iters + // ))); + // } + // Ok( + // (sp_iters + num_sp_intervals_extra as u64 * sp_interval_iters + self.required_iters) + // % self.sub_slot_iters, + // ) + // } } #[cfg(feature = "py-bindings")] @@ -159,7 +160,7 @@ impl BlockRecord { fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; - self.calculate_sp_iters(num_sps_sub_slot) + calculate_sp_iters(num_sps_sub_slot, self.signage_point_index, self.sub_slot_iters) } fn ip_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { @@ -167,7 +168,7 @@ impl BlockRecord { let num_sp_intervals_extra = constants .get_item("NUM_SP_INTERVALS_EXTRA")? .extract::()?; - self.calculate_ip_iters(num_sps_sub_slot, num_sp_intervals_extra) + calculate_ip_iters(num_sps_sub_slot, self.signage_point_index, num_sp_intervals_extra, self.sub_slot_iters, self.required_iters) } fn sp_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index e37ec5ef2..36c17a508 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -1,5 +1,5 @@ from typing import Optional, Any, Callable - +from pytest import raises import sys import time from chia_rs import BlockRecord, ClassgroupElement @@ -129,3 +129,12 @@ def wrap_call(expr: str, br: Any) -> str: return f"V:{ret}" except Exception as e: return f"E:{e}" + +def test_calculate_sp_iters(): + ssi: uint64 = uint64(100001 * 64 * 4) + rng = Random() + rng.seed(1337) + br = get_block_record(rng) + with raises(ValueError): + br.sp_iters_impl(DEFAULT_CONSTANTS) + br.sp_iters_impl(DEFAULT_CONSTANTS) From 74a700e9f57921f80b1cb5b12547d75166923865 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 11:06:12 +0000 Subject: [PATCH 08/28] fix circular import --- crates/chia-consensus/src/lib.rs | 4 +--- crates/chia-protocol/src/block_record.rs | 2 +- crates/chia-protocol/src/lib.rs | 4 ++++ .../{chia-consensus => chia-protocol}/src/pos_quality.rs | 0 .../src/pot_iterations.rs | 8 ++++---- 5 files changed, 10 insertions(+), 8 deletions(-) rename crates/{chia-consensus => chia-protocol}/src/pos_quality.rs (100%) rename crates/{chia-consensus => chia-protocol}/src/pot_iterations.rs (96%) diff --git a/crates/chia-consensus/src/lib.rs b/crates/chia-consensus/src/lib.rs index 3a002dde6..a990832bb 100644 --- a/crates/chia-consensus/src/lib.rs +++ b/crates/chia-consensus/src/lib.rs @@ -10,6 +10,4 @@ pub mod generator_rom; pub mod merkle_set; pub mod merkle_tree; pub mod spendbundle_conditions; -pub mod spendbundle_validation; -pub mod pot_iterations; -pub mod pos_quality; \ No newline at end of file +pub mod spendbundle_validation; \ No newline at end of file diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index c5e2774f3..d111a559d 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,6 +1,6 @@ use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; use chia_streamable_macro::streamable; -use chia_consensus::pot_iterations::{calculate_sp_iters, calculate_ip_iters}; +use crate::pot_iterations::{calculate_sp_iters, calculate_ip_iters}; use pyo3::exceptions::PyValueError; #[cfg(feature = "py-bindings")] diff --git a/crates/chia-protocol/src/lib.rs b/crates/chia-protocol/src/lib.rs index 544979383..dbb077337 100644 --- a/crates/chia-protocol/src/lib.rs +++ b/crates/chia-protocol/src/lib.rs @@ -24,6 +24,8 @@ mod unfinished_header_block; mod vdf; mod wallet_protocol; mod weight_proof; +mod pot_iterations; +mod pos_quality; #[cfg(feature = "py-bindings")] mod lazy_node; @@ -55,6 +57,8 @@ pub use crate::unfinished_header_block::*; pub use crate::vdf::*; pub use crate::wallet_protocol::*; pub use crate::weight_proof::*; +pub use crate::pot_iterations::*; +pub use crate::pos_quality::*; #[cfg(feature = "py-bindings")] pub use crate::lazy_node::*; diff --git a/crates/chia-consensus/src/pos_quality.rs b/crates/chia-protocol/src/pos_quality.rs similarity index 100% rename from crates/chia-consensus/src/pos_quality.rs rename to crates/chia-protocol/src/pos_quality.rs diff --git a/crates/chia-consensus/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs similarity index 96% rename from crates/chia-consensus/src/pot_iterations.rs rename to crates/chia-protocol/src/pot_iterations.rs index 3b58655a4..65149bb61 100644 --- a/crates/chia-consensus/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -1,8 +1,8 @@ -use chia_protocol::Bytes32; -use chia_sha2::Sha256; -use std::convert::TryInto; -use crate::pos_quality::expected_plot_size; +// use crate::Bytes32; +// use chia_sha2::Sha256; +// use std::convert::TryInto; +// use crate::pos_quality::expected_plot_size; #[cfg(feature = "py-bindings")] From ef8c93609b5cab084305ac357cce990e76674174 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 13:55:33 +0000 Subject: [PATCH 09/28] temp commit --- crates/chia-protocol/src/pos_quality.rs | 6 ++++-- crates/chia-protocol/src/pot_iterations.rs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/chia-protocol/src/pos_quality.rs b/crates/chia-protocol/src/pos_quality.rs index 4d72203ba..9741f110f 100644 --- a/crates/chia-protocol/src/pos_quality.rs +++ b/crates/chia-protocol/src/pos_quality.rs @@ -4,7 +4,9 @@ pub const UI_ACTUAL_SPACE_CONSTANT_FACTOR: f32 = 0.78; // TODO: Update this when new plot format releases -pub fn expected_plot_size(k: u32) -> u64 { +#[cfg(feature = "py-bindings")] +#[pyo3::pyfunction] +pub fn expected_plot_size(k: u32) -> pyo3::PyResult { // """ // Given the plot size parameter k (which is between 32 and 59), computes the // expected size of the plot in bytes (times a constant factor). This is based on efficient encoding @@ -13,5 +15,5 @@ pub fn expected_plot_size(k: u32) -> u64 { // is necessary to store the entries in the plot. // """ - ((2 * k as u64 + 1) * (1_u64 << (k - 1))) + Ok((2 * k as u64 + 1) * (1_u64 << (k - 1))) } \ No newline at end of file diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 65149bb61..45f479850 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -4,7 +4,6 @@ // use std::convert::TryInto; // use crate::pos_quality::expected_plot_size; - #[cfg(feature = "py-bindings")] #[pyo3::pyfunction] pub fn is_overflow_block(num_sps_sub_slot: u32, num_sp_intervals_extra: u8, signage_point_index: u8) -> pyo3::PyResult { From 06cdaadc2948873ff3ca6b05c03d440ffbe03c54 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 14:16:23 +0000 Subject: [PATCH 10/28] fix build with py-bindings --- crates/chia-protocol/src/block_record.rs | 2 ++ crates/chia-protocol/src/lib.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index d111a559d..4446d941e 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,6 +1,8 @@ use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; use chia_streamable_macro::streamable; +#[cfg(feature = "py-bindings")] use crate::pot_iterations::{calculate_sp_iters, calculate_ip_iters}; +#[cfg(feature = "py-bindings")] use pyo3::exceptions::PyValueError; #[cfg(feature = "py-bindings")] diff --git a/crates/chia-protocol/src/lib.rs b/crates/chia-protocol/src/lib.rs index dbb077337..414944a21 100644 --- a/crates/chia-protocol/src/lib.rs +++ b/crates/chia-protocol/src/lib.rs @@ -24,7 +24,9 @@ mod unfinished_header_block; mod vdf; mod wallet_protocol; mod weight_proof; +#[cfg(feature = "py-bindings")] mod pot_iterations; +#[cfg(feature = "py-bindings")] mod pos_quality; #[cfg(feature = "py-bindings")] @@ -57,7 +59,9 @@ pub use crate::unfinished_header_block::*; pub use crate::vdf::*; pub use crate::wallet_protocol::*; pub use crate::weight_proof::*; +#[cfg(feature = "py-bindings")] pub use crate::pot_iterations::*; +#[cfg(feature = "py-bindings")] pub use crate::pos_quality::*; #[cfg(feature = "py-bindings")] From 2b9d0f7b878e637f9e90b782177382b3e30909b1 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 14:47:21 +0000 Subject: [PATCH 11/28] clippy and fmt --- crates/chia-consensus/src/lib.rs | 2 +- crates/chia-protocol/src/block_record.rs | 18 +++++++++--- crates/chia-protocol/src/lib.rs | 16 +++++------ crates/chia-protocol/src/pos_quality.rs | 4 +-- crates/chia-protocol/src/pot_iterations.rs | 32 ++++++++++++++-------- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/crates/chia-consensus/src/lib.rs b/crates/chia-consensus/src/lib.rs index a990832bb..141d777c6 100644 --- a/crates/chia-consensus/src/lib.rs +++ b/crates/chia-consensus/src/lib.rs @@ -10,4 +10,4 @@ pub mod generator_rom; pub mod merkle_set; pub mod merkle_tree; pub mod spendbundle_conditions; -pub mod spendbundle_validation; \ No newline at end of file +pub mod spendbundle_validation; diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index 4446d941e..25d1f1de6 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -1,8 +1,8 @@ +#[cfg(feature = "py-bindings")] +use crate::pot_iterations::{calculate_ip_iters, calculate_sp_iters}; use crate::{Bytes32, ClassgroupElement, Coin, SubEpochSummary}; use chia_streamable_macro::streamable; #[cfg(feature = "py-bindings")] -use crate::pot_iterations::{calculate_sp_iters, calculate_ip_iters}; -#[cfg(feature = "py-bindings")] use pyo3::exceptions::PyValueError; #[cfg(feature = "py-bindings")] @@ -162,7 +162,11 @@ impl BlockRecord { fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; - calculate_sp_iters(num_sps_sub_slot, self.signage_point_index, self.sub_slot_iters) + calculate_sp_iters( + num_sps_sub_slot, + self.signage_point_index, + self.sub_slot_iters, + ) } fn ip_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { @@ -170,7 +174,13 @@ impl BlockRecord { let num_sp_intervals_extra = constants .get_item("NUM_SP_INTERVALS_EXTRA")? .extract::()?; - calculate_ip_iters(num_sps_sub_slot, self.signage_point_index, num_sp_intervals_extra, self.sub_slot_iters, self.required_iters) + calculate_ip_iters( + num_sps_sub_slot, + self.signage_point_index, + num_sp_intervals_extra, + self.sub_slot_iters, + self.required_iters, + ) } fn sp_total_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { diff --git a/crates/chia-protocol/src/lib.rs b/crates/chia-protocol/src/lib.rs index 414944a21..53d6a6c7a 100644 --- a/crates/chia-protocol/src/lib.rs +++ b/crates/chia-protocol/src/lib.rs @@ -13,6 +13,10 @@ mod fullblock; mod header_block; mod peer_info; mod pool_target; +#[cfg(feature = "py-bindings")] +mod pos_quality; +#[cfg(feature = "py-bindings")] +mod pot_iterations; mod program; mod proof_of_space; mod reward_chain_block; @@ -24,10 +28,6 @@ mod unfinished_header_block; mod vdf; mod wallet_protocol; mod weight_proof; -#[cfg(feature = "py-bindings")] -mod pot_iterations; -#[cfg(feature = "py-bindings")] -mod pos_quality; #[cfg(feature = "py-bindings")] mod lazy_node; @@ -48,6 +48,10 @@ pub use crate::fullblock::*; pub use crate::header_block::*; pub use crate::peer_info::*; pub use crate::pool_target::*; +#[cfg(feature = "py-bindings")] +pub use crate::pos_quality::*; +#[cfg(feature = "py-bindings")] +pub use crate::pot_iterations::*; pub use crate::program::*; pub use crate::proof_of_space::*; pub use crate::reward_chain_block::*; @@ -59,10 +63,6 @@ pub use crate::unfinished_header_block::*; pub use crate::vdf::*; pub use crate::wallet_protocol::*; pub use crate::weight_proof::*; -#[cfg(feature = "py-bindings")] -pub use crate::pot_iterations::*; -#[cfg(feature = "py-bindings")] -pub use crate::pos_quality::*; #[cfg(feature = "py-bindings")] pub use crate::lazy_node::*; diff --git a/crates/chia-protocol/src/pos_quality.rs b/crates/chia-protocol/src/pos_quality.rs index 9741f110f..ae13f1eac 100644 --- a/crates/chia-protocol/src/pos_quality.rs +++ b/crates/chia-protocol/src/pos_quality.rs @@ -14,6 +14,6 @@ pub fn expected_plot_size(k: u32) -> pyo3::PyResult { // necessarily get more rewards per byte. The +1 is added to give half a bit more space per entry, which // is necessary to store the entries in the plot. // """ - + Ok((2 * k as u64 + 1) * (1_u64 << (k - 1))) -} \ No newline at end of file +} diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 45f479850..89db7b399 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -1,4 +1,3 @@ - // use crate::Bytes32; // use chia_sha2::Sha256; // use std::convert::TryInto; @@ -6,26 +5,38 @@ #[cfg(feature = "py-bindings")] #[pyo3::pyfunction] -pub fn is_overflow_block(num_sps_sub_slot: u32, num_sp_intervals_extra: u8, signage_point_index: u8) -> pyo3::PyResult { +pub fn is_overflow_block( + num_sps_sub_slot: u32, + num_sp_intervals_extra: u8, + signage_point_index: u8, +) -> pyo3::PyResult { if signage_point_index as u32 >= num_sps_sub_slot { return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); - } else { - return Ok(signage_point_index as u32 >= num_sps_sub_slot - num_sp_intervals_extra as u32) } + Ok(signage_point_index as u32 >= num_sps_sub_slot - num_sp_intervals_extra as u32) } #[cfg(feature = "py-bindings")] #[pyo3::pyfunction] -pub fn calculate_sp_interval_iters(num_sps_sub_slot: u32, sub_slot_iters: u64) -> pyo3::PyResult { +pub fn calculate_sp_interval_iters( + num_sps_sub_slot: u32, + sub_slot_iters: u64, +) -> pyo3::PyResult { if sub_slot_iters % num_sps_sub_slot as u64 == 0 { - return Err(pyo3::exceptions::PyValueError::new_err("ssi % num_sps_sub_slot == 0")); + return Err(pyo3::exceptions::PyValueError::new_err( + "ssi % num_sps_sub_slot == 0", + )); } Ok(sub_slot_iters / num_sps_sub_slot as u64) } #[cfg(feature = "py-bindings")] #[pyo3::pyfunction] -pub fn calculate_sp_iters(num_sps_sub_slot: u32, signage_point_index: u8, sub_slot_iters: u64) -> pyo3::PyResult { +pub fn calculate_sp_iters( + num_sps_sub_slot: u32, + signage_point_index: u8, + sub_slot_iters: u64, +) -> pyo3::PyResult { if signage_point_index as u32 >= num_sps_sub_slot { return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); } @@ -49,8 +60,7 @@ pub fn calculate_ip_iters( ))); } else if required_iters >= sp_interval_iters || required_iters == 0 { return Err(pyo3::exceptions::PyValueError::new_err(format!( - "Required iters {} is not below the sp interval iters {} {} or not >=0", - required_iters, sp_interval_iters, sub_slot_iters + "Required iters {required_iters} is not below the sp interval iters {sp_interval_iters} {sub_slot_iters} or not >=0", ))); } Ok( @@ -75,7 +85,7 @@ pub fn calculate_ip_iters( // hasher.update(quality_string); // hasher.update(cc_sp_output_hash); // let sp_quality_string = hasher.finalize(); - + // // Convert the hash bytes to a big-endian u128 integer // let sp_quality_value = u128::from_be_bytes(sp_quality_string[..16]); @@ -87,4 +97,4 @@ pub fn calculate_ip_iters( // / ((1_u128 << 256) * plot_size as u128); // Ok(iters.max(1) as u64) -// } \ No newline at end of file +// } From 242c993a8f684d4b1cc20217c6be04790a879858 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 22 Jan 2025 14:53:32 +0000 Subject: [PATCH 12/28] black format test --- tests/test_block_record_fidelity.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index 36c17a508..bcc80a88b 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -129,12 +129,13 @@ def wrap_call(expr: str, br: Any) -> str: return f"V:{ret}" except Exception as e: return f"E:{e}" - + + def test_calculate_sp_iters(): - ssi: uint64 = uint64(100001 * 64 * 4) - rng = Random() - rng.seed(1337) - br = get_block_record(rng) - with raises(ValueError): - br.sp_iters_impl(DEFAULT_CONSTANTS) + ssi: uint64 = uint64(100001 * 64 * 4) + rng = Random() + rng.seed(1337) + br = get_block_record(rng) + with raises(ValueError): br.sp_iters_impl(DEFAULT_CONSTANTS) + br.sp_iters_impl(DEFAULT_CONSTANTS) From b8c03057bb4796e16fdb583454737febc9cd0b10 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Thu, 23 Jan 2025 17:12:25 +0000 Subject: [PATCH 13/28] fix fetching rust values from python --- crates/chia-protocol/src/block_record.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index 25d1f1de6..d18962359 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -161,7 +161,7 @@ impl BlockRecord { } fn sp_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { - let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; + let num_sps_sub_slot = constants.getattr("NUM_SPS_SUB_SLOT")?.extract::()?; calculate_sp_iters( num_sps_sub_slot, self.signage_point_index, @@ -170,9 +170,9 @@ impl BlockRecord { } fn ip_iters_impl(&self, constants: &Bound<'_, PyAny>) -> PyResult { - let num_sps_sub_slot = constants.get_item("NUM_SPS_SUB_SLOT")?.extract::()?; + let num_sps_sub_slot = constants.getattr("NUM_SPS_SUB_SLOT")?.extract::()?; let num_sp_intervals_extra = constants - .get_item("NUM_SP_INTERVALS_EXTRA")? + .getattr("NUM_SP_INTERVALS_EXTRA")? .extract::()?; calculate_ip_iters( num_sps_sub_slot, From 7d38538e53cf7e032386cf25624ffd12f1a87a31 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 24 Jan 2025 13:00:54 +0000 Subject: [PATCH 14/28] tests run but overflow --- crates/chia-protocol/src/pot_iterations.rs | 6 +- tests/test_block_record_fidelity.py | 7 +- tests/test_pot_iterations.py | 125 +++++++++++++++++++++ wheel/src/api.rs | 9 ++ 4 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 tests/test_pot_iterations.py diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 89db7b399..a67ab600c 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -34,8 +34,8 @@ pub fn calculate_sp_interval_iters( #[pyo3::pyfunction] pub fn calculate_sp_iters( num_sps_sub_slot: u32, - signage_point_index: u8, sub_slot_iters: u64, + signage_point_index: u8, ) -> pyo3::PyResult { if signage_point_index as u32 >= num_sps_sub_slot { return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); @@ -47,13 +47,13 @@ pub fn calculate_sp_iters( #[pyo3::pyfunction] pub fn calculate_ip_iters( num_sps_sub_slot: u32, - signage_point_index: u8, num_sp_intervals_extra: u8, sub_slot_iters: u64, + signage_point_index: u8, required_iters: u64, ) -> pyo3::PyResult { let sp_interval_iters = calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)?; - let sp_iters = calculate_sp_iters(num_sps_sub_slot, signage_point_index, sub_slot_iters)?; + let sp_iters = calculate_sp_iters(num_sps_sub_slot, sub_slot_iters, signage_point_index)?; if sp_iters % sp_interval_iters != 0 || sp_iters > sub_slot_iters { return Err(pyo3::exceptions::PyValueError::new_err(format!( "Invalid sp iters {sp_iters} for this ssi {sub_slot_iters}", diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index bcc80a88b..0b69dcf78 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -130,12 +130,11 @@ def wrap_call(expr: str, br: Any) -> str: except Exception as e: return f"E:{e}" - +# TODO: more thoroughly check these new functions which use self def test_calculate_sp_iters(): ssi: uint64 = uint64(100001 * 64 * 4) rng = Random() rng.seed(1337) br = get_block_record(rng) - with raises(ValueError): - br.sp_iters_impl(DEFAULT_CONSTANTS) - br.sp_iters_impl(DEFAULT_CONSTANTS) + res = br.sp_iters_impl(DEFAULT_CONSTANTS) + diff --git a/tests/test_pot_iterations.py b/tests/test_pot_iterations.py new file mode 100644 index 000000000..1b6f01610 --- /dev/null +++ b/tests/test_pot_iterations.py @@ -0,0 +1,125 @@ +from __future__ import annotations + +from pytest import raises + +from run_gen import DEFAULT_CONSTANTS +# from chia.consensus.pos_quality import _expected_plot_size +from chia_rs import ( + calculate_ip_iters, + # calculate_iterations_quality, + calculate_sp_iters, + is_overflow_block, +) +# from chia.util.hash import std_hash +from chia_rs.sized_ints import uint8, uint16, uint32, uint64 #, uint128 + +test_constants = DEFAULT_CONSTANTS.replace(NUM_SPS_SUB_SLOT=uint32(32), SUB_SLOT_TIME_TARGET=uint16(300)) + + +class TestPotIterations: + def test_is_overflow_block(self): + assert not is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(27)) + assert not is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(28)) + assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(29)) + assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(30)) + assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(31)) + with raises(ValueError): + assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(32)) + + def test_calculate_sp_iters(self): + ssi: uint64 = uint64(100001 * 64 * 4) + with raises(ValueError): + calculate_sp_iters(test_constants.NUM_SPS_SUB_SLOT, ssi, uint8(32)) + calculate_sp_iters(test_constants.NUM_SPS_SUB_SLOT, ssi, uint8(31)) + + def test_calculate_ip_iters(self): + # num_sps_sub_slot: u32, + # num_sp_intervals_extra: u8, + # sub_slot_iters: u64, + # signage_point_index: u8, + # required_iters: u64, + ssi: uint64 = uint64(100001 * 64 * 4) + sp_interval_iters = ssi // test_constants.NUM_SPS_SUB_SLOT + + with raises(ValueError): + # Invalid signage point index + calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(123), uint64(100000) + ) + + sp_iters = sp_interval_iters * 13 + + with raises(ValueError): + # required_iters too high + calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, sp_interval_iters) + + with raises(ValueError): + # required_iters too high + calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, sp_interval_iters * 12) + + with raises(ValueError): + # required_iters too low (0) + calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, uint64(0)) + + required_iters = sp_interval_iters - 1 + ip_iters = calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(13), required_iters) + assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + + required_iters = uint64(1) + ip_iters = calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(13), required_iters) + assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + + required_iters = uint64(int(ssi * 4 / 300)) + ip_iters = calculate_ip_iters(test_constants, ssi, uint8(13), required_iters) + assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + assert sp_iters < ip_iters + + # Overflow + sp_iters = sp_interval_iters * (test_constants.NUM_SPS_SUB_SLOT - 1) + ip_iters = calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + uint8(test_constants.NUM_SPS_SUB_SLOT - 1), + required_iters, + ) + assert ip_iters == (sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters) % ssi + assert sp_iters > ip_iters + + # def test_win_percentage(self): + # """ + # Tests that the percentage of blocks won is proportional to the space of each farmer, + # with the assumption that all farmers have access to the same VDF speed. + # """ + # farmer_ks = { + # uint8(32): 100, + # uint8(33): 100, + # uint8(34): 100, + # uint8(35): 100, + # uint8(36): 100, + # } + # farmer_space = {k: _expected_plot_size(uint8(k)) * count for k, count in farmer_ks.items()} + # total_space = sum(farmer_space.values()) + # percentage_space = {k: float(sp / total_space) for k, sp in farmer_space.items()} + # wins = {k: 0 for k in farmer_ks.keys()} + # total_slots = 50 + # num_sps = 16 + # sp_interval_iters = uint64(100000000 // 32) + # difficulty = uint64(500000000000) + + # for slot_index in range(total_slots): + # total_wins_in_slot = 0 + # for sp_index in range(num_sps): + # sp_hash = std_hash(slot_index.to_bytes(4, "big") + sp_index.to_bytes(4, "big")) + # for k, count in farmer_ks.items(): + # for farmer_index in range(count): + # quality = std_hash(slot_index.to_bytes(4, "big") + k.to_bytes(1, "big") + bytes(farmer_index)) + # required_iters = calculate_iterations_quality(uint128(2**25), quality, k, difficulty, sp_hash) + # if required_iters < sp_interval_iters: + # wins[k] += 1 + # total_wins_in_slot += 1 + + # win_percentage = {k: wins[k] / sum(wins.values()) for k in farmer_ks.keys()} + # for k in farmer_ks.keys(): + # # Win rate is proportional to percentage of space + # assert abs(win_percentage[k] - percentage_space[k]) < 0.01 diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 70b2c5916..2266c1ac9 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -44,6 +44,9 @@ use chia_protocol::{ SubSlotProofs, TimestampedPeerInfo, TransactionAck, TransactionsInfo, UnfinishedBlock, UnfinishedHeaderBlock, VDFInfo, VDFProof, WeightProof, }; +use chia_protocol::{ + calculate_ip_iters, calculate_sp_interval_iters, is_overflow_block, calculate_sp_iters +}; use chia_traits::ChiaToPython; use clvm_utils::tree_hash_from_bytes; use clvmr::chia_dialect::{ENABLE_KECCAK, ENABLE_KECCAK_OPS_OUTSIDE_GUARD}; @@ -458,6 +461,12 @@ pub fn chia_rs(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { )?; m.add_class::()?; + // pot functions + m.add_function(wrap_pyfunction!(calculate_sp_interval_iters, m)?)?; + m.add_function(wrap_pyfunction!(calculate_sp_iters, m)?)?; + m.add_function(wrap_pyfunction!(calculate_ip_iters, m)?)?; + m.add_function(wrap_pyfunction!(is_overflow_block, m)?)?; + // constants m.add_class::()?; From 2bb5c1ec2a64e4c6fa092845e8f19143f891000e Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 24 Jan 2025 14:11:40 +0000 Subject: [PATCH 15/28] correct order of blockrecord args --- crates/chia-protocol/src/block_record.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index d18962359..a430c7744 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -164,8 +164,8 @@ impl BlockRecord { let num_sps_sub_slot = constants.getattr("NUM_SPS_SUB_SLOT")?.extract::()?; calculate_sp_iters( num_sps_sub_slot, - self.signage_point_index, self.sub_slot_iters, + self.signage_point_index, ) } @@ -176,9 +176,9 @@ impl BlockRecord { .extract::()?; calculate_ip_iters( num_sps_sub_slot, - self.signage_point_index, num_sp_intervals_extra, self.sub_slot_iters, + self.signage_point_index, self.required_iters, ) } From 31bdbc706e33a5f7d13498e63c40b645a635ff19 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 24 Jan 2025 15:54:57 +0000 Subject: [PATCH 16/28] add tests to pot_iterations.rs --- crates/chia-protocol/src/pot_iterations.rs | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index a67ab600c..16b8e6dfc 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -69,6 +69,107 @@ pub fn calculate_ip_iters( ) } +#[cfg(test)] +mod tests { + use super::*; + static NUM_SPS_SUB_SLOT: u32 = 32; + static NUM_SPS_SUB_SLOT_U8: u8 = 32; + static NUM_SP_INTERVALS_EXTRA: u8 = 3; + + #[test] + fn test_is_overflow_block() { + assert!(!is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 27).expect("valid SP index")); + assert!(!is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 28).expect("valid SP index")); + assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 29).expect("valid SP index")); + assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 30).expect("valid SP index")); + assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 31).expect("valid SP index")); + assert!(matches!( + is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 32), + Err(_) + )); + } + + #[test] + fn test_calculate_sp_iters() { + let ssi: u64 = 100001 * 64 * 4; + assert!(matches!( + calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 32), + Err(_) + )); + calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 31).expect("valid_result"); + } + + #[test] + fn test_calculate_ip_iters(){ + // # num_sps_sub_slot: u32, + // # num_sp_intervals_extra: u8, + // # sub_slot_iters: u64, + // # signage_point_index: u8, + // # required_iters: u64, + let ssi: u64 = 100001 * 64 * 4; + let sp_interval_iters = ssi / NUM_SPS_SUB_SLOT as u64; + + // Invalid signage point index + assert!(matches!( + calculate_ip_iters( + NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100000 + ), + Err(_) + )); + + let sp_iters = sp_interval_iters * 13; + + // required_iters too high + assert!(matches!( + calculate_ip_iters( + NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters + ), + Err(_) + )); + + // required_iters too high + assert!(matches!( + calculate_ip_iters( + NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters * 12 + ), + Err(_) + )); + + // required_iters too low (0) + assert!(matches!( + calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), 0), + Err(_) + )); + + let required_iters = sp_interval_iters - 1; + let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("should be valid"); + assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + + let required_iters = 1_u64; + let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("valid"); + assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + + let required_iters: u64 = ssi * 4 / 300; + let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("valid"); + assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + assert!(sp_iters < ip_iters); + + // Overflow + let sp_iters = sp_interval_iters * (NUM_SPS_SUB_SLOT - 1) as u64; + let ip_iters = calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + NUM_SPS_SUB_SLOT_U8 - 1_u8, + required_iters, + ).expect("valid"); + assert_eq!(ip_iters, (sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters) % ssi); + assert!(sp_iters > ip_iters) + } + + +} + // TODO: enable and fix below // #[cfg(feature = "py-bindings")] From a1e942506eda7753f4f7e0e98970d5ad4e920b0a Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 13:02:53 +0000 Subject: [PATCH 17/28] fix bug in implementation --- crates/chia-protocol/src/pot_iterations.rs | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 16b8e6dfc..94a43f002 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -22,7 +22,7 @@ pub fn calculate_sp_interval_iters( num_sps_sub_slot: u32, sub_slot_iters: u64, ) -> pyo3::PyResult { - if sub_slot_iters % num_sps_sub_slot as u64 == 0 { + if sub_slot_iters % num_sps_sub_slot as u64 != 0 { return Err(pyo3::exceptions::PyValueError::new_err( "ssi % num_sps_sub_slot == 0", )); @@ -120,26 +120,27 @@ mod tests { let sp_iters = sp_interval_iters * 13; // required_iters too high - assert!(matches!( - calculate_ip_iters( - NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters - ), - Err(_) - )); - - // required_iters too high - assert!(matches!( - calculate_ip_iters( - NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters * 12 - ), - Err(_) - )); - - // required_iters too low (0) - assert!(matches!( - calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), 0), - Err(_) - )); + // disabled this test as rusts typing enforces it already + // assert!(matches!( + // calculate_ip_iters( + // NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters + // ), + // Err(_) + // )); + + // // required_iters too high + // assert!(matches!( + // calculate_ip_iters( + // NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters * 12 + // ), + // Err(_) + // )); + + // // required_iters too low (0) + // assert!(matches!( + // calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), 0), + // Err(_) + // )); let required_iters = sp_interval_iters - 1; let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("should be valid"); From 6251c19e7fac97d26f9bdd6f7d1bbb701695f64d Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 13:31:08 +0000 Subject: [PATCH 18/28] fix python test --- crates/chia-protocol/src/pot_iterations.rs | 2 +- tests/test_block_record_fidelity.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 94a43f002..d97e5fc85 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -24,7 +24,7 @@ pub fn calculate_sp_interval_iters( ) -> pyo3::PyResult { if sub_slot_iters % num_sps_sub_slot as u64 != 0 { return Err(pyo3::exceptions::PyValueError::new_err( - "ssi % num_sps_sub_slot == 0", + "ssi % num_sps_sub_slot != 0", )); } Ok(sub_slot_iters / num_sps_sub_slot as u64) diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index 0b69dcf78..adbd76bc2 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -62,14 +62,14 @@ def get_hash(rng: Random) -> bytes32: return bytes32.random(rng) -def get_block_record(rng: Random) -> BlockRecord: +def get_block_record(rng: Random, ssi=None, ri=None, spi=None) -> BlockRecord: height = get_u32(rng) weight = get_u128(rng) iters = get_u128(rng) - sp_index = get_u4(rng) + sp_index = spi if spi is not None else get_u4(rng) vdf_out = get_classgroup_element(rng) infused_challenge = get_optional(rng, get_classgroup_element) - sub_slot_iters = get_ssi(rng) + sub_slot_iters = ssi if ssi is not None else get_ssi(rng) required_iters = get_u64(rng) deficit = get_u8(rng) overflow = get_bool(rng) @@ -135,6 +135,7 @@ def test_calculate_sp_iters(): ssi: uint64 = uint64(100001 * 64 * 4) rng = Random() rng.seed(1337) - br = get_block_record(rng) + br = get_block_record(rng, ssi=ssi, spi=31) res = br.sp_iters_impl(DEFAULT_CONSTANTS) + assert res is not None From 6645f85d003ef9f8b724d9ca5a778c90f84fc75c Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 13:33:39 +0000 Subject: [PATCH 19/28] fmt and black --- crates/chia-protocol/src/pot_iterations.rs | 85 +++++++++++++++++----- tests/test_block_record_fidelity.py | 2 +- wheel/src/api.rs | 6 +- 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index d97e5fc85..82a8003b4 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -78,11 +78,26 @@ mod tests { #[test] fn test_is_overflow_block() { - assert!(!is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 27).expect("valid SP index")); - assert!(!is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 28).expect("valid SP index")); - assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 29).expect("valid SP index")); - assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 30).expect("valid SP index")); - assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 31).expect("valid SP index")); + assert!( + !is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 27) + .expect("valid SP index") + ); + assert!( + !is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 28) + .expect("valid SP index") + ); + assert!( + is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 29) + .expect("valid SP index") + ); + assert!( + is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 30) + .expect("valid SP index") + ); + assert!( + is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 31) + .expect("valid SP index") + ); assert!(matches!( is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 32), Err(_) @@ -100,7 +115,7 @@ mod tests { } #[test] - fn test_calculate_ip_iters(){ + fn test_calculate_ip_iters() { // # num_sps_sub_slot: u32, // # num_sp_intervals_extra: u8, // # sub_slot_iters: u64, @@ -111,9 +126,7 @@ mod tests { // Invalid signage point index assert!(matches!( - calculate_ip_iters( - NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100000 - ), + calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100000), Err(_) )); @@ -143,32 +156,64 @@ mod tests { // )); let required_iters = sp_interval_iters - 1; - let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("should be valid"); - assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + let ip_iters = calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + 13, + required_iters, + ) + .expect("should be valid"); + assert_eq!( + ip_iters, + sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters + ); let required_iters = 1_u64; - let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("valid"); - assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + let ip_iters = calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + 13, + required_iters, + ) + .expect("valid"); + assert_eq!( + ip_iters, + sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters + ); let required_iters: u64 = ssi * 4 / 300; - let ip_iters = calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 13, required_iters).expect("valid"); - assert_eq!(ip_iters, sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters); + let ip_iters = calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + 13, + required_iters, + ) + .expect("valid"); + assert_eq!( + ip_iters, + sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters + ); assert!(sp_iters < ip_iters); // Overflow let sp_iters = sp_interval_iters * (NUM_SPS_SUB_SLOT - 1) as u64; let ip_iters = calculate_ip_iters( - NUM_SPS_SUB_SLOT, + NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, NUM_SPS_SUB_SLOT_U8 - 1_u8, required_iters, - ).expect("valid"); - assert_eq!(ip_iters, (sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters) % ssi); + ) + .expect("valid"); + assert_eq!( + ip_iters, + (sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters) % ssi + ); assert!(sp_iters > ip_iters) } - - } // TODO: enable and fix below diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index adbd76bc2..a56b353f5 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -130,6 +130,7 @@ def wrap_call(expr: str, br: Any) -> str: except Exception as e: return f"E:{e}" + # TODO: more thoroughly check these new functions which use self def test_calculate_sp_iters(): ssi: uint64 = uint64(100001 * 64 * 4) @@ -138,4 +139,3 @@ def test_calculate_sp_iters(): br = get_block_record(rng, ssi=ssi, spi=31) res = br.sp_iters_impl(DEFAULT_CONSTANTS) assert res is not None - diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 2266c1ac9..65540a621 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -16,6 +16,9 @@ use chia_consensus::spendbundle_conditions::get_conditions_from_spendbundle; use chia_consensus::spendbundle_validation::{ get_flags_for_height_and_constants, validate_clvm_and_signature, }; +use chia_protocol::{ + calculate_ip_iters, calculate_sp_interval_iters, calculate_sp_iters, is_overflow_block, +}; use chia_protocol::{ BlockRecord, Bytes32, ChallengeBlockInfo, ChallengeChainSubSlot, ClassgroupElement, Coin, CoinSpend, CoinState, CoinStateFilters, CoinStateUpdate, EndOfSubSlotBundle, FeeEstimate, @@ -44,9 +47,6 @@ use chia_protocol::{ SubSlotProofs, TimestampedPeerInfo, TransactionAck, TransactionsInfo, UnfinishedBlock, UnfinishedHeaderBlock, VDFInfo, VDFProof, WeightProof, }; -use chia_protocol::{ - calculate_ip_iters, calculate_sp_interval_iters, is_overflow_block, calculate_sp_iters -}; use chia_traits::ChiaToPython; use clvm_utils::tree_hash_from_bytes; use clvmr::chia_dialect::{ENABLE_KECCAK, ENABLE_KECCAK_OPS_OUTSIDE_GUARD}; From fb5897ebd063f229fd2a8b31bea6fa876901d982 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 13:42:42 +0000 Subject: [PATCH 20/28] add ip_iters pytest --- tests/test_block_record_fidelity.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_block_record_fidelity.py b/tests/test_block_record_fidelity.py index a56b353f5..10698035e 100644 --- a/tests/test_block_record_fidelity.py +++ b/tests/test_block_record_fidelity.py @@ -70,7 +70,7 @@ def get_block_record(rng: Random, ssi=None, ri=None, spi=None) -> BlockRecord: vdf_out = get_classgroup_element(rng) infused_challenge = get_optional(rng, get_classgroup_element) sub_slot_iters = ssi if ssi is not None else get_ssi(rng) - required_iters = get_u64(rng) + required_iters = ri if ri is not None else get_u64(rng) deficit = get_u8(rng) overflow = get_bool(rng) prev_tx_height = get_u32(rng) @@ -139,3 +139,18 @@ def test_calculate_sp_iters(): br = get_block_record(rng, ssi=ssi, spi=31) res = br.sp_iters_impl(DEFAULT_CONSTANTS) assert res is not None + + +def test_calculate_ip_iters(): + ssi: uint64 = uint64(100001 * 64 * 4) + sp_interval_iters = ssi // 32 + ri = sp_interval_iters - 1 + rng = Random() + rng.seed(1337) + br = get_block_record(rng, ssi=ssi, spi=31, ri=ri) + with raises(ValueError): + res = br.ip_iters_impl(DEFAULT_CONSTANTS) + + br = get_block_record(rng, ssi=ssi, spi=13, ri=1) + res = br.ip_iters_impl(DEFAULT_CONSTANTS) + assert res is not None From 44a04d3ad27d6b76a960efa58266ccf86319ee4d Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 14:07:57 +0000 Subject: [PATCH 21/28] clippy changes --- crates/chia-protocol/src/pot_iterations.rs | 24 ++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 82a8003b4..631223f97 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -98,19 +98,13 @@ mod tests { is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 31) .expect("valid SP index") ); - assert!(matches!( - is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 32), - Err(_) - )); + assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 32).is_err()); } #[test] fn test_calculate_sp_iters() { - let ssi: u64 = 100001 * 64 * 4; - assert!(matches!( - calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 32), - Err(_) - )); + let ssi: u64 = 100_001 * 64 * 4; + assert!(calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 32).is_err()); calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 31).expect("valid_result"); } @@ -121,14 +115,14 @@ mod tests { // # sub_slot_iters: u64, // # signage_point_index: u8, // # required_iters: u64, - let ssi: u64 = 100001 * 64 * 4; + let ssi: u64 = 100_001 * 64 * 4; let sp_interval_iters = ssi / NUM_SPS_SUB_SLOT as u64; // Invalid signage point index - assert!(matches!( - calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100000), - Err(_) - )); + assert!( + calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100_000) + .is_err() + ); let sp_iters = sp_interval_iters * 13; @@ -212,7 +206,7 @@ mod tests { ip_iters, (sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters) % ssi ); - assert!(sp_iters > ip_iters) + assert!(sp_iters > ip_iters); } } From d752a289514c4e2a4369e76f3bd201732a9fece6 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 14:29:12 +0000 Subject: [PATCH 22/28] update type stubs for new python functions --- wheel/generate_type_stubs.py | 27 +++++++++++++++++++++++++++ wheel/python/chia_rs/chia_rs.pyi | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/wheel/generate_type_stubs.py b/wheel/generate_type_stubs.py index 48ec6a9c6..6788b0d83 100644 --- a/wheel/generate_type_stubs.py +++ b/wheel/generate_type_stubs.py @@ -336,6 +336,33 @@ def get_flags_for_height_and_constants( constants: ConsensusConstants ) -> int: ... +def calculate_ip_iters( + num_sps_sub_slot: int, + num_sp_intervals_extra: int, + sub_slot_iters: int, + signage_point_index: int, + required_iters: int, +) -> int: ... + +def calculate_sp_iters( + num_sps_sub_slot: int, + sub_slot_iters: int, + signage_point_index: int, +) -> int: ... + +def calculate_sp_interval_iters( + num_sps_sub_slot: int, + sub_slot_iters: int, +) -> int: ... + +def is_overflow_block( + num_sps_sub_slot: int, + num_sp_intervals_extra: int, + signage_point_index: int, +) -> bool: ... + +def expected_plot_size(k: int) -> int: + NO_UNKNOWN_CONDS: int = ... STRICT_ARGS_COUNT: int = ... diff --git a/wheel/python/chia_rs/chia_rs.pyi b/wheel/python/chia_rs/chia_rs.pyi index af0306b92..4e7e7e4b8 100644 --- a/wheel/python/chia_rs/chia_rs.pyi +++ b/wheel/python/chia_rs/chia_rs.pyi @@ -65,6 +65,33 @@ def get_flags_for_height_and_constants( constants: ConsensusConstants ) -> int: ... +def calculate_ip_iters( + num_sps_sub_slot: int, + num_sp_intervals_extra: int, + sub_slot_iters: int, + signage_point_index: int, + required_iters: int, +) -> int: ... + +def calculate_sp_iters( + num_sps_sub_slot: int, + sub_slot_iters: int, + signage_point_index: int, +) -> int: ... + +def calculate_sp_interval_iters( + num_sps_sub_slot: int, + sub_slot_iters: int, +) -> int: ... + +def is_overflow_block( + num_sps_sub_slot: int, + num_sp_intervals_extra: int, + signage_point_index: int, +) -> bool: ... + +def expected_plot_size(k: int) -> int: + NO_UNKNOWN_CONDS: int = ... STRICT_ARGS_COUNT: int = ... From d0d08839765b6a8b9132f0e37a2e724a944d3ee4 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 14:33:51 +0000 Subject: [PATCH 23/28] fix stubs --- wheel/generate_type_stubs.py | 4 +++- wheel/python/chia_rs/chia_rs.pyi | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/wheel/generate_type_stubs.py b/wheel/generate_type_stubs.py index 6788b0d83..4800c19ec 100644 --- a/wheel/generate_type_stubs.py +++ b/wheel/generate_type_stubs.py @@ -361,7 +361,9 @@ def is_overflow_block( signage_point_index: int, ) -> bool: ... -def expected_plot_size(k: int) -> int: +def expected_plot_size( + k: int +) -> int: ... NO_UNKNOWN_CONDS: int = ... diff --git a/wheel/python/chia_rs/chia_rs.pyi b/wheel/python/chia_rs/chia_rs.pyi index 4e7e7e4b8..03c727dc6 100644 --- a/wheel/python/chia_rs/chia_rs.pyi +++ b/wheel/python/chia_rs/chia_rs.pyi @@ -90,7 +90,9 @@ def is_overflow_block( signage_point_index: int, ) -> bool: ... -def expected_plot_size(k: int) -> int: +def expected_plot_size( + k: int +) -> int: ... NO_UNKNOWN_CONDS: int = ... From b39c89c044b6a8cd0a8db153de10b1ea72cd2e04 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 15:04:11 +0000 Subject: [PATCH 24/28] add expected_plot_size to api.rs --- wheel/src/api.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 65540a621..0f6680e00 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -17,7 +17,8 @@ use chia_consensus::spendbundle_validation::{ get_flags_for_height_and_constants, validate_clvm_and_signature, }; use chia_protocol::{ - calculate_ip_iters, calculate_sp_interval_iters, calculate_sp_iters, is_overflow_block, + calculate_ip_iters, calculate_sp_interval_iters, calculate_sp_iters, expected_plot_size, + is_overflow_block, }; use chia_protocol::{ BlockRecord, Bytes32, ChallengeBlockInfo, ChallengeChainSubSlot, ClassgroupElement, Coin, @@ -466,6 +467,7 @@ pub fn chia_rs(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(calculate_sp_iters, m)?)?; m.add_function(wrap_pyfunction!(calculate_ip_iters, m)?)?; m.add_function(wrap_pyfunction!(is_overflow_block, m)?)?; + m.add_function(wrap_pyfunction!(expected_plot_size, m)?)?; // constants m.add_class::()?; From 638943b5f85941d65d1d0f1befbddac7566bc3f1 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 15:13:03 +0000 Subject: [PATCH 25/28] black test --- tests/test_pot_iterations.py | 123 +++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 19 deletions(-) diff --git a/tests/test_pot_iterations.py b/tests/test_pot_iterations.py index 1b6f01610..6296a91a2 100644 --- a/tests/test_pot_iterations.py +++ b/tests/test_pot_iterations.py @@ -3,6 +3,7 @@ from pytest import raises from run_gen import DEFAULT_CONSTANTS + # from chia.consensus.pos_quality import _expected_plot_size from chia_rs import ( calculate_ip_iters, @@ -10,21 +11,48 @@ calculate_sp_iters, is_overflow_block, ) + # from chia.util.hash import std_hash -from chia_rs.sized_ints import uint8, uint16, uint32, uint64 #, uint128 +from chia_rs.sized_ints import uint8, uint16, uint32, uint64 # , uint128 -test_constants = DEFAULT_CONSTANTS.replace(NUM_SPS_SUB_SLOT=uint32(32), SUB_SLOT_TIME_TARGET=uint16(300)) +test_constants = DEFAULT_CONSTANTS.replace( + NUM_SPS_SUB_SLOT=uint32(32), SUB_SLOT_TIME_TARGET=uint16(300) +) class TestPotIterations: def test_is_overflow_block(self): - assert not is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(27)) - assert not is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(28)) - assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(29)) - assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(30)) - assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(31)) + assert not is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(27), + ) + assert not is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(28), + ) + assert is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(29), + ) + assert is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(30), + ) + assert is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(31), + ) with raises(ValueError): - assert is_overflow_block(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, uint8(32)) + assert is_overflow_block( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + uint8(32), + ) def test_calculate_sp_iters(self): ssi: uint64 = uint64(100001 * 64 * 4) @@ -44,46 +72,103 @@ def test_calculate_ip_iters(self): with raises(ValueError): # Invalid signage point index calculate_ip_iters( - test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(123), uint64(100000) + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + uint8(123), + uint64(100000), ) sp_iters = sp_interval_iters * 13 with raises(ValueError): # required_iters too high - calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, sp_interval_iters) + calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters, + sp_interval_iters, + ) with raises(ValueError): # required_iters too high - calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, sp_interval_iters * 12) + calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters, + sp_interval_iters * 12, + ) with raises(ValueError): # required_iters too low (0) - calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters, uint64(0)) + calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters, + uint64(0), + ) required_iters = sp_interval_iters - 1 - ip_iters = calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(13), required_iters) - assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + ip_iters = calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + uint8(13), + required_iters, + ) + assert ( + ip_iters + == sp_iters + + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + + required_iters + ) required_iters = uint64(1) - ip_iters = calculate_ip_iters(test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(13), required_iters) - assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + ip_iters = calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + uint8(13), + required_iters, + ) + assert ( + ip_iters + == sp_iters + + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + + required_iters + ) required_iters = uint64(int(ssi * 4 / 300)) ip_iters = calculate_ip_iters(test_constants, ssi, uint8(13), required_iters) - assert ip_iters == sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters + assert ( + ip_iters + == sp_iters + + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + + required_iters + ) assert sp_iters < ip_iters # Overflow sp_iters = sp_interval_iters * (test_constants.NUM_SPS_SUB_SLOT - 1) ip_iters = calculate_ip_iters( - test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, ssi, uint8(test_constants.NUM_SPS_SUB_SLOT - 1), required_iters, ) - assert ip_iters == (sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters) % ssi + assert ( + ip_iters + == ( + sp_iters + + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + + required_iters + ) + % ssi + ) assert sp_iters > ip_iters # def test_win_percentage(self): From 4294ff44f713cef18f9242407af6056ddd4af7d3 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 15:40:48 +0000 Subject: [PATCH 26/28] process signage_point_index as u32 to prevent overflows --- crates/chia-protocol/src/block_record.rs | 4 +- crates/chia-protocol/src/pot_iterations.rs | 64 ++++++++++++---------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/crates/chia-protocol/src/block_record.rs b/crates/chia-protocol/src/block_record.rs index a430c7744..3391ec520 100644 --- a/crates/chia-protocol/src/block_record.rs +++ b/crates/chia-protocol/src/block_record.rs @@ -165,7 +165,7 @@ impl BlockRecord { calculate_sp_iters( num_sps_sub_slot, self.sub_slot_iters, - self.signage_point_index, + self.signage_point_index as u32, ) } @@ -178,7 +178,7 @@ impl BlockRecord { num_sps_sub_slot, num_sp_intervals_extra, self.sub_slot_iters, - self.signage_point_index, + self.signage_point_index as u32, self.required_iters, ) } diff --git a/crates/chia-protocol/src/pot_iterations.rs b/crates/chia-protocol/src/pot_iterations.rs index 631223f97..321a83624 100644 --- a/crates/chia-protocol/src/pot_iterations.rs +++ b/crates/chia-protocol/src/pot_iterations.rs @@ -8,12 +8,12 @@ pub fn is_overflow_block( num_sps_sub_slot: u32, num_sp_intervals_extra: u8, - signage_point_index: u8, + signage_point_index: u32, ) -> pyo3::PyResult { - if signage_point_index as u32 >= num_sps_sub_slot { + if signage_point_index >= num_sps_sub_slot { return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); } - Ok(signage_point_index as u32 >= num_sps_sub_slot - num_sp_intervals_extra as u32) + Ok(signage_point_index >= num_sps_sub_slot - num_sp_intervals_extra as u32) } #[cfg(feature = "py-bindings")] @@ -35,9 +35,9 @@ pub fn calculate_sp_interval_iters( pub fn calculate_sp_iters( num_sps_sub_slot: u32, sub_slot_iters: u64, - signage_point_index: u8, + signage_point_index: u32, ) -> pyo3::PyResult { - if signage_point_index as u32 >= num_sps_sub_slot { + if signage_point_index >= num_sps_sub_slot { return Err(pyo3::exceptions::PyValueError::new_err("SP index too high")); } Ok(calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)? * signage_point_index as u64) @@ -49,7 +49,7 @@ pub fn calculate_ip_iters( num_sps_sub_slot: u32, num_sp_intervals_extra: u8, sub_slot_iters: u64, - signage_point_index: u8, + signage_point_index: u32, required_iters: u64, ) -> pyo3::PyResult { let sp_interval_iters = calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)?; @@ -73,7 +73,6 @@ pub fn calculate_ip_iters( mod tests { use super::*; static NUM_SPS_SUB_SLOT: u32 = 32; - static NUM_SPS_SUB_SLOT_U8: u8 = 32; static NUM_SP_INTERVALS_EXTRA: u8 = 3; #[test] @@ -127,27 +126,34 @@ mod tests { let sp_iters = sp_interval_iters * 13; // required_iters too high - // disabled this test as rusts typing enforces it already - // assert!(matches!( - // calculate_ip_iters( - // NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters - // ), - // Err(_) - // )); - - // // required_iters too high - // assert!(matches!( - // calculate_ip_iters( - // NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), sp_interval_iters * 12 - // ), - // Err(_) - // )); - - // // required_iters too low (0) - // assert!(matches!( - // calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, sp_interval_iters.try_into().unwrap(), 0), - // Err(_) - // )); + assert!(calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters.try_into().unwrap(), + sp_interval_iters + ) + .is_err()); + + // required_iters too high + assert!(calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters.try_into().unwrap(), + sp_interval_iters * 12 + ) + .is_err()); + + // required_iters too low (0) + assert!(calculate_ip_iters( + NUM_SPS_SUB_SLOT, + NUM_SP_INTERVALS_EXTRA, + ssi, + sp_interval_iters.try_into().unwrap(), + 0 + ) + .is_err()); let required_iters = sp_interval_iters - 1; let ip_iters = calculate_ip_iters( @@ -198,7 +204,7 @@ mod tests { NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, - NUM_SPS_SUB_SLOT_U8 - 1_u8, + NUM_SPS_SUB_SLOT - 1_u32, required_iters, ) .expect("valid"); From 68aca234210d67387485a12cd3cec3741c637821 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 15:45:29 +0000 Subject: [PATCH 27/28] pytests passing --- tests/test_pot_iterations.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_pot_iterations.py b/tests/test_pot_iterations.py index 6296a91a2..e9660243d 100644 --- a/tests/test_pot_iterations.py +++ b/tests/test_pot_iterations.py @@ -142,7 +142,13 @@ def test_calculate_ip_iters(self): ) required_iters = uint64(int(ssi * 4 / 300)) - ip_iters = calculate_ip_iters(test_constants, ssi, uint8(13), required_iters) + ip_iters = calculate_ip_iters( + test_constants.NUM_SPS_SUB_SLOT, + test_constants.NUM_SP_INTERVALS_EXTRA, + ssi, + uint8(13), + required_iters + ) assert ( ip_iters == sp_iters From 9f6f641cc8e55d5f980753fcc8db3f398604beb4 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 27 Jan 2025 15:50:36 +0000 Subject: [PATCH 28/28] black test again --- tests/test_pot_iterations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_pot_iterations.py b/tests/test_pot_iterations.py index e9660243d..4ed7bbc3a 100644 --- a/tests/test_pot_iterations.py +++ b/tests/test_pot_iterations.py @@ -145,9 +145,9 @@ def test_calculate_ip_iters(self): ip_iters = calculate_ip_iters( test_constants.NUM_SPS_SUB_SLOT, test_constants.NUM_SP_INTERVALS_EXTRA, - ssi, - uint8(13), - required_iters + ssi, + uint8(13), + required_iters, ) assert ( ip_iters