From bced560048c330437f641bf5f9526b8e157dcdf1 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Tue, 27 Aug 2024 20:46:10 +0100 Subject: [PATCH] Include the cost of the whole spend in get_conditions_from_spendbundle's return value. --- .../src/spendbundle_conditions.rs | 65 +++++++++++++++---- .../src/spendbundle_validation.rs | 15 +++-- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/crates/chia-consensus/src/spendbundle_conditions.rs b/crates/chia-consensus/src/spendbundle_conditions.rs index 95ac279d5..f52eedb84 100644 --- a/crates/chia-consensus/src/spendbundle_conditions.rs +++ b/crates/chia-consensus/src/spendbundle_conditions.rs @@ -4,6 +4,7 @@ use crate::gen::conditions::{ }; use crate::gen::flags::MEMPOOL_MODE; use crate::gen::run_block_generator::subtract_cost; +use crate::gen::solution_generator::solution_generator; use crate::gen::validation_error::ValidationErr; use crate::spendbundle_validation::get_flags_for_height_and_constants; use chia_protocol::SpendBundle; @@ -30,11 +31,13 @@ pub fn get_conditions_from_spendbundle( let mut ret = SpendBundleConditions::default(); let mut state = ParseState::default(); + let mut spends_info = Vec::new(); for coin_spend in &spend_bundle.coin_spends { - let byte_cost = (coin_spend.puzzle_reveal.len() + coin_spend.solution.len()) as u64 - * constants.cost_per_byte; - - subtract_cost(a, &mut cost_left, byte_cost)?; + spends_info.push(( + coin_spend.coin, + &coin_spend.puzzle_reveal, + &coin_spend.solution, + )); // process the spend let puz = node_from_bytes(a, coin_spend.puzzle_reveal.as_slice())?; @@ -61,6 +64,10 @@ pub fn get_conditions_from_spendbundle( )?; } + let spend_generator_length = solution_generator(spends_info)?.len(); + let byte_cost = spend_generator_length as u64 * constants.cost_per_byte; + subtract_cost(a, &mut cost_left, byte_cost)?; + validate_conditions(a, &ret, state, a.nil(), flags)?; assert!(max_cost >= cost_left); ret.cost = max_cost - cost_left; @@ -74,6 +81,7 @@ mod tests { use super::*; use crate::allocator::make_allocator; use crate::gen::conditions::{ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF}; + use crate::gen::run_block_generator::run_block_generator2; use chia_bls::Signature; use chia_protocol::CoinSpend; use chia_traits::Streamable; @@ -82,8 +90,8 @@ mod tests { use std::fs::read; #[rstest] - #[case("3000253", 8, 2, 46_860_870)] - #[case("1000101", 34, 15, 231_687_677)] + #[case("3000253", 8, 2, 51_240_870)] + #[case("1000101", 34, 15, 250_107_677)] fn test_get_conditions_from_spendbundle( #[case] filename: &str, #[case] spends: usize, @@ -108,6 +116,32 @@ mod tests { .fold(0, |sum, spend| sum + spend.create_coin.len()); assert_eq!(create_coins, additions); assert_eq!(conditions.cost, cost); + // Generate a block with the same spend bundle and compare its cost + let program_spends: Vec<_> = bundle + .coin_spends + .iter() + .map(|coin_spend| { + ( + coin_spend.coin, + &coin_spend.puzzle_reveal, + &coin_spend.solution, + ) + }) + .collect(); + let program = solution_generator(program_spends).expect("solution_generator failed"); + let blocks: &[&[u8]] = &[]; + let block_conds = run_block_generator2::<_, MempoolVisitor, _>( + &mut a, + program.as_slice(), + blocks, + 11_000_000_000, + MEMPOOL_MODE, + &TEST_CONSTANTS, + ) + .expect("run_block_generator2 failed"); + const QUOTE_COST: u64 = 20; + // run_block_generator2 wraps the probram in a quote + assert_eq!(conditions.cost, block_conds.cost - QUOTE_COST); } #[rstest] @@ -117,7 +151,7 @@ mod tests { #[case] filename: &str, #[values(0, 1, 1_000_000, 5_000_000)] height: u32, ) { - let cost = 76_825_866; + let cost = 77_365_866; let spend = CoinSpend::from_bytes( &read(format!("../../ff-tests/{filename}.spend")).expect("read file"), ) @@ -306,12 +340,21 @@ mod tests { // block will likely be smaller because the compression makes it // smaller. let block_byte_cost = generator_buffer.len() as u64 * TEST_CONSTANTS.cost_per_byte; - let bundle_byte_cost = bundle + let program_spends: Vec<_> = bundle .coin_spends .iter() - .map(|s| s.puzzle_reveal.len() + s.solution.len()) - .sum::() as u64 - * TEST_CONSTANTS.cost_per_byte; + .map(|coin_spend| { + ( + coin_spend.coin, + &coin_spend.puzzle_reveal, + &coin_spend.solution, + ) + }) + .collect(); + let spend_generator_length = solution_generator(program_spends) + .expect("solution_generator failed") + .len(); + let bundle_byte_cost = spend_generator_length as u64 * TEST_CONSTANTS.cost_per_byte; println!("block_cost: {block_cost} bytes: {block_byte_cost}"); println!("bundle_cost: {} bytes: {bundle_byte_cost}", conditions.cost); assert!(conditions.cost - bundle_byte_cost <= block_cost - block_byte_cost); diff --git a/crates/chia-consensus/src/spendbundle_validation.rs b/crates/chia-consensus/src/spendbundle_validation.rs index afb5a50c4..8b5a1f2d9 100644 --- a/crates/chia-consensus/src/spendbundle_validation.rs +++ b/crates/chia-consensus/src/spendbundle_validation.rs @@ -228,12 +228,15 @@ ff01\ coin_spends, aggregated_signature: G2Element::default(), }; - let result = validate_clvm_and_signature(&spend_bundle, 5526552044, &TEST_CONSTANTS, 236); - let Ok((conds, _, _)) = result else { - panic!("failed"); - }; - assert_eq!(conds.cost, 5526552044); - let result = validate_clvm_and_signature(&spend_bundle, 5526552043, &TEST_CONSTANTS, 236); + let expected_cost = 5_527_140_044; + let max_cost = expected_cost; + let test_height = 236; + let (conds, _, _) = + validate_clvm_and_signature(&spend_bundle, max_cost, &TEST_CONSTANTS, test_height) + .expect("validate_clvm_and_signature failed"); + assert_eq!(conds.cost, expected_cost); + let result = + validate_clvm_and_signature(&spend_bundle, max_cost - 1, &TEST_CONSTANTS, test_height); assert!(matches!(result, Err(ErrorCode::CostExceeded))); }