From 1270f1da021d5a10e707a5fadaabc76dd96cb752 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 31 Jul 2024 13:08:38 +0100 Subject: [PATCH 01/15] initial commit --- .../src/spendbundle_conditions.rs | 69 +++++++++++++++++++ .../src/spendbundle_validation.rs | 38 ++++++++++ 2 files changed, 107 insertions(+) create mode 100644 crates/chia-consensus/src/spendbundle_conditions.rs create mode 100644 crates/chia-consensus/src/spendbundle_validation.rs diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs new file mode 100644 index 000000000..86a32eb02 --- /dev/null +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -0,0 +1,69 @@ +use crate::allocator::make_allocator; +use crate::consensus_constants::ConsensusConstants; +use crate::gen::conditions::{ + process_single_spend, validate_conditions, MempoolVisitor, ParseState, SpendBundleConditions, +}; +use crate::gen::flags::MEMPOOL_MODE; +use crate::gen::owned_conditions::OwnedSpendBundleConditions; +use crate::gen::run_block_generator::subtract_cost; +use crate::gen::validation_error::ValidationErr; +use crate::spendbundle_validation::get_flags_for_height_and_constants; +use chia_protocol::SpendBundle; +use clvm_utils::{tree_hash_cached, TreeHash}; +use clvmr::allocator::{Allocator, NodePtr}; +use clvmr::chia_dialect::ChiaDialect; +use clvmr::chia_dialect::LIMIT_HEAP; +use clvmr::reduction::Reduction; +use clvmr::run_program::run_program; +use clvmr::serde::node_from_bytes; +use std::collections::{HashMap, HashSet}; + +pub fn get_conditions_from_spendbundle( + spend_bundle: &SpendBundle, + max_cost: u64, + height: u32, + constants: &ConsensusConstants, +) -> Result { + let flags = get_flags_for_height_and_constants(height, constants) | MEMPOOL_MODE; + + // below is an adapted version of the code from run_block_generators::run_block_generator2() + // it assumes no block references are passed in + let mut cost_left = max_cost; + let dialect = ChiaDialect::new(flags); + let mut a: Allocator = make_allocator(LIMIT_HEAP); + let mut ret = SpendBundleConditions::default(); + let mut state = ParseState::default(); + let mut cache = HashMap::::new(); + + for coin_spend in &spend_bundle.coin_spends { + // process the spend + let puz = node_from_bytes(&mut a, coin_spend.puzzle_reveal.as_slice())?; + let sol = node_from_bytes(&mut a, coin_spend.solution.as_slice())?; + let parent = a.new_atom(coin_spend.coin.parent_coin_info.as_slice())?; + let amount = a.new_number(coin_spend.coin.amount.into())?; + let Reduction(clvm_cost, conditions) = run_program(&mut a, &dialect, puz, sol, cost_left)?; + + subtract_cost(&a, &mut cost_left, clvm_cost)?; + + let buf = tree_hash_cached(&a, puz, &HashSet::::new(), &mut cache); + let puzzle_hash = a.new_atom(&buf)?; + process_single_spend::( + &a, + &mut ret, + &mut state, + parent, + puzzle_hash, + amount, + conditions, + flags, + &mut cost_left, + constants, + )?; + } + + validate_conditions(&a, &ret, state, a.nil(), flags)?; + assert!(max_cost >= cost_left); + ret.cost = max_cost - cost_left; + let osbc = OwnedSpendBundleConditions::from(&a, ret); + Ok(osbc) +} diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs new file mode 100644 index 000000000..7cb1b1ba0 --- /dev/null +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -0,0 +1,38 @@ +use crate::consensus_constants::ConsensusConstants; +use crate::gen::flags::{ALLOW_BACKREFS, DISALLOW_INFINITY_G1, ENABLE_MESSAGE_CONDITIONS}; +use crate::gen::opcodes::{ + AGG_SIG_AMOUNT, AGG_SIG_ME, AGG_SIG_PARENT, AGG_SIG_PARENT_AMOUNT, AGG_SIG_PARENT_PUZZLE, + AGG_SIG_PUZZLE, AGG_SIG_PUZZLE_AMOUNT, +}; + + +pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusConstants) -> u32 { + let mut flags: u32 = 0; + + if height >= constants.soft_fork4_height { + flags |= ENABLE_MESSAGE_CONDITIONS; + } + + if height >= constants.soft_fork5_height { + flags |= DISALLOW_INFINITY_G1; + } + + if height >= constants.hard_fork_height { + // the hard-fork initiated with 2.0. To activate June 2024 + // * costs are ascribed to some unknown condition codes, to allow for + // soft-forking in new conditions with cost + // * a new condition, SOFTFORK, is added which takes a first parameter to + // specify its cost. This allows soft-forks similar to the softfork + // operator + // * BLS operators introduced in the soft-fork (behind the softfork + // guard) are made available outside of the guard. + // * division with negative numbers are allowed, and round toward + // negative infinity + // * AGG_SIG_* conditions are allowed to have unknown additional + // arguments + // * Allow the block generator to be serialized with the improved clvm + // serialization format (with back-references) + flags = flags | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS; + } + flags +} From 9ec59d9ab228f3d01002f942546ddbd627bb2dc1 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 31 Jul 2024 13:15:25 +0100 Subject: [PATCH 02/15] add to lib --- crates/chia-consensus/src/gen/run_block_generator.rs | 2 +- crates/chia-consensus/src/lib.rs | 2 ++ crates/chia-consensus/src/spendbundle_validation.rs | 6 ++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/chia-consensus/src/gen/run_block_generator.rs b/crates/chia-consensus/src/gen/run_block_generator.rs index 8a0360d4f..53135dfee 100644 --- a/crates/chia-consensus/src/gen/run_block_generator.rs +++ b/crates/chia-consensus/src/gen/run_block_generator.rs @@ -15,7 +15,7 @@ use clvmr::run_program::run_program; use clvmr::serde::{node_from_bytes, node_from_bytes_backrefs, node_from_bytes_backrefs_record}; use std::collections::{HashMap, HashSet}; -fn subtract_cost(a: &Allocator, cost_left: &mut Cost, subtract: Cost) -> Result<(), ValidationErr> { +pub fn subtract_cost(a: &Allocator, cost_left: &mut Cost, subtract: Cost) -> Result<(), ValidationErr> { if subtract > *cost_left { Err(ValidationErr(a.nil(), ErrorCode::CostExceeded)) } else { diff --git a/crates/chia-consensus/src/lib.rs b/crates/chia-consensus/src/lib.rs index b7e99a193..2656d87c9 100644 --- a/crates/chia-consensus/src/lib.rs +++ b/crates/chia-consensus/src/lib.rs @@ -8,3 +8,5 @@ pub mod gen; 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 diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index 7cb1b1ba0..c2bfbe1c4 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -1,9 +1,7 @@ +use clvmr::{ENABLE_BLS_OPS_OUTSIDE_GUARD, ENABLE_FIXED_DIV}; + use crate::consensus_constants::ConsensusConstants; use crate::gen::flags::{ALLOW_BACKREFS, DISALLOW_INFINITY_G1, ENABLE_MESSAGE_CONDITIONS}; -use crate::gen::opcodes::{ - AGG_SIG_AMOUNT, AGG_SIG_ME, AGG_SIG_PARENT, AGG_SIG_PARENT_AMOUNT, AGG_SIG_PARENT_PUZZLE, - AGG_SIG_PUZZLE, AGG_SIG_PUZZLE_AMOUNT, -}; pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusConstants) -> u32 { From 83398d947418d269baf5d26b604611ebea39adf7 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 31 Jul 2024 13:25:22 +0100 Subject: [PATCH 03/15] add api info for pybindings --- wheel/generate_type_stubs.py | 13 ++++++++++++ wheel/python/chia_rs/chia_rs.pyi | 13 ++++++++++++ wheel/src/api.rs | 35 +++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/wheel/generate_type_stubs.py b/wheel/generate_type_stubs.py index 008b8ecdb..c8c9a952f 100644 --- a/wheel/generate_type_stubs.py +++ b/wheel/generate_type_stubs.py @@ -305,6 +305,19 @@ def confirm_not_included_already_hashed( proof: bytes, ) -> bool: ... +def get_name_puzzle_conditions( + spend_bundle: SpendBundle, + max_cost: int, + constants: ConsensusConstants, + height: int, +) -> SpendBundleConditions: ... + +def get_flags_for_height_and_constants( + height: int, + constants: ConsensusConstants +) -> int: ... + + NO_UNKNOWN_CONDS: int = ... STRICT_ARGS_COUNT: int = ... LIMIT_HEAP: int = ... diff --git a/wheel/python/chia_rs/chia_rs.pyi b/wheel/python/chia_rs/chia_rs.pyi index 3a543d342..686c99d43 100644 --- a/wheel/python/chia_rs/chia_rs.pyi +++ b/wheel/python/chia_rs/chia_rs.pyi @@ -49,6 +49,19 @@ def confirm_not_included_already_hashed( proof: bytes, ) -> bool: ... +def get_name_puzzle_conditions( + spend_bundle: SpendBundle, + max_cost: int, + constants: ConsensusConstants, + height: int, +) -> SpendBundleConditions: ... + +def get_flags_for_height_and_constants( + height: int, + constants: ConsensusConstants +) -> int: ... + + NO_UNKNOWN_CONDS: int = ... STRICT_ARGS_COUNT: int = ... LIMIT_HEAP: int = ... diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 43c7e88d3..fc6441de2 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -12,6 +12,8 @@ use chia_consensus::gen::solution_generator::solution_generator as native_soluti use chia_consensus::gen::solution_generator::solution_generator_backrefs as native_solution_generator_backrefs; use chia_consensus::merkle_set::compute_merkle_set_root as compute_merkle_root_impl; use chia_consensus::merkle_tree::{validate_merkle_proof, MerkleSet}; +use chia_consensus::spendbundle_conditions::get_conditions_from_spendbundle; +use chia_consensus::spendbundle_validation::get_flags_for_height_and_constants; use chia_protocol::{ BlockRecord, Bytes32, ChallengeBlockInfo, ChallengeChainSubSlot, ClassgroupElement, Coin, CoinSpend, CoinState, CoinStateFilters, CoinStateUpdate, EndOfSubSlotBundle, Foliage, @@ -41,7 +43,7 @@ use chia_protocol::{ use clvm_utils::tree_hash_from_bytes; use clvmr::{ENABLE_BLS_OPS_OUTSIDE_GUARD, ENABLE_FIXED_DIV, LIMIT_HEAP, NO_UNKNOWN_OPS}; use pyo3::buffer::PyBuffer; -use pyo3::exceptions::{PyRuntimeError, PyValueError}; +use pyo3::exceptions::{PyRuntimeError, PyTypeError, PyValueError}; use pyo3::prelude::*; use pyo3::pybacked::PyBackedBytes; use pyo3::types::PyBytes; @@ -356,6 +358,33 @@ fn fast_forward_singleton<'p>( )) } +#[pyfunction] +#[pyo3(name = "get_conditions_from_spendbundle")] +pub fn py_get_conditions_from_spendbundle( + spend_bundle: &SpendBundle, + max_cost: u64, + constants: &ConsensusConstants, + height: u32, +) -> PyResult { + let osbc = get_conditions_from_spendbundle(spend_bundle, max_cost, height, constants).map_err( + |e| { + let error_code: u32 = e.1.into(); + PyErr::new::(error_code) + }, + )?; + Ok(osbc) +} + +#[pyfunction] +#[pyo3(name = "get_flags_for_height_and_constants")] +pub fn py_get_flags_for_height_and_constants( + height: u32, + constants: &ConsensusConstants, +) -> PyResult { + let flags = get_flags_for_height_and_constants(height, constants); + Ok(flags) +} + #[pymodule] pub fn chia_rs(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { // generator functions @@ -385,6 +414,10 @@ pub fn chia_rs(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(confirm_included_already_hashed, m)?)?; m.add_function(wrap_pyfunction!(confirm_not_included_already_hashed, m)?)?; + // multithread validattion + m.add_function(wrap_pyfunction!(py_get_conditions_from_spendbundle, m)?)?; + m.add_function(wrap_pyfunction!(py_get_flags_for_height_and_constants, m)?)?; + // clvm functions m.add("NO_UNKNOWN_CONDS", NO_UNKNOWN_CONDS)?; m.add("STRICT_ARGS_COUNT", STRICT_ARGS_COUNT)?; From ce15eeced993c981ed0471eb61cb466ec6a82889 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Wed, 31 Jul 2024 13:44:26 +0100 Subject: [PATCH 04/15] cargo fmt --- crates/chia-consensus/src/gen/run_block_generator.rs | 6 +++++- crates/chia-consensus/src/lib.rs | 2 +- crates/chia-consensus/src/spendbundle_validation.rs | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/chia-consensus/src/gen/run_block_generator.rs b/crates/chia-consensus/src/gen/run_block_generator.rs index 53135dfee..e73ebf01d 100644 --- a/crates/chia-consensus/src/gen/run_block_generator.rs +++ b/crates/chia-consensus/src/gen/run_block_generator.rs @@ -15,7 +15,11 @@ use clvmr::run_program::run_program; use clvmr::serde::{node_from_bytes, node_from_bytes_backrefs, node_from_bytes_backrefs_record}; use std::collections::{HashMap, HashSet}; -pub fn subtract_cost(a: &Allocator, cost_left: &mut Cost, subtract: Cost) -> Result<(), ValidationErr> { +pub fn subtract_cost( + a: &Allocator, + cost_left: &mut Cost, + subtract: Cost, +) -> Result<(), ValidationErr> { if subtract > *cost_left { Err(ValidationErr(a.nil(), ErrorCode::CostExceeded)) } else { diff --git a/crates/chia-consensus/src/lib.rs b/crates/chia-consensus/src/lib.rs index 2656d87c9..018eac02b 100644 --- a/crates/chia-consensus/src/lib.rs +++ b/crates/chia-consensus/src/lib.rs @@ -9,4 +9,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-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index c2bfbe1c4..967673344 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -3,7 +3,6 @@ use clvmr::{ENABLE_BLS_OPS_OUTSIDE_GUARD, ENABLE_FIXED_DIV}; use crate::consensus_constants::ConsensusConstants; use crate::gen::flags::{ALLOW_BACKREFS, DISALLOW_INFINITY_G1, ENABLE_MESSAGE_CONDITIONS}; - pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusConstants) -> u32 { let mut flags: u32 = 0; From 0b73cb31abc3a377780df3ec622bd8310e405da6 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 2 Aug 2024 11:26:29 +0100 Subject: [PATCH 05/15] use uncached tree_hash() --- crates/chia-consensus/src/spendbundle_conditions.rs | 8 +++----- wheel/src/api.rs | 5 ++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs index 86a32eb02..50fd96258 100644 --- a/crates/chia-consensus/src/spendbundle_conditions.rs +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -9,14 +9,13 @@ use crate::gen::run_block_generator::subtract_cost; use crate::gen::validation_error::ValidationErr; use crate::spendbundle_validation::get_flags_for_height_and_constants; use chia_protocol::SpendBundle; -use clvm_utils::{tree_hash_cached, TreeHash}; -use clvmr::allocator::{Allocator, NodePtr}; +use clvm_utils::tree_hash; +use clvmr::allocator::Allocator; use clvmr::chia_dialect::ChiaDialect; use clvmr::chia_dialect::LIMIT_HEAP; use clvmr::reduction::Reduction; use clvmr::run_program::run_program; use clvmr::serde::node_from_bytes; -use std::collections::{HashMap, HashSet}; pub fn get_conditions_from_spendbundle( spend_bundle: &SpendBundle, @@ -33,7 +32,6 @@ pub fn get_conditions_from_spendbundle( let mut a: Allocator = make_allocator(LIMIT_HEAP); let mut ret = SpendBundleConditions::default(); let mut state = ParseState::default(); - let mut cache = HashMap::::new(); for coin_spend in &spend_bundle.coin_spends { // process the spend @@ -45,7 +43,7 @@ pub fn get_conditions_from_spendbundle( subtract_cost(&a, &mut cost_left, clvm_cost)?; - let buf = tree_hash_cached(&a, puz, &HashSet::::new(), &mut cache); + let buf = tree_hash(&a, puz); let puzzle_hash = a.new_atom(&buf)?; process_single_spend::( &a, diff --git a/wheel/src/api.rs b/wheel/src/api.rs index fc6441de2..59bb874b5 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -380,9 +380,8 @@ pub fn py_get_conditions_from_spendbundle( pub fn py_get_flags_for_height_and_constants( height: u32, constants: &ConsensusConstants, -) -> PyResult { - let flags = get_flags_for_height_and_constants(height, constants); - Ok(flags) +) -> u32 { + get_flags_for_height_and_constants(height, constants) } #[pymodule] From 46de45ebf49b79655e812aee56dbb74691187605 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 2 Aug 2024 12:56:45 +0100 Subject: [PATCH 06/15] fmt --- wheel/src/api.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 59bb874b5..f6127c8b0 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -377,10 +377,7 @@ pub fn py_get_conditions_from_spendbundle( #[pyfunction] #[pyo3(name = "get_flags_for_height_and_constants")] -pub fn py_get_flags_for_height_and_constants( - height: u32, - constants: &ConsensusConstants, -) -> u32 { +pub fn py_get_flags_for_height_and_constants(height: u32, constants: &ConsensusConstants) -> u32 { get_flags_for_height_and_constants(height, constants) } From 54ff4d36f410d0e0d5920cb9b601f9037d3e8c3a Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 2 Aug 2024 16:02:28 +0100 Subject: [PATCH 07/15] add test for get_conditions_from_spendbundle() --- .../src/spendbundle_conditions.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs index 50fd96258..ebcef1ed8 100644 --- a/crates/chia-consensus/src/spendbundle_conditions.rs +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -65,3 +65,43 @@ pub fn get_conditions_from_spendbundle( let osbc = OwnedSpendBundleConditions::from(&a, ret); Ok(osbc) } + +#[cfg(test)] +mod tests { + use crate::consensus_constants::TEST_CONSTANTS; + + use super::*; + use chia_bls::Signature; + use chia_protocol::{Coin, CoinSpend, Program}; + use hex_literal::hex; + + #[test] + fn test_get_conditions_from_spendbundle() { + let test_coin = Coin::new( + hex!("4444444444444444444444444444444444444444444444444444444444444444").into(), + hex!("3333333333333333333333333333333333333333333333333333333333333333").into(), + 1, + ); + + let solution = hex!("ffff31ffb0997cc43ed8788f841fcf3071f6f212b89ba494b6ebaf1bda88c3f9de9d968a61f3b7284a5ee13889399ca71a026549a2ff8568656c6c6f8080").to_vec(); + // ((49 0x997cc43ed8788f841fcf3071f6f212b89ba494b6ebaf1bda88c3f9de9d968a61f3b7284a5ee13889399ca71a026549a2 "hello")) + + let spend = CoinSpend::new(test_coin, Program::new(vec![1_u8].into()), solution.into()); + + let coin_spends: Vec = vec![spend]; + let spend_bundle = SpendBundle { + coin_spends, + aggregated_signature: Signature::default(), + }; + let osbc = get_conditions_from_spendbundle( + &spend_bundle, + TEST_CONSTANTS.max_block_cost_clvm, + 236, + &TEST_CONSTANTS, + ) + .expect("test should pass"); + + assert!(osbc.spends.len() == 1); + assert!(osbc.agg_sig_unsafe.len() == 1); + } +} From 7546defaae285e47634b53bfe410372bf3d1ae0b Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 2 Aug 2024 18:26:00 +0100 Subject: [PATCH 08/15] add regression test for get_flags --- .../src/spendbundle_validation.rs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index 967673344..9f61d9b6b 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -33,3 +33,41 @@ pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusCons } flags } + +#[cfg(test)] +mod tests { + use super::*; + use crate::consensus_constants::TEST_CONSTANTS; + + #[test] + fn test_get_flags() { + assert_eq!( + get_flags_for_height_and_constants( + TEST_CONSTANTS.soft_fork4_height - 1, + &TEST_CONSTANTS + ), + 33554592 + ); + assert_eq!( + get_flags_for_height_and_constants( + TEST_CONSTANTS.soft_fork5_height - 1, + &TEST_CONSTANTS + ), + 167772320 + ); + assert_eq!( + get_flags_for_height_and_constants( + TEST_CONSTANTS.hard_fork_height - 1, + &TEST_CONSTANTS + ), + 0 + ); + assert_eq!( + get_flags_for_height_and_constants( + TEST_CONSTANTS.soft_fork5_height + 1, + &TEST_CONSTANTS + ), + 436207776 + ); + } +} From 907cd19290c0b29cb8267f223b79f738acd365f4 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Fri, 2 Aug 2024 18:27:24 +0100 Subject: [PATCH 09/15] use underscored numbers for readability --- crates/chia-consensus/src/spendbundle_validation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index 9f61d9b6b..80c85ccdf 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -46,14 +46,14 @@ mod tests { TEST_CONSTANTS.soft_fork4_height - 1, &TEST_CONSTANTS ), - 33554592 + 33_554_592 ); assert_eq!( get_flags_for_height_and_constants( TEST_CONSTANTS.soft_fork5_height - 1, &TEST_CONSTANTS ), - 167772320 + 167_772_320 ); assert_eq!( get_flags_for_height_and_constants( @@ -67,7 +67,7 @@ mod tests { TEST_CONSTANTS.soft_fork5_height + 1, &TEST_CONSTANTS ), - 436207776 + 436_207_776 ); } } From b143770a4e7645c06cc1dc1ce6357565d4b6e6e2 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 2 Aug 2024 22:38:20 +0200 Subject: [PATCH 10/15] make get_conditions_from_spendbundle() return a non-owned SpendBundleConditions (to enable reusing existing test facilities). Extend the tests to cover the block-generator test cases --- crates/chia-consensus/src/gen/mod.rs | 2 +- .../chia-consensus/src/gen/test_generators.rs | 4 +- .../src/spendbundle_conditions.rs | 297 +++++++++++++++--- wheel/src/api.rs | 17 +- 4 files changed, 271 insertions(+), 49 deletions(-) diff --git a/crates/chia-consensus/src/gen/mod.rs b/crates/chia-consensus/src/gen/mod.rs index a48e1022d..246d2bd15 100644 --- a/crates/chia-consensus/src/gen/mod.rs +++ b/crates/chia-consensus/src/gen/mod.rs @@ -17,4 +17,4 @@ pub mod validation_error; // unoptimized builds. Only run these with --release #[cfg(not(debug_assertions))] #[cfg(test)] -mod test_generators; +pub(crate) mod test_generators; diff --git a/crates/chia-consensus/src/gen/test_generators.rs b/crates/chia-consensus/src/gen/test_generators.rs index 6f1794745..fafcbac8c 100644 --- a/crates/chia-consensus/src/gen/test_generators.rs +++ b/crates/chia-consensus/src/gen/test_generators.rs @@ -12,7 +12,7 @@ use text_diff::Difference; use rstest::rstest; -fn print_conditions(a: &Allocator, c: &SpendBundleConditions) -> String { +pub(crate) fn print_conditions(a: &Allocator, c: &SpendBundleConditions) -> String { let mut ret = String::new(); if c.reserve_fee > 0 { ret += &format!("RESERVE_FEE: {}\n", c.reserve_fee); @@ -115,7 +115,7 @@ fn print_conditions(a: &Allocator, c: &SpendBundleConditions) -> String { ret } -fn print_diff(output: &str, expected: &str) { +pub(crate) fn print_diff(output: &str, expected: &str) { println!("\x1b[102m \x1b[0m - output from test"); println!("\x1b[101m \x1b[0m - expected output"); for diff in diff(expected, output, "\n").1 { diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs index ebcef1ed8..55fd9051f 100644 --- a/crates/chia-consensus/src/spendbundle_conditions.rs +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -1,10 +1,8 @@ -use crate::allocator::make_allocator; use crate::consensus_constants::ConsensusConstants; use crate::gen::conditions::{ process_single_spend, validate_conditions, MempoolVisitor, ParseState, SpendBundleConditions, }; use crate::gen::flags::MEMPOOL_MODE; -use crate::gen::owned_conditions::OwnedSpendBundleConditions; use crate::gen::run_block_generator::subtract_cost; use crate::gen::validation_error::ValidationErr; use crate::spendbundle_validation::get_flags_for_height_and_constants; @@ -12,41 +10,40 @@ use chia_protocol::SpendBundle; use clvm_utils::tree_hash; use clvmr::allocator::Allocator; use clvmr::chia_dialect::ChiaDialect; -use clvmr::chia_dialect::LIMIT_HEAP; use clvmr::reduction::Reduction; use clvmr::run_program::run_program; use clvmr::serde::node_from_bytes; pub fn get_conditions_from_spendbundle( + a: &mut Allocator, spend_bundle: &SpendBundle, max_cost: u64, height: u32, constants: &ConsensusConstants, -) -> Result { +) -> Result { let flags = get_flags_for_height_and_constants(height, constants) | MEMPOOL_MODE; // below is an adapted version of the code from run_block_generators::run_block_generator2() // it assumes no block references are passed in let mut cost_left = max_cost; let dialect = ChiaDialect::new(flags); - let mut a: Allocator = make_allocator(LIMIT_HEAP); let mut ret = SpendBundleConditions::default(); let mut state = ParseState::default(); for coin_spend in &spend_bundle.coin_spends { // process the spend - let puz = node_from_bytes(&mut a, coin_spend.puzzle_reveal.as_slice())?; - let sol = node_from_bytes(&mut a, coin_spend.solution.as_slice())?; + let puz = node_from_bytes(a, coin_spend.puzzle_reveal.as_slice())?; + let sol = node_from_bytes(a, coin_spend.solution.as_slice())?; let parent = a.new_atom(coin_spend.coin.parent_coin_info.as_slice())?; let amount = a.new_number(coin_spend.coin.amount.into())?; - let Reduction(clvm_cost, conditions) = run_program(&mut a, &dialect, puz, sol, cost_left)?; + let Reduction(clvm_cost, conditions) = run_program(a, &dialect, puz, sol, cost_left)?; - subtract_cost(&a, &mut cost_left, clvm_cost)?; + subtract_cost(a, &mut cost_left, clvm_cost)?; - let buf = tree_hash(&a, puz); + let buf = tree_hash(a, puz); let puzzle_hash = a.new_atom(&buf)?; process_single_spend::( - &a, + a, &mut ret, &mut state, parent, @@ -59,11 +56,10 @@ pub fn get_conditions_from_spendbundle( )?; } - validate_conditions(&a, &ret, state, a.nil(), flags)?; + validate_conditions(a, &ret, state, a.nil(), flags)?; assert!(max_cost >= cost_left); ret.cost = max_cost - cost_left; - let osbc = OwnedSpendBundleConditions::from(&a, ret); - Ok(osbc) + Ok(ret) } #[cfg(test)] @@ -71,37 +67,260 @@ mod tests { use crate::consensus_constants::TEST_CONSTANTS; use super::*; + use crate::allocator::make_allocator; + use crate::gen::conditions::{ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF}; use chia_bls::Signature; - use chia_protocol::{Coin, CoinSpend, Program}; - use hex_literal::hex; - - #[test] - fn test_get_conditions_from_spendbundle() { - let test_coin = Coin::new( - hex!("4444444444444444444444444444444444444444444444444444444444444444").into(), - hex!("3333333333333333333333333333333333333333333333333333333333333333").into(), - 1, - ); + use chia_protocol::CoinSpend; + use chia_traits::Streamable; + use clvmr::chia_dialect::LIMIT_HEAP; + use rstest::rstest; + use std::fs::read; + + #[rstest] + #[case("3000253", 8, 2, 13_344_870)] + #[case("1000101", 34, 15, 66_723_677)] + fn test_get_conditions_from_spendbundle( + #[case] filename: &str, + #[case] spends: usize, + #[case] additions: usize, + #[values(0, 1, 1000000, 5000000)] height: u32, + #[case] cost: u64, + ) { + let bundle = SpendBundle::from_bytes( + &read(format!("../../test-bundles/{filename}.bundle")).expect("read file"), + ) + .expect("parse bundle"); + + let mut a = make_allocator(LIMIT_HEAP); + let conditions = + get_conditions_from_spendbundle(&mut a, &bundle, cost, height, &TEST_CONSTANTS) + .expect("get_conditions_from_spendbundle"); + + assert_eq!(conditions.spends.len(), spends); + let create_coins = conditions + .spends + .iter() + .fold(0, |sum, spend| sum + spend.create_coin.len()); + assert_eq!(create_coins, additions); + assert_eq!(conditions.cost, cost); + } + + #[rstest] + #[case("bb13")] + #[case("e3c0")] + fn test_get_conditions_from_spendbundle_fast_forward( + #[case] filename: &str, + #[values(0, 1, 1_000_000, 5_000_000)] height: u32, + ) { + let cost = 2_125_866; + let spend = CoinSpend::from_bytes( + &read(format!("../../ff-tests/{filename}.spend")).expect("read file"), + ) + .expect("parse Spend"); + + let bundle = SpendBundle::new(vec![spend], Signature::default()); + + let mut a = make_allocator(LIMIT_HEAP); + let conditions = + get_conditions_from_spendbundle(&mut a, &bundle, cost, height, &TEST_CONSTANTS) + .expect("get_conditions_from_spendbundle"); + + assert_eq!(conditions.spends.len(), 1); + let spend = &conditions.spends[0]; + assert_eq!(spend.flags, ELIGIBLE_FOR_FF | ELIGIBLE_FOR_DEDUP); + assert_eq!(conditions.cost, cost); + } + + #[cfg(not(debug_assertions))] + use crate::gen::flags::{ALLOW_BACKREFS, ENABLE_MESSAGE_CONDITIONS}; + + #[cfg(not(debug_assertions))] + const DEFAULT_FLAGS: u32 = ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS | MEMPOOL_MODE; + + // given a block generator and block-refs, convert run the generator to + // produce the SpendBundle for the block without runningi, or validating, + // the puzzles. + #[cfg(not(debug_assertions))] + fn convert_block_to_bundle(generator: &[u8], block_refs: &[Vec]) -> SpendBundle { + use crate::gen::run_block_generator::extract_n; + use crate::gen::run_block_generator::setup_generator_args; + use crate::gen::validation_error::ErrorCode; + use chia_protocol::Coin; + use clvmr::op_utils::first; + use clvmr::serde::node_from_bytes_backrefs; + use clvmr::serde::node_to_bytes; + + let mut a = make_allocator(DEFAULT_FLAGS); + + let generator = node_from_bytes_backrefs(&mut a, generator).expect("node_from_bytes"); + let args = setup_generator_args(&mut a, block_refs).expect("setup_generator_args"); + let dialect = ChiaDialect::new(DEFAULT_FLAGS); + let Reduction(_, mut all_spends) = + run_program(&mut a, &dialect, generator, args, 11_000_000_000).expect("run_program"); - let solution = hex!("ffff31ffb0997cc43ed8788f841fcf3071f6f212b89ba494b6ebaf1bda88c3f9de9d968a61f3b7284a5ee13889399ca71a026549a2ff8568656c6c6f8080").to_vec(); - // ((49 0x997cc43ed8788f841fcf3071f6f212b89ba494b6ebaf1bda88c3f9de9d968a61f3b7284a5ee13889399ca71a026549a2 "hello")) + all_spends = first(&a, all_spends).expect("first"); - let spend = CoinSpend::new(test_coin, Program::new(vec![1_u8].into()), solution.into()); + let mut spends = Vec::::new(); - let coin_spends: Vec = vec![spend]; - let spend_bundle = SpendBundle { - coin_spends, - aggregated_signature: Signature::default(), + // at this point all_spends is a list of: + // (parent-coin-id puzzle-reveal amount solution . extra) + // where extra may be nil, or additional extension data + while let Some((spend, rest)) = a.next(all_spends) { + all_spends = rest; + // process the spend + let [parent_id, puzzle, amount, solution, _spend_level_extra] = + extract_n::<5>(&a, spend, ErrorCode::InvalidCondition).expect("extract_n"); + + spends.push(CoinSpend::new( + Coin::new( + a.atom(parent_id).as_ref().try_into().expect("parent_id"), + tree_hash(&a, puzzle).into(), + a.number(amount).try_into().expect("amount"), + ), + node_to_bytes(&a, puzzle).expect("node_to_bytes").into(), + node_to_bytes(&a, solution).expect("node_to_bytes").into(), + )); + } + SpendBundle::new(spends, Signature::default()) + } + + #[cfg(not(debug_assertions))] + #[rstest] + #[case("new-agg-sigs")] + #[case("infinity-g1")] + #[case("block-1ee588dc")] + #[case("block-6fe59b24")] + #[case("block-b45268ac")] + #[case("block-c2a8df0d")] + #[case("block-e5002df2")] + #[case("block-4671894")] + #[case("block-225758")] + #[case("assert-puzzle-announce-fail")] + #[case("block-834752")] + #[case("block-834752-compressed")] + #[case("block-834760")] + #[case("block-834761")] + #[case("block-834765")] + #[case("block-834766")] + #[case("block-834768")] + #[case("create-coin-different-amounts")] + #[case("create-coin-hint-duplicate-outputs")] + #[case("create-coin-hint")] + #[case("create-coin-hint2")] + #[case("deep-recursion-plus")] + #[case("double-spend")] + #[case("duplicate-coin-announce")] + #[case("duplicate-create-coin")] + #[case("duplicate-height-absolute-div")] + #[case("duplicate-height-absolute-substr-tail")] + #[case("duplicate-height-absolute-substr")] + #[case("duplicate-height-absolute")] + #[case("duplicate-height-relative")] + #[case("duplicate-outputs")] + #[case("duplicate-reserve-fee")] + #[case("duplicate-seconds-absolute")] + #[case("duplicate-seconds-relative")] + #[case("height-absolute-ladder")] + //#[case("infinite-recursion1")] + //#[case("infinite-recursion2")] + //#[case("infinite-recursion3")] + //#[case("infinite-recursion4")] + #[case("invalid-conditions")] + #[case("just-puzzle-announce")] + #[case("many-create-coin")] + #[case("many-large-ints-negative")] + #[case("many-large-ints")] + #[case("max-height")] + #[case("multiple-reserve-fee")] + #[case("negative-reserve-fee")] + //#[case("recursion-pairs")] + #[case("unknown-condition")] + #[case("duplicate-messages")] + fn run_generator(#[case] name: &str) { + use crate::gen::run_block_generator::run_block_generator; + use crate::gen::test_generators::{print_conditions, print_diff}; + use std::fs::read_to_string; + + let filename = format!("../../generator-tests/{name}.txt"); + println!("file: {filename}"); + let test_file = read_to_string(filename).expect("test file not found"); + let (generator, expected) = test_file.split_once('\n').expect("invalid test file"); + let generator_buffer = hex::decode(generator).expect("invalid hex encoded generator"); + + let expected = match expected.split_once("STRICT:\n") { + Some((_, m)) => m, + None => expected, + }; + + let mut block_refs = Vec::>::new(); + + let filename = format!("../../generator-tests/{name}.env"); + if let Ok(env_hex) = read_to_string(&filename) { + println!("block-ref file: {filename}"); + block_refs.push(hex::decode(env_hex).expect("hex decode env-file")); + } + + let bundle = convert_block_to_bundle(&generator_buffer, &block_refs); + + // run the whole block through run_block_generator() to ensure the + // output conditions match and update the cost. The cost + // of just the spend bundle will be lower + let (block_cost, block_output) = { + let mut a = make_allocator(DEFAULT_FLAGS); + let block_conds = run_block_generator::<_, MempoolVisitor, _>( + &mut a, + &generator_buffer, + &block_refs, + 11_000_000_000, + DEFAULT_FLAGS, + &TEST_CONSTANTS, + ); + match block_conds { + Ok(ref conditions) => (conditions.cost, print_conditions(&a, &conditions)), + Err(code) => { + println!("error: {code:?}"); + (0, format!("FAILED: {}\n", u32::from(code.1))) + } + } }; - let osbc = get_conditions_from_spendbundle( - &spend_bundle, - TEST_CONSTANTS.max_block_cost_clvm, - 236, + + let mut a = make_allocator(LIMIT_HEAP); + let conds = get_conditions_from_spendbundle( + &mut a, + &bundle, + 11_000_000_000, + 5_000_000, &TEST_CONSTANTS, - ) - .expect("test should pass"); + ); + + let output = match conds { + Ok(mut conditions) => { + // the cost of running the spend bundle should never be higher + // than the whole block but it's likely less. + println!("block_cost: {block_cost}"); + println!("bundle_cost: {}", conditions.cost); + assert!(conditions.cost <= block_cost); + assert!(conditions.cost > 0); + // update the cost we print here, just to be compatible with + // the test cases we have. We've already ensured the cost is + // lower + conditions.cost = block_cost; + print_conditions(&a, &conditions) + } + Err(code) => { + println!("error: {code:?}"); + format!("FAILED: {}\n", u32::from(code.1)) + } + }; + + if output != block_output { + print_diff(&output, &block_output); + panic!("run_block_generator produced a different result than get_conditions_from_spendbundle()"); + } - assert!(osbc.spends.len() == 1); - assert!(osbc.agg_sig_unsafe.len() == 1); + if output != expected { + print_diff(&output, expected); + panic!("mismatching condition output"); + } } } diff --git a/wheel/src/api.rs b/wheel/src/api.rs index f6127c8b0..7ab98ef3c 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -366,13 +366,16 @@ pub fn py_get_conditions_from_spendbundle( constants: &ConsensusConstants, height: u32, ) -> PyResult { - let osbc = get_conditions_from_spendbundle(spend_bundle, max_cost, height, constants).map_err( - |e| { - let error_code: u32 = e.1.into(); - PyErr::new::(error_code) - }, - )?; - Ok(osbc) + use chia_consensus::allocator::make_allocator; + use chia_consensus::gen::owned_conditions::OwnedSpendBundleConditions; + let mut a = make_allocator(LIMIT_HEAP); + let conditions = + get_conditions_from_spendbundle(&mut a, spend_bundle, max_cost, height, constants) + .map_err(|e| { + let error_code: u32 = e.1.into(); + PyErr::new::(error_code) + })?; + Ok(OwnedSpendBundleConditions::from(&a, conditions)) } #[pyfunction] From 2613ac47205982435477fb11f4b37e7ddb7625d2 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 5 Aug 2024 10:57:36 +0100 Subject: [PATCH 11/15] paramterise test and use exact fork values --- .../src/spendbundle_validation.rs | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index 80c85ccdf..a5343e9a6 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -38,36 +38,17 @@ pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusCons mod tests { use super::*; use crate::consensus_constants::TEST_CONSTANTS; + use rstest::rstest; - #[test] - fn test_get_flags() { + #[rstest] + #[case(0, 0)] + #[case(TEST_CONSTANTS.hard_fork_height, 33_554_592)] + #[case(TEST_CONSTANTS.soft_fork4_height, 167_772_320)] + #[case(TEST_CONSTANTS.soft_fork5_height, 436_207_776)] + fn test_get_flags(#[case] height: u32, #[case] expected_value: u32) { assert_eq!( - get_flags_for_height_and_constants( - TEST_CONSTANTS.soft_fork4_height - 1, - &TEST_CONSTANTS - ), - 33_554_592 - ); - assert_eq!( - get_flags_for_height_and_constants( - TEST_CONSTANTS.soft_fork5_height - 1, - &TEST_CONSTANTS - ), - 167_772_320 - ); - assert_eq!( - get_flags_for_height_and_constants( - TEST_CONSTANTS.hard_fork_height - 1, - &TEST_CONSTANTS - ), - 0 - ); - assert_eq!( - get_flags_for_height_and_constants( - TEST_CONSTANTS.soft_fork5_height + 1, - &TEST_CONSTANTS - ), - 436_207_776 + get_flags_for_height_and_constants(height, &TEST_CONSTANTS), + expected_value ); } } From 296f78cafbd0d27d631e39b64771f0a4a2d59e38 Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 5 Aug 2024 16:03:35 +0100 Subject: [PATCH 12/15] use named flags for case definitions --- crates/chia-consensus/src/spendbundle_validation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index a5343e9a6..5569043be 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -42,9 +42,9 @@ mod tests { #[rstest] #[case(0, 0)] - #[case(TEST_CONSTANTS.hard_fork_height, 33_554_592)] - #[case(TEST_CONSTANTS.soft_fork4_height, 167_772_320)] - #[case(TEST_CONSTANTS.soft_fork5_height, 436_207_776)] + #[case(TEST_CONSTANTS.hard_fork_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS)] + #[case(TEST_CONSTANTS.soft_fork4_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS)] + #[case(TEST_CONSTANTS.soft_fork5_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS | DISALLOW_INFINITY_G1)] fn test_get_flags(#[case] height: u32, #[case] expected_value: u32) { assert_eq!( get_flags_for_height_and_constants(height, &TEST_CONSTANTS), From 8452eb3a396fb6a304c15c97fb66ab5f365111ed Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 5 Aug 2024 16:09:15 +0100 Subject: [PATCH 13/15] remove unnecessary 0 --- crates/chia-consensus/src/spendbundle_validation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index 5569043be..6f4d939e9 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -42,9 +42,9 @@ mod tests { #[rstest] #[case(0, 0)] - #[case(TEST_CONSTANTS.hard_fork_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS)] - #[case(TEST_CONSTANTS.soft_fork4_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS)] - #[case(TEST_CONSTANTS.soft_fork5_height, 0 | ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS | DISALLOW_INFINITY_G1)] + #[case(TEST_CONSTANTS.hard_fork_height, ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS)] + #[case(TEST_CONSTANTS.soft_fork4_height, ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS)] + #[case(TEST_CONSTANTS.soft_fork5_height, ENABLE_BLS_OPS_OUTSIDE_GUARD | ENABLE_FIXED_DIV | ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS | DISALLOW_INFINITY_G1)] fn test_get_flags(#[case] height: u32, #[case] expected_value: u32) { assert_eq!( get_flags_for_height_and_constants(height, &TEST_CONSTANTS), From 01cfdff4e5fe05a0001bae0a62f683eaedbd949e Mon Sep 17 00:00:00 2001 From: Matthew Howard Date: Mon, 5 Aug 2024 17:05:08 +0100 Subject: [PATCH 14/15] fix typestub incorrect name --- wheel/generate_type_stubs.py | 2 +- wheel/python/chia_rs/chia_rs.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wheel/generate_type_stubs.py b/wheel/generate_type_stubs.py index c8c9a952f..8c8ee653f 100644 --- a/wheel/generate_type_stubs.py +++ b/wheel/generate_type_stubs.py @@ -305,7 +305,7 @@ def confirm_not_included_already_hashed( proof: bytes, ) -> bool: ... -def get_name_puzzle_conditions( +def get_conditions_from_spendbundle( spend_bundle: SpendBundle, max_cost: int, constants: ConsensusConstants, diff --git a/wheel/python/chia_rs/chia_rs.pyi b/wheel/python/chia_rs/chia_rs.pyi index 686c99d43..4fc806c61 100644 --- a/wheel/python/chia_rs/chia_rs.pyi +++ b/wheel/python/chia_rs/chia_rs.pyi @@ -49,7 +49,7 @@ def confirm_not_included_already_hashed( proof: bytes, ) -> bool: ... -def get_name_puzzle_conditions( +def get_conditions_from_spendbundle( spend_bundle: SpendBundle, max_cost: int, constants: ConsensusConstants, From 81f111262be552b30ed5be0f0d19314a3a33b7b8 Mon Sep 17 00:00:00 2001 From: Rigidity Date: Mon, 5 Aug 2024 13:41:41 -0400 Subject: [PATCH 15/15] Only pass coin spends to get_conditions_from_spendbundle --- .../src/spendbundle_conditions.rs | 38 +++++++++++++------ wheel/src/api.rs | 17 ++++++--- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs index 55fd9051f..bfe57b538 100644 --- a/crates/chia-consensus/src/spendbundle_conditions.rs +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -1,3 +1,5 @@ +use std::borrow::Borrow; + use crate::consensus_constants::ConsensusConstants; use crate::gen::conditions::{ process_single_spend, validate_conditions, MempoolVisitor, ParseState, SpendBundleConditions, @@ -6,7 +8,7 @@ use crate::gen::flags::MEMPOOL_MODE; use crate::gen::run_block_generator::subtract_cost; use crate::gen::validation_error::ValidationErr; use crate::spendbundle_validation::get_flags_for_height_and_constants; -use chia_protocol::SpendBundle; +use chia_protocol::CoinSpend; use clvm_utils::tree_hash; use clvmr::allocator::Allocator; use clvmr::chia_dialect::ChiaDialect; @@ -16,7 +18,7 @@ use clvmr::serde::node_from_bytes; pub fn get_conditions_from_spendbundle( a: &mut Allocator, - spend_bundle: &SpendBundle, + coin_spends: impl IntoIterator>, max_cost: u64, height: u32, constants: &ConsensusConstants, @@ -30,7 +32,9 @@ pub fn get_conditions_from_spendbundle( let mut ret = SpendBundleConditions::default(); let mut state = ParseState::default(); - for coin_spend in &spend_bundle.coin_spends { + for coin_spend in coin_spends { + let coin_spend = coin_spend.borrow(); + // process the spend let puz = node_from_bytes(a, coin_spend.puzzle_reveal.as_slice())?; let sol = node_from_bytes(a, coin_spend.solution.as_slice())?; @@ -70,7 +74,7 @@ mod tests { use crate::allocator::make_allocator; use crate::gen::conditions::{ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF}; use chia_bls::Signature; - use chia_protocol::CoinSpend; + use chia_protocol::{CoinSpend, SpendBundle}; use chia_traits::Streamable; use clvmr::chia_dialect::LIMIT_HEAP; use rstest::rstest; @@ -83,7 +87,7 @@ mod tests { #[case] filename: &str, #[case] spends: usize, #[case] additions: usize, - #[values(0, 1, 1000000, 5000000)] height: u32, + #[values(0, 1, 1_000_000, 5_000_000)] height: u32, #[case] cost: u64, ) { let bundle = SpendBundle::from_bytes( @@ -92,9 +96,14 @@ mod tests { .expect("parse bundle"); let mut a = make_allocator(LIMIT_HEAP); - let conditions = - get_conditions_from_spendbundle(&mut a, &bundle, cost, height, &TEST_CONSTANTS) - .expect("get_conditions_from_spendbundle"); + let conditions = get_conditions_from_spendbundle( + &mut a, + &bundle.coin_spends, + cost, + height, + &TEST_CONSTANTS, + ) + .expect("get_conditions_from_spendbundle"); assert_eq!(conditions.spends.len(), spends); let create_coins = conditions @@ -121,9 +130,14 @@ mod tests { let bundle = SpendBundle::new(vec![spend], Signature::default()); let mut a = make_allocator(LIMIT_HEAP); - let conditions = - get_conditions_from_spendbundle(&mut a, &bundle, cost, height, &TEST_CONSTANTS) - .expect("get_conditions_from_spendbundle"); + let conditions = get_conditions_from_spendbundle( + &mut a, + &bundle.coin_spends, + cost, + height, + &TEST_CONSTANTS, + ) + .expect("get_conditions_from_spendbundle"); assert_eq!(conditions.spends.len(), 1); let spend = &conditions.spends[0]; @@ -287,7 +301,7 @@ mod tests { let mut a = make_allocator(LIMIT_HEAP); let conds = get_conditions_from_spendbundle( &mut a, - &bundle, + &bundle.coin_spends, 11_000_000_000, 5_000_000, &TEST_CONSTANTS, diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 7ab98ef3c..c1913f5d5 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -369,12 +369,17 @@ pub fn py_get_conditions_from_spendbundle( use chia_consensus::allocator::make_allocator; use chia_consensus::gen::owned_conditions::OwnedSpendBundleConditions; let mut a = make_allocator(LIMIT_HEAP); - let conditions = - get_conditions_from_spendbundle(&mut a, spend_bundle, max_cost, height, constants) - .map_err(|e| { - let error_code: u32 = e.1.into(); - PyErr::new::(error_code) - })?; + let conditions = get_conditions_from_spendbundle( + &mut a, + &spend_bundle.coin_spends, + max_cost, + height, + constants, + ) + .map_err(|e| { + let error_code: u32 = e.1.into(); + PyErr::new::(error_code) + })?; Ok(OwnedSpendBundleConditions::from(&a, conditions)) }