Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pass ParseState by reference into validate_conditions() #738

Merged
merged 1 commit into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 31 additions & 41 deletions crates/chia-consensus/src/gen/conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,7 +1260,7 @@ pub fn parse_spends<V: SpendVisitor>(
)?;
}

validate_conditions(a, &ret, state, spends, flags)?;
validate_conditions(a, &ret, &state, spends, flags)?;
ret.cost = max_cost - cost_left;

Ok(ret)
Expand All @@ -1269,7 +1269,7 @@ pub fn parse_spends<V: SpendVisitor>(
pub fn validate_conditions(
a: &Allocator,
ret: &SpendBundleConditions,
state: ParseState,
state: &ParseState,
spends: NodePtr,
_flags: u32,
) -> Result<(), ValidationErr> {
Expand Down Expand Up @@ -1309,13 +1309,13 @@ pub fn validate_conditions(
}

// check concurrent spent assertions
for coin_id in state.assert_concurrent_spend {
for coin_id in &state.assert_concurrent_spend {
if !state
.spent_coins
.contains_key(&Bytes32::try_from(a.atom(coin_id).as_ref()).unwrap())
.contains_key(&Bytes32::try_from(a.atom(*coin_id).as_ref()).unwrap())
{
return Err(ValidationErr(
coin_id,
*coin_id,
ErrorCode::AssertConcurrentSpendFailed,
));
}
Expand All @@ -1326,14 +1326,14 @@ pub fn validate_conditions(

// expand all the spent puzzle hashes into a set, to allow
// fast lookups of all assertions
for ph in state.spent_puzzles {
spent_phs.insert(a.atom(ph).as_ref().try_into().unwrap());
for ph in &state.spent_puzzles {
spent_phs.insert(a.atom(*ph).as_ref().try_into().unwrap());
}

for puzzle_assert in state.assert_concurrent_puzzle {
if !spent_phs.contains(&a.atom(puzzle_assert).as_ref().try_into().unwrap()) {
for puzzle_assert in &state.assert_concurrent_puzzle {
if !spent_phs.contains(&a.atom(*puzzle_assert).as_ref().try_into().unwrap()) {
return Err(ValidationErr(
puzzle_assert,
*puzzle_assert,
ErrorCode::AssertConcurrentPuzzleFailed,
));
}
Expand All @@ -1345,41 +1345,41 @@ pub fn validate_conditions(
if !state.assert_coin.is_empty() {
let mut announcements = HashSet::<Bytes32>::new();

for (coin_id, announce) in state.announce_coin {
for (coin_id, announce) in &state.announce_coin {
let mut hasher = Sha256::new();
hasher.update(*coin_id);
hasher.update(a.atom(announce));
hasher.update(**coin_id);
hasher.update(a.atom(*announce));
let announcement_id: [u8; 32] = hasher.finalize();
announcements.insert(announcement_id.into());
}

for coin_assert in state.assert_coin {
if !announcements.contains(&a.atom(coin_assert).as_ref().try_into().unwrap()) {
for coin_assert in &state.assert_coin {
if !announcements.contains(&a.atom(*coin_assert).as_ref().try_into().unwrap()) {
return Err(ValidationErr(
coin_assert,
*coin_assert,
ErrorCode::AssertCoinAnnouncementFailed,
));
}
}
}

for spend_idx in state.assert_ephemeral {
for spend_idx in &state.assert_ephemeral {
// make sure this coin was created in this block
if !is_ephemeral(a, spend_idx, &state.spent_coins, &ret.spends) {
if !is_ephemeral(a, *spend_idx, &state.spent_coins, &ret.spends) {
return Err(ValidationErr(
ret.spends[spend_idx].parent_id,
ret.spends[*spend_idx].parent_id,
ErrorCode::AssertEphemeralFailed,
));
}
}

for spend_idx in state.assert_not_ephemeral {
for spend_idx in &state.assert_not_ephemeral {
// make sure this coin was NOT created in this block
// because consensus rules do not allow relative conditions on
// ephemeral spends
if is_ephemeral(a, spend_idx, &state.spent_coins, &ret.spends) {
if is_ephemeral(a, *spend_idx, &state.spent_coins, &ret.spends) {
return Err(ValidationErr(
ret.spends[spend_idx].parent_id,
ret.spends[*spend_idx].parent_id,
ErrorCode::EphemeralRelativeCondition,
));
}
Expand All @@ -1388,18 +1388,18 @@ pub fn validate_conditions(
if !state.assert_puzzle.is_empty() {
let mut announcements = HashSet::<Bytes32>::new();

for (puzzle_hash, announce) in state.announce_puzzle {
for (puzzle_hash, announce) in &state.announce_puzzle {
let mut hasher = Sha256::new();
hasher.update(a.atom(puzzle_hash));
hasher.update(a.atom(announce));
hasher.update(a.atom(*puzzle_hash));
hasher.update(a.atom(*announce));
let announcement_id: [u8; 32] = hasher.finalize();
announcements.insert(announcement_id.into());
}

for puzzle_assert in state.assert_puzzle {
if !announcements.contains(&a.atom(puzzle_assert).as_ref().try_into().unwrap()) {
for puzzle_assert in &state.assert_puzzle {
if !announcements.contains(&a.atom(*puzzle_assert).as_ref().try_into().unwrap()) {
return Err(ValidationErr(
puzzle_assert,
*puzzle_assert,
ErrorCode::AssertPuzzleAnnouncementFailed,
));
}
Expand Down Expand Up @@ -1434,19 +1434,6 @@ pub fn validate_conditions(
Ok(())
}

#[cfg(test)]
pub(crate) fn u64_to_bytes(n: u64) -> Vec<u8> {
let mut buf = Vec::<u8>::new();
buf.extend_from_slice(&n.to_be_bytes());
if (buf[0] & 0x80) != 0 {
buf.insert(0, 0);
} else {
while buf.len() > 1 && buf[0] == 0 && (buf[1] & 0x80) == 0 {
buf.remove(0);
}
}
buf
}
#[cfg(test)]
use crate::consensus_constants::TEST_CONSTANTS;
#[cfg(test)]
Expand Down Expand Up @@ -1521,6 +1508,9 @@ const LONGMSG: &[u8; 1025] = &[
4,
];

#[cfg(test)]
use crate::gen::make_aggsig_final_message::u64_to_bytes;

#[cfg(test)]
fn hash_buf(b1: &[u8], b2: &[u8]) -> Vec<u8> {
let mut ctx = Sha256::new();
Expand Down
9 changes: 6 additions & 3 deletions crates/chia-consensus/src/gen/flags.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use clvmr::MEMPOOL_MODE as CLVM_MEMPOOL_MODE;

// flags controlling to condition parsing
// flags controlling the condition parsing
// These flags are combined in the same fields as clvm_rs flags, controlling the
// CLVM execution. To avoid clashes, CLVM flags are in the lower two bytes and
// condition parsing and validation flags are in the top two bytes.

// unknown condition codes are disallowed
pub const NO_UNKNOWN_CONDS: u32 = 0x20000;
pub const NO_UNKNOWN_CONDS: u32 = 0x2_0000;

// With this flag, conditions will require the exact number of arguments
// currently supported for those conditions. This is meant for mempool-mode
pub const STRICT_ARGS_COUNT: u32 = 0x80000;
pub const STRICT_ARGS_COUNT: u32 = 0x8_0000;

// when this flag is set, the block generator serialization is allowed to
// contain back-references
Expand Down
2 changes: 1 addition & 1 deletion crates/chia-consensus/src/gen/get_puzzle_and_solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ pub fn get_puzzle_and_solution_for_coin(
mod test {
use super::*;
use crate::consensus_constants::TEST_CONSTANTS;
use crate::gen::conditions::u64_to_bytes;
use crate::gen::flags::{ALLOW_BACKREFS, MEMPOOL_MODE};
use crate::gen::make_aggsig_final_message::u64_to_bytes;
use crate::gen::run_block_generator::{run_block_generator2, setup_generator_args};
use chia_protocol::Bytes32;
use clvm_traits::FromClvm;
Expand Down
7 changes: 3 additions & 4 deletions crates/chia-consensus/src/gen/make_aggsig_final_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::gen::opcodes::{
AGG_SIG_PARENT_PUZZLE, AGG_SIG_PUZZLE, AGG_SIG_PUZZLE_AMOUNT,
};
use crate::gen::owned_conditions::OwnedSpendConditions;
use chia_protocol::Bytes;
use chia_protocol::Coin;

pub fn make_aggsig_final_message(
Expand Down Expand Up @@ -51,13 +50,13 @@ pub fn make_aggsig_final_message(
}
}

fn u64_to_bytes(val: u64) -> Bytes {
pub fn u64_to_bytes(val: u64) -> Vec<u8> {
let amount_bytes: [u8; 8] = val.to_be_bytes();
if val >= 0x8000_0000_0000_0000_u64 {
let mut ret = Vec::<u8>::new();
ret.push(0_u8);
ret.extend(amount_bytes);
Bytes::new(ret)
ret
} else {
let start = match val {
n if n >= 0x0080_0000_0000_0000_u64 => 0,
Expand All @@ -70,7 +69,7 @@ fn u64_to_bytes(val: u64) -> Bytes {
n if n > 0 => 7,
_ => 8,
};
Bytes::new(amount_bytes[start..].to_vec())
amount_bytes[start..].to_vec()
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/chia-consensus/src/gen/run_block_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ where
return Err(ValidationErr(all_spends, ErrorCode::GeneratorRuntimeError));
}

validate_conditions(a, &ret, state, a.nil(), flags)?;
validate_conditions(a, &ret, &state, a.nil(), flags)?;

ret.cost = max_cost - cost_left;
Ok(ret)
Expand Down
2 changes: 1 addition & 1 deletion crates/chia-consensus/src/spendbundle_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ 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;
Ok(ret)
Expand Down
2 changes: 1 addition & 1 deletion crates/chia-consensus/src/spendbundle_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub fn get_flags_for_height_and_constants(height: u32, constants: &ConsensusCons
mod tests {
use super::*;
use crate::consensus_constants::TEST_CONSTANTS;
use crate::gen::conditions::u64_to_bytes;
use crate::gen::make_aggsig_final_message::u64_to_bytes;
use chia_bls::{sign, G2Element, SecretKey, Signature};
use chia_protocol::{Bytes, Bytes32};
use chia_protocol::{Coin, CoinSpend, Program};
Expand Down