Skip to content

Commit

Permalink
add new coinid operator under softfork guard (extension 0)
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Apr 24, 2023
1 parent 3a245a6 commit 95fe193
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 26 deletions.
35 changes: 27 additions & 8 deletions src/chia_dialect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::cost::Cost;
use crate::dialect::{Dialect, Extension};
use crate::err_utils::err;
use crate::more_ops::{
op_add, op_all, op_any, op_ash, op_concat, op_div, op_divmod, op_gr, op_gr_bytes, op_logand,
op_logior, op_lognot, op_logxor, op_lsh, op_multiply, op_not, op_point_add, op_pubkey_for_exp,
op_sha256, op_strlen, op_substr, op_subtract, op_unknown,
op_add, op_all, op_any, op_ash, op_coinid, op_concat, op_div, op_divmod, op_gr, op_gr_bytes,
op_logand, op_logior, op_lognot, op_logxor, op_lsh, op_multiply, op_not, op_point_add,
op_pubkey_for_exp, op_sha256, op_strlen, op_substr, op_subtract, op_unknown,
};
use crate::reduction::Response;

Expand All @@ -21,6 +21,10 @@ pub const LIMIT_HEAP: u32 = 0x0004;
// When set, enforce a stack size limit for CLVM programs
pub const LIMIT_STACK: u32 = 0x0008;

// When set, we allow softfork with extension 0 (which includes coinid and the
// BLS operators)
pub const ENABLE_BLS_OPS: u32 = 0x0010;

// The default mode when running grnerators in mempool-mode (i.e. the stricter
// mode)
pub const MEMPOOL_MODE: u32 = NO_UNKNOWN_OPS | LIMIT_HEAP | LIMIT_STACK;
Expand Down Expand Up @@ -56,7 +60,7 @@ impl Dialect for ChiaDialect {
o: NodePtr,
argument_list: NodePtr,
max_cost: Cost,
_extensions: Extension,
extensions: Extension,
) -> Response {
let b = &allocator.atom(o);
if b.len() != 1 {
Expand Down Expand Up @@ -99,10 +103,18 @@ impl Dialect for ChiaDialect {
34 => op_all,
// 35 ---
// 36 = softfork
_ => {
// new extension opcodes go here
return unknown_operator(allocator, o, argument_list, self.flags, max_cost);
}
_ => match extensions {
Extension::BLS => match b[0] {
48 => op_coinid,
// TODO: add BLS operators here
_ => {
return unknown_operator(allocator, o, argument_list, self.flags, max_cost);
}
},
_ => {
return unknown_operator(allocator, o, argument_list, self.flags, max_cost);
}
},
};
f(allocator, argument_list, max_cost)
}
Expand All @@ -121,6 +133,13 @@ impl Dialect for ChiaDialect {

fn softfork_extension(&self, ext: u32) -> Extension {
match ext {
0 => {
if (self.flags & ENABLE_BLS_OPS) == 0 {
Extension::None
} else {
Extension::BLS
}
}
// new extensions go here
_ => Extension::None,
}
Expand Down
3 changes: 2 additions & 1 deletion src/dialect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::reduction::Response;
#[repr(u32)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Extension {
None = 0,
None,
BLS,
}

pub trait Dialect {
Expand Down
46 changes: 46 additions & 0 deletions src/more_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ const PUBKEY_BASE_COST: Cost = 1325730;
// increased from 12 to closer model Raspberry PI
const PUBKEY_COST_PER_BYTE: Cost = 38;

// the new coinid operator
const COINID_COST: Cost =
SHA256_BASE_COST + SHA256_COST_PER_ARG * 3 + SHA256_COST_PER_BYTE * (32 + 32 + 8);

fn limbs_for_int(v: &Number) -> usize {
((v.bits() + 7) / 8) as usize
}
Expand Down Expand Up @@ -860,3 +864,45 @@ pub fn op_point_add(a: &mut Allocator, input: NodePtr, max_cost: Cost) -> Respon
let total: G1Affine = total.into();
new_atom_and_cost(a, cost, &total.to_compressed())
}

pub fn op_coinid(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
let args = Node::new(a, input);
check_arg_count(&args, 3, "coinid")?;

let parent_coin = atom(args.first()?, "coinid")?;
if parent_coin.len() != 32 {
return args.err("coinid: invalid parent coin id (must be 32 bytes)");
}
let args = args.rest()?;
let puzzle_hash = atom(args.first()?, "coinid")?;
if puzzle_hash.len() != 32 {
return args.err("coinid: invalid puzzle hash (must be 32 bytes)");
}
let args = args.rest()?;
let amount = atom(args.first()?, "coinid")?;
if !amount.is_empty() {
if (amount[0] & 0x80) != 0 {
return args.err("coinid: invalid amount (may not be negative");
}
if amount == [0_u8] || (amount.len() > 1 && amount[0] == 0 && (amount[1] & 0x80) == 0) {
return args.err("coinid: invalid amount (may not have redundant leading zero)");
}
// the only valid coin value that's 9 bytes is when a leading zero is
// required to not have the value interpreted as negative
if amount.len() > 9 || (amount.len() == 9 && amount[0] != 0) {
return args.err("coinid: invalid amount (may not exceed max coin amount)");
}
}

let mut hasher = Sha256::new();
hasher.update(parent_coin);
hasher.update(puzzle_hash);
hasher.update(amount);
let ret: [u8; 32] = hasher
.finalize()
.as_slice()
.try_into()
.expect("sha256 hash is not 32 bytes");
let ret = a.new_atom(&ret)?;
Ok(Reduction(COINID_COST, ret))
}
92 changes: 78 additions & 14 deletions src/run_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,8 @@ struct RunProgramTest {
#[cfg(test)]
use crate::test_ops::parse_exp;

#[cfg(test)]
use crate::chia_dialect::ENABLE_BLS_OPS;
#[cfg(test)]
use crate::chia_dialect::NO_UNKNOWN_OPS;

Expand Down Expand Up @@ -922,7 +924,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 979))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -938,7 +940,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 959) (q . 9))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -954,7 +956,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 939) (q . 9) (q x))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -972,7 +974,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 919) (q . 9) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -981,7 +983,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 0x00000397) (q . 9) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -999,7 +1001,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 919) (q . 0x00ffffffff) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -1017,7 +1019,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 919) (q . -1) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -1035,7 +1037,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 919) (q . 0x0100000000) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -1053,7 +1055,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 919) (q 1 2 3) (q x) (q . ()))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1000,
err: "",
Expand All @@ -1071,7 +1073,7 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . 1000))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: None,
cost: 1000,
err: "cost exceeded",
Expand All @@ -1080,15 +1082,15 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork)",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: None,
cost: 0,
err: "first of non-cons",
},
RunProgramTest {
prg: "(softfork (q . 0))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: None,
cost: 1000,
err: "cost must be > 0",
Expand All @@ -1097,19 +1099,81 @@ const TEST_CASES: &[RunProgramTest] = &[
RunProgramTest {
prg: "(softfork (q . -1))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: None,
cost: 1000,
err: "softfork requires positive int arg",
},
RunProgramTest {
prg: "(softfork (q 1 2 3))",
args: "()",
flags: 0,
flags: ENABLE_BLS_OPS,
result: None,
cost: 1000,
err: "softfork requires int arg",
},

// test mismatching cost
RunProgramTest {
prg: "(softfork (q . 160) (q . 0) (q . (q . 42)) (q . ()))",
args: "()",
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 241,
err: "",
},
// the program under the softfork is restricted by the specified cost
RunProgramTest {
prg: "(softfork (q . 159) (q . 0) (q . (q . 42)) (q . ()))",
args: "()",
flags: ENABLE_BLS_OPS,
result: None,
cost: 241,
err: "cost exceeded",
},
// the cost specified on the softfork must match exactly the cost of
// executing the program
RunProgramTest {
prg: "(softfork (q . 161) (q . 0) (q . (q . 42)) (q . ()))",
args: "()",
flags: ENABLE_BLS_OPS,
result: None,
cost: 10000,
err: "softfork specified cost mismatch",
},

// without the flag to enable the BLS extensions, it's an unknown extension
RunProgramTest {
prg: "(softfork (q . 161) (q . 0) (q . (q . 42)) (q . ()))",
args: "()",
flags: NO_UNKNOWN_OPS,
result: None,
cost: 10000,
err: "unknown softfork extension",
},

// coinid extension
// make sure we can execute the coinid operator under softfork 0
// this program raises an exception if the computed coin ID matches the
// expected
RunProgramTest {
prg: "(softfork (q . 1265) (q . 0) (q a (i (= (coinid (q . 0x1234500000000000000000000000000000000000000000000000000000000000) (q . 0x6789abcdef000000000000000000000000000000000000000000000000000000) (q . 123456789)) (q . 0x69bfe81b052bfc6bd7f3fb9167fec61793175b897c16a35827f947d5cc98e4bc)) (q x) (q . 0)) (q . ())) (q . ()))",
args: "()",
flags: ENABLE_BLS_OPS,
result: None,
cost: 1346,
err: "clvm raise",
},
// also test the opposite. This program is the same as above but it raises
// if the coin ID is a mismatch
RunProgramTest {
prg: "(softfork (q . 1265) (q . 0) (q a (i (= (coinid (q . 0x1234500000000000000000000000000000000000000000000000000000000000) (q . 0x6789abcdef000000000000000000000000000000000000000000000000000000) (q . 123456789)) (q . 0x69bfe81b052bfc6bd7f3fb9167fec61793175b897c16a35827f947d5cc98e4bc)) (q . 0) (q x)) (q . ())) (q . ()))",
args: "()",
flags: ENABLE_BLS_OPS,
result: Some("()"),
cost: 1346,
err: "",
},
];

#[cfg(test)]
Expand Down
Loading

0 comments on commit 95fe193

Please sign in to comment.