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

enable message conditions unconditionally #644

Merged
merged 1 commit into from
Aug 8, 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
4 changes: 2 additions & 2 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-cond-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use chia_consensus::gen::conditions::parse_args;
use clvmr::allocator::Allocator;
use fuzzing_utils::{make_list, BitCursor};

use chia_consensus::gen::flags::{ENABLE_MESSAGE_CONDITIONS, STRICT_ARGS_COUNT};
use chia_consensus::gen::flags::STRICT_ARGS_COUNT;

use chia_consensus::gen::opcodes::{
AGG_SIG_AMOUNT, AGG_SIG_ME, AGG_SIG_PARENT, AGG_SIG_PARENT_AMOUNT, AGG_SIG_PARENT_PUZZLE,
Expand All @@ -20,7 +20,7 @@ fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_list(&mut a, &mut BitCursor::new(data));

for flags in &[0, STRICT_ARGS_COUNT, ENABLE_MESSAGE_CONDITIONS] {
for flags in &[0, STRICT_ARGS_COUNT] {
for op in &[
AGG_SIG_ME,
AGG_SIG_UNSAFE,
Expand Down
9 changes: 2 additions & 7 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use fuzzing_utils::{make_list, BitCursor};
use std::collections::HashSet;
use std::sync::Arc;

use chia_consensus::gen::flags::{ENABLE_MESSAGE_CONDITIONS, NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT};
use chia_consensus::gen::flags::{NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT};

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
Expand All @@ -40,12 +40,7 @@ fuzz_target!(|data: &[u8]| {

let mut state = ParseState::default();

for flags in &[
0,
STRICT_ARGS_COUNT,
NO_UNKNOWN_CONDS,
ENABLE_MESSAGE_CONDITIONS,
] {
for flags in &[0, STRICT_ARGS_COUNT, NO_UNKNOWN_CONDS] {
let mut coin_spend = Spend {
parent_id,
coin_amount: amount,
Expand Down
9 changes: 2 additions & 7 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-spends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@ use clvmr::{Allocator, NodePtr};
use fuzzing_utils::{make_list, BitCursor};

use chia_consensus::consensus_constants::TEST_CONSTANTS;
use chia_consensus::gen::flags::{ENABLE_MESSAGE_CONDITIONS, NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT};
use chia_consensus::gen::flags::{NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT};

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_list(&mut a, &mut BitCursor::new(data));
// spends is a list of spends
let input = a.new_pair(input, NodePtr::NIL).unwrap();
for flags in &[
0,
STRICT_ARGS_COUNT,
NO_UNKNOWN_CONDS,
ENABLE_MESSAGE_CONDITIONS,
] {
for flags in &[0, STRICT_ARGS_COUNT, NO_UNKNOWN_CONDS] {
let _ret =
parse_spends::<MempoolVisitor>(&a, input, 33_000_000_000, *flags, &TEST_CONSTANTS);
}
Expand Down
141 changes: 67 additions & 74 deletions crates/chia-consensus/src/gen/conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1722,9 +1722,6 @@ fn cond_test_cb(
#[cfg(test)]
use crate::gen::flags::MEMPOOL_MODE;

#[cfg(test)]
use crate::gen::flags::ENABLE_MESSAGE_CONDITIONS;

#[cfg(test)]
fn cond_test(input: &str) -> Result<(Allocator, SpendBundleConditions), ValidationErr> {
// by default, run all tests in strict mempool mode
Expand Down Expand Up @@ -1931,7 +1928,7 @@ fn test_message_strict_args_count(
&format!(
"((({{h1}} ({{h2}} (123 (((66 ({mode} ({msg} {arg} {extra1} ) ((67 ({mode} ({msg} {extra2} ) ))))"
),
flags | ENABLE_MESSAGE_CONDITIONS,
flags,
);
if flags == 0 {
ret.unwrap();
Expand Down Expand Up @@ -4676,29 +4673,28 @@ enum Ex {
#[case("(67 (0x12 ({msg1} ({coin12} )", Ex::Fail)]
#[case("(66 (0x12 ({msg1} ({coin12} )", Ex::Fail)]
fn test_message_conditions_single_spend(#[case] test_case: &str, #[case] expect: Ex) {
for flags in &[ENABLE_MESSAGE_CONDITIONS, MEMPOOL_MODE] {
let ret = cond_test_flag(&format!("((({{h1}} ({{h2}} (123 (({test_case}))))"), *flags);
let flags = MEMPOOL_MODE;
let ret = cond_test_flag(&format!("((({{h1}} ({{h2}} (123 (({test_case}))))"), flags);

let expect_pass = match expect {
Ex::Pass => true,
Ex::Fail => false,
};
let expect_pass = match expect {
Ex::Pass => true,
Ex::Fail => false,
};

if let Ok((a, conds)) = ret {
assert!(expect_pass);
assert_eq!(conds.cost, 0);
assert_eq!(conds.spends.len(), 1);
let spend = &conds.spends[0];
assert_eq!(*spend.coin_id, test_coin_id(H1, H2, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H2);
assert_eq!(spend.flags, 0);
} else if expect_pass {
panic!("failed: {:?}", ret.unwrap_err().1);
} else {
let actual_err = ret.unwrap_err().1;
println!("Error: {actual_err:?}");
assert_eq!(ErrorCode::MessageNotSentOrReceived, actual_err);
}
if let Ok((a, conds)) = ret {
assert!(expect_pass);
assert_eq!(conds.cost, 0);
assert_eq!(conds.spends.len(), 1);
let spend = &conds.spends[0];
assert_eq!(*spend.coin_id, test_coin_id(H1, H2, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H2);
assert_eq!(spend.flags, 0);
} else if expect_pass {
panic!("failed: {:?}", ret.unwrap_err().1);
} else {
let actual_err = ret.unwrap_err().1;
println!("Error: {actual_err:?}");
assert_eq!(ErrorCode::MessageNotSentOrReceived, actual_err);
}
}

Expand All @@ -4709,7 +4705,7 @@ fn test_message_conditions_single_spend(#[case] test_case: &str, #[case] expect:
fn test_limit_messages(#[case] count: i32, #[case] expect_err: Option<ErrorCode>) {
let r = cond_test_cb(
"((({h1} ({h1} (123 ({} )))",
ENABLE_MESSAGE_CONDITIONS,
0,
Some(Box::new(move |a: &mut Allocator| -> NodePtr {
let mut rest: NodePtr = a.nil();

Expand Down Expand Up @@ -4864,14 +4860,13 @@ fn test_limit_messages(#[case] count: i32, #[case] expect_err: Option<ErrorCode>
ErrorCode::CoinAmountNegative
)]
fn test_message_conditions_failures(#[case] test_case: &str, #[case] expect: ErrorCode) {
for flags in [ENABLE_MESSAGE_CONDITIONS, MEMPOOL_MODE] {
let ret = cond_test_flag(&format!("((({{h1}} ({{h2}} (123 (({test_case}))))"), flags);
let flags = MEMPOOL_MODE;
let ret = cond_test_flag(&format!("((({{h1}} ({{h2}} (123 (({test_case}))))"), flags);

let Err(ValidationErr(_, code)) = ret else {
panic!("expected failure: {expect:?}");
};
assert_eq!(code, expect);
}
let Err(ValidationErr(_, code)) = ret else {
panic!("expected failure: {expect:?}");
};
assert_eq!(code, expect);
}

#[cfg(test)]
Expand Down Expand Up @@ -5081,45 +5076,44 @@ fn test_message_conditions_two_spends(
#[case] coin2_case: &str,
#[case] expect: Ex,
) {
for flags in &[ENABLE_MESSAGE_CONDITIONS, MEMPOOL_MODE] {
let test = format!(
"(\
(({{h1}} ({{h2}} (123 (\
({coin1_case} \
))\
(({{h2}} ({{h1}} (123 (\
({coin2_case} \
))\
))"
);
let ret = cond_test_flag(&test, *flags);
let flags = MEMPOOL_MODE;
let test = format!(
"(\
(({{h1}} ({{h2}} (123 (\
({coin1_case} \
))\
(({{h2}} ({{h1}} (123 (\
({coin2_case} \
))\
))"
);
let ret = cond_test_flag(&test, flags);

let expect_pass = match expect {
Ex::Pass => true,
Ex::Fail => false,
};
let expect_pass = match expect {
Ex::Pass => true,
Ex::Fail => false,
};

if let Ok((a, conds)) = ret {
assert!(expect_pass);
assert_eq!(conds.cost, 0);
assert_eq!(conds.spends.len(), 2);

let spend = &conds.spends[0];
assert_eq!(*spend.coin_id, test_coin_id(H1, H2, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H2);
assert_eq!(spend.flags, 0);

let spend = &conds.spends[1];
assert_eq!(*spend.coin_id, test_coin_id(H2, H1, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H1);
assert_eq!(spend.flags, 0);
} else if expect_pass {
panic!("failed: {:?}", ret.unwrap_err().1);
} else {
let actual_err = ret.unwrap_err().1;
println!("Error: {actual_err:?}");
assert_eq!(ErrorCode::MessageNotSentOrReceived, actual_err);
}
if let Ok((a, conds)) = ret {
assert!(expect_pass);
assert_eq!(conds.cost, 0);
assert_eq!(conds.spends.len(), 2);

let spend = &conds.spends[0];
assert_eq!(*spend.coin_id, test_coin_id(H1, H2, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H2);
assert_eq!(spend.flags, 0);

let spend = &conds.spends[1];
assert_eq!(*spend.coin_id, test_coin_id(H2, H1, 123));
assert_eq!(a.atom(spend.puzzle_hash).as_ref(), H1);
assert_eq!(spend.flags, 0);
} else if expect_pass {
panic!("failed: {:?}", ret.unwrap_err().1);
} else {
let actual_err = ret.unwrap_err().1;
println!("Error: {actual_err:?}");
assert_eq!(ErrorCode::MessageNotSentOrReceived, actual_err);
}
}

Expand Down Expand Up @@ -5165,8 +5159,7 @@ fn test_all_message_conditions() {
))\
))"
);
let (a, conds) =
cond_test_flag(&test, ENABLE_MESSAGE_CONDITIONS).expect("condition expected to pass");
let (a, conds) = cond_test_flag(&test, 0).expect("condition expected to pass");

assert_eq!(conds.cost, 0);
assert_eq!(conds.spends.len(), 2);
Expand Down Expand Up @@ -5237,7 +5230,7 @@ fn test_message_eligible_for_ff() {
))"
);

let (_a, cond) = cond_test_flag(&test, ENABLE_MESSAGE_CONDITIONS).expect("cond_test");
let (_a, cond) = cond_test_flag(&test, 0).expect("cond_test");
assert!(cond.spends.len() == 2);
assert_eq!(
(cond.spends[0].flags & ELIGIBLE_FOR_FF) != 0,
Expand All @@ -5261,7 +5254,7 @@ fn test_message_eligible_for_ff() {
))"
);

let (_a, cond) = cond_test_flag(&test, ENABLE_MESSAGE_CONDITIONS).expect("cond_test");
let (_a, cond) = cond_test_flag(&test, 0).expect("cond_test");
assert!(cond.spends.len() == 2);
assert_eq!(
(cond.spends[0].flags & ELIGIBLE_FOR_FF) != 0,
Expand Down
4 changes: 0 additions & 4 deletions crates/chia-consensus/src/gen/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ pub const ALLOW_BACKREFS: u32 = 0x0200_0000;
// what features are detected of the spends
pub const ANALYZE_SPENDS: u32 = 0x0400_0000;

// This enables support for the new SEND_MESSAGE and RECEIVE_MESSAGE conditions
pub const ENABLE_MESSAGE_CONDITIONS: u32 = 0x0800_0000;

// When this flag is set, we reject AGG_SIG_* conditions whose public key is the
// infinity G1 point. Such public keys are mathematically valid, but do not
// provide any security guarantees. Chia has historically allowed them. Enabling
Expand All @@ -30,5 +27,4 @@ pub const MEMPOOL_MODE: u32 = CLVM_MEMPOOL_MODE
| NO_UNKNOWN_CONDS
| STRICT_ARGS_COUNT
| ANALYZE_SPENDS
| ENABLE_MESSAGE_CONDITIONS
| DISALLOW_INFINITY_G1;
56 changes: 8 additions & 48 deletions crates/chia-consensus/src/gen/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::gen::flags::ENABLE_MESSAGE_CONDITIONS;
use clvmr::allocator::{Allocator, NodePtr, SExp};
use clvmr::cost::Cost;

Expand Down Expand Up @@ -105,7 +104,7 @@ pub fn compute_unknown_condition_cost(op: ConditionOpcode) -> Cost {
}
}

pub fn parse_opcode(a: &Allocator, op: NodePtr, flags: u32) -> Option<ConditionOpcode> {
pub fn parse_opcode(a: &Allocator, op: NodePtr, _flags: u32) -> Option<ConditionOpcode> {
let buf = match a.sexp(op) {
SExp::Atom => a.atom(op),
SExp::Pair(..) => return None,
Expand Down Expand Up @@ -154,16 +153,10 @@ pub fn parse_opcode(a: &Allocator, op: NodePtr, flags: u32) -> Option<ConditionO
| AGG_SIG_AMOUNT
| AGG_SIG_PUZZLE_AMOUNT
| AGG_SIG_PARENT_AMOUNT
| AGG_SIG_PARENT_PUZZLE => Some(b0),
_ => {
if (flags & ENABLE_MESSAGE_CONDITIONS) != 0
&& [SEND_MESSAGE, RECEIVE_MESSAGE].contains(&b0)
{
Some(b0)
} else {
None
}
}
| AGG_SIG_PARENT_PUZZLE
| SEND_MESSAGE
| RECEIVE_MESSAGE => Some(b0),
_ => None,
}
} else {
None
Expand Down Expand Up @@ -215,10 +208,7 @@ use rstest::rstest;
fn test_parse_opcode(#[case] input: &[u8], #[case] expected: Option<ConditionOpcode>) {
let mut a = Allocator::new();
assert_eq!(opcode_tester(&mut a, input, 0), expected);
assert_eq!(
opcode_tester(&mut a, input, ENABLE_MESSAGE_CONDITIONS),
expected
);
assert_eq!(opcode_tester(&mut a, input, 0), expected);
}

#[cfg(test)]
Expand All @@ -236,43 +226,13 @@ fn test_parse_opcode(#[case] input: &[u8], #[case] expected: Option<ConditionOpc
#[case(&[AGG_SIG_PARENT_PUZZLE as u8], Some(AGG_SIG_PARENT_PUZZLE))]
#[case(&[ASSERT_EPHEMERAL as u8], Some(ASSERT_EPHEMERAL))]
#[case(&[ASSERT_BEFORE_SECONDS_RELATIVE as u8], Some(ASSERT_BEFORE_SECONDS_RELATIVE))]
#[case(&[SEND_MESSAGE as u8], None)]
#[case(&[RECEIVE_MESSAGE as u8], None)]
#[case(&[SEND_MESSAGE as u8], Some(SEND_MESSAGE))]
#[case(&[RECEIVE_MESSAGE as u8], Some(RECEIVE_MESSAGE))]
fn test_parse_opcode_softfork(#[case] input: &[u8], #[case] expected: Option<ConditionOpcode>) {
let mut a = Allocator::new();
assert_eq!(opcode_tester(&mut a, input, 0), expected);
}

#[cfg(test)]
#[rstest]
#[case(&[AGG_SIG_UNSAFE as u8], Some(AGG_SIG_UNSAFE), Some(AGG_SIG_UNSAFE))]
#[case(&[AGG_SIG_ME as u8], Some(AGG_SIG_ME), Some(AGG_SIG_ME))]
#[case(&[CREATE_COIN as u8], Some(CREATE_COIN), Some(CREATE_COIN))]
// the SOFTOFORK and new AGG_SIG_* condition is only recognized when the flag is set
#[case(&[SOFTFORK as u8], Some(SOFTFORK), Some(SOFTFORK))]
#[case(&[AGG_SIG_PARENT as u8], Some(AGG_SIG_PARENT), Some(AGG_SIG_PARENT))]
#[case(&[AGG_SIG_PUZZLE as u8], Some(AGG_SIG_PUZZLE), Some(AGG_SIG_PUZZLE))]
#[case(&[AGG_SIG_AMOUNT as u8], Some(AGG_SIG_AMOUNT), Some(AGG_SIG_AMOUNT))]
#[case(&[AGG_SIG_PUZZLE_AMOUNT as u8], Some(AGG_SIG_PUZZLE_AMOUNT), Some(AGG_SIG_PUZZLE_AMOUNT))]
#[case(&[AGG_SIG_PARENT_AMOUNT as u8], Some(AGG_SIG_PARENT_AMOUNT), Some(AGG_SIG_PARENT_AMOUNT))]
#[case(&[AGG_SIG_PARENT_PUZZLE as u8], Some(AGG_SIG_PARENT_PUZZLE), Some(AGG_SIG_PARENT_PUZZLE))]
#[case(&[ASSERT_EPHEMERAL as u8], Some(ASSERT_EPHEMERAL), Some(ASSERT_EPHEMERAL))]
#[case(&[ASSERT_BEFORE_SECONDS_RELATIVE as u8], Some(ASSERT_BEFORE_SECONDS_RELATIVE), Some(ASSERT_BEFORE_SECONDS_RELATIVE))]
#[case(&[SEND_MESSAGE as u8], None, Some(SEND_MESSAGE))]
#[case(&[RECEIVE_MESSAGE as u8], None, Some(RECEIVE_MESSAGE))]
fn test_parse_opcode_message(
#[case] input: &[u8],
#[case] expected: Option<ConditionOpcode>,
#[case] expected2: Option<ConditionOpcode>,
) {
let mut a = Allocator::new();
assert_eq!(opcode_tester(&mut a, input, 0), expected);
assert_eq!(
opcode_tester(&mut a, input, ENABLE_MESSAGE_CONDITIONS),
expected2
);
}

#[test]
fn test_parse_invalid_opcode() {
// a pair is never a valid condition
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-consensus/src/gen/test_generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::conditions::{MempoolVisitor, NewCoin, Spend, SpendBundleConditions};
use super::run_block_generator::{run_block_generator, run_block_generator2};
use crate::allocator::make_allocator;
use crate::consensus_constants::TEST_CONSTANTS;
use crate::gen::flags::{ALLOW_BACKREFS, ENABLE_MESSAGE_CONDITIONS, MEMPOOL_MODE};
use crate::gen::flags::{ALLOW_BACKREFS, MEMPOOL_MODE};
use chia_protocol::{Bytes, Bytes48};
use clvmr::allocator::NodePtr;
use clvmr::Allocator;
Expand Down Expand Up @@ -227,7 +227,7 @@ fn run_generator(#[case] name: &str) {
block_refs.push(hex::decode(env_hex).expect("hex decode env-file"));
}

const DEFAULT_FLAGS: u32 = ALLOW_BACKREFS | ENABLE_MESSAGE_CONDITIONS;
const DEFAULT_FLAGS: u32 = ALLOW_BACKREFS;
for (flags, expected) in zip(&[DEFAULT_FLAGS, DEFAULT_FLAGS | MEMPOOL_MODE], expected) {
println!("flags: {flags:x}");
let mut a = make_allocator(*flags);
Expand Down
Loading
Loading