Skip to content

Commit

Permalink
Include the cost of the whole spend in get_conditions_from_spendbundl…
Browse files Browse the repository at this point in the history
…e's return value.
  • Loading branch information
AmineKhaldi committed Aug 29, 2024
1 parent e032f9d commit ebeb253
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 18 deletions.
79 changes: 67 additions & 12 deletions crates/chia-consensus/src/spendbundle_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,12 +31,21 @@ pub fn get_conditions_from_spendbundle(
let mut ret = SpendBundleConditions::default();
let mut state = ParseState::default();

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)?;
let spends_info = spend_bundle.coin_spends.iter().map(|coin_spend| {
(
coin_spend.coin,
&coin_spend.puzzle_reveal,
&coin_spend.solution,
)
});
// We don't pay the size cost (nor execution cost) of being wrapped by a
// quote (in solution_generator).
const QUOTE_BYTES: usize = 2;
let generator_length_without_quote = solution_generator(spends_info)?.len() - QUOTE_BYTES;
let byte_cost = generator_length_without_quote as u64 * constants.cost_per_byte;
subtract_cost(a, &mut cost_left, byte_cost)?;

for coin_spend in &spend_bundle.coin_spends {
// 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())?;
Expand Down Expand Up @@ -74,6 +84,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;
Expand All @@ -82,8 +93,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_216_870)]
#[case("1000101", 34, 15, 250_083_677)]
fn test_get_conditions_from_spendbundle(
#[case] filename: &str,
#[case] spends: usize,
Expand All @@ -108,6 +119,38 @@ 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");
// The cost difference here is because get_conditions_from_spendbundle
// uses solution_generator which wraps the program in a quote, and we
// don't pay the size cost nor execution cost for that there.
const QUOTE_EXECUTION_COST: u64 = 20;
const QUOTE_BYTE_COST: u64 = 2 * TEST_CONSTANTS.cost_per_byte;
assert_eq!(
conditions.cost,
block_conds.cost - QUOTE_EXECUTION_COST - QUOTE_BYTE_COST
);
}

#[rstest]
Expand All @@ -117,7 +160,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_341_866;
let spend = CoinSpend::from_bytes(
&read(format!("../../ff-tests/{filename}.spend")).expect("read file"),
)
Expand Down Expand Up @@ -306,12 +349,24 @@ 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::<usize>() as u64
* TEST_CONSTANTS.cost_per_byte;
.map(|coin_spend| {
(
coin_spend.coin,
&coin_spend.puzzle_reveal,
&coin_spend.solution,
)
})
.collect();
const QUOTE_BYTES: usize = 2;
let generator_length_without_quote = solution_generator(program_spends)
.expect("solution_generator failed")
.len()
- QUOTE_BYTES;
let bundle_byte_cost =
generator_length_without_quote 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);
Expand Down
15 changes: 9 additions & 6 deletions crates/chia-consensus/src/spendbundle_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_116_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)));
}

Expand Down

0 comments on commit ebeb253

Please sign in to comment.