diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index d1c4d986..aadb4cf3 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -153,7 +153,7 @@ jobs: # Check that recompiling deployed puzzles match with their deployed hashes cp support/install_deps.sh support/verify_compiler_version.sh chia-blockchain - (cd chia-blockchain && python -m venv venv && . venv/bin/activate && pip install --upgrade pip && \ + (cd chia-blockchain && python -m venv .venv && . .venv/bin/activate && pip install --upgrade pip && \ python -m pip install maturin==1.1.0 && \ cd .. && pip install --no-index --find-links target/wheels/ clvm_tools_rs && \ cd chia-blockchain && \ diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 3bc3e1a7..53a3bbdd 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -21,4 +21,5 @@ jobs: - name: "Dependency Review" uses: actions/dependency-review-action@v4 with: + allow-dependencies-licenses: pkg:pypi/pylint, pkg:pypi/pyinstaller deny-licenses: AGPL-1.0-only, AGPL-1.0-or-later, AGPL-1.0-or-later, AGPL-3.0-or-later, GPL-1.0-only, GPL-1.0-or-later, GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later diff --git a/resources/tests/lz.bin b/resources/tests/lz.bin new file mode 100644 index 00000000..bdc955b7 Binary files /dev/null and b/resources/tests/lz.bin differ diff --git a/src/classic/clvm/mod.rs b/src/classic/clvm/mod.rs index 0c54c008..bb269fa5 100644 --- a/src/classic/clvm/mod.rs +++ b/src/classic/clvm/mod.rs @@ -20,7 +20,7 @@ struct KwAtomPair { version: usize, } -const KW_PAIRS: [KwAtomPair; 46] = [ +const KW_PAIRS: [KwAtomPair; 48] = [ KwAtomPair { v: &[0x01], n: "q", @@ -241,6 +241,16 @@ const KW_PAIRS: [KwAtomPair; 46] = [ n: "bls_verify", version: 1, }, + KwAtomPair { + v: &[0x3c], + n: "modpow", + version: 1, + }, + KwAtomPair { + v: &[0x3d], + n: "%", + version: 1, + }, KwAtomPair { v: &[0x13, 0xd6, 0x1f, 0x00], n: "secp256k1_verify", diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 9438415d..ee1ea3bf 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -383,23 +383,26 @@ fn yamlette_string(to_print: &[BTreeMap]) -> String { } } -pub fn cldb_hierarchy( - runner: Rc, - prim_map: Rc, Rc>>, - input_file_name: Option, - lines: Rc>, - symbol_table: Rc>, - prog: Rc, - args: Rc, -) -> Vec> { +pub struct CldbHierarchyArgs { + pub runner: Rc, + pub prim_map: Rc, Rc>>, + pub input_file_name: Option, + pub lines: Rc>, + pub symbol_table: Rc>, + pub prog: Rc, + pub args: Rc, + pub flags: u32, +} + +pub fn cldb_hierarchy(args: CldbHierarchyArgs) -> Vec> { let mut runner = HierarchialRunner::new( - runner, - prim_map, - input_file_name, - lines, - symbol_table, - prog, - args, + args.runner, + args.prim_map, + args.input_file_name, + args.lines, + args.symbol_table, + args.prog, + args.args, ); let mut output_stack = vec![Vec::new()]; @@ -434,7 +437,7 @@ pub fn cldb_hierarchy( ); let mut arg_values = BTreeMap::new(); for (k, v) in runner.running[run_idx].named_args.iter() { - arg_values.insert(k.clone(), YamlElement::String(format!("{v}"))); + arg_values.insert(k.clone(), YamlElement::String(format!("{}", v.clone()))); } function_entry.insert( "Function-Args".to_string(), @@ -722,15 +725,16 @@ pub fn cldb(args: &[String]) { ); if parsed_args.contains_key("tree") { - let result = cldb_hierarchy( + let result = cldb_hierarchy(CldbHierarchyArgs { runner, - Rc::new(prim_map), - input_file, - program_lines, - Rc::new(use_symbol_table), - program, + prim_map: Rc::new(prim_map), + input_file_name: input_file, + lines: program_lines, + symbol_table: Rc::new(use_symbol_table), + prog: program, args, - ); + flags: 0, + }); // Print the tree let string_result = yamlette_string(&result); diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 5af5be38..707ce160 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -689,7 +689,11 @@ impl Preprocessor { .read_new_file(self.opts.filename(), fname.to_string())?; let content = if let IncludeProcessType::Bin = &kind { - Rc::new(SExp::Atom(loc.clone(), content)) + if self.opts.dialect().int_fix { + Rc::new(SExp::QuotedString(loc.clone(), b'x', content)) + } else { + Rc::new(SExp::Atom(loc.clone(), content)) + } } else if let IncludeProcessType::Hex = &kind { hex_to_modern_sexp( &mut allocator, diff --git a/src/compiler/prims.rs b/src/compiler/prims.rs index 8a30023b..4b51554c 100644 --- a/src/compiler/prims.rs +++ b/src/compiler/prims.rs @@ -187,6 +187,14 @@ pub fn prims() -> Vec<(Vec, SExp)> { "bls_verify".as_bytes().to_vec(), SExp::Integer(primloc.clone(), 59_u32.to_bigint().unwrap()), ), + ( + "modpow".as_bytes().to_vec(), + SExp::Integer(primloc.clone(), 60_u32.to_bigint().unwrap()), + ), + ( + "%".as_bytes().to_vec(), + SExp::Integer(primloc.clone(), 61_u32.to_bigint().unwrap()), + ), ( "secp256k1_verify".as_bytes().to_vec(), SExp::Integer(primloc.clone(), 0x13d61f00.to_bigint().unwrap()), diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 4f9635b9..a8acc5ea 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -275,8 +275,18 @@ fn normalize_int(v: Vec, base: u32) -> Number { // left to retain their sign and hex constants are considered unsigned so _not_ // padded. fn from_hex(l: Srcloc, v: &[u8]) -> SExp { - let mut result = vec![0; (v.len() - 2) / 2]; - hex2bin(&v[2..], &mut result).expect("should convert from hex"); + let mut result = vec![0; (v.len() - 1) / 2]; + let mut hex_const; + // This assigns a new reference so the vec is copied only when we need + // to pad it. + let v_ref = if v.len() % 2 == 1 { + hex_const = v.to_vec(); + hex_const.insert(2, b'0'); + &hex_const[2..] + } else { + &v[2..] + }; + hex2bin(v_ref, &mut result).ok(); SExp::QuotedString(l, b'x', result) } diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index d0a0fd7f..f21ac8de 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -2518,3 +2518,70 @@ fn test_assign_cse_tricky_2() { let wanted_repr = "(2 (1 2 10 (4 2 (4 5 ()))) (4 (1 ((11 5 11) 2 8 (4 2 (4 5 (4 11 ())))) (2 22 (4 2 (4 3 (4 (18 5 (1 . 11)) (4 (16 5 (1 . 1)) ()))))) (2 30 (4 2 (4 3 (4 (1 . 121) ())))) 2 (3 (9 17 (1 . 13)) (1 2 12 (4 2 (4 45 (4 21 ())))) (1 2 (3 (9 17 (1 . 15)) (1 2 8 (4 2 (4 45 (4 21 ())))) (1 . 11)) 1)) 1) 1))"; assert_eq!(program, wanted_repr); } + +#[test] +fn test_classic_modpow() { + let result = do_basic_brun(&vec![ + "brun".to_string(), + "(modpow (q . 2) (q . 6) (q . 5))".to_string(), + ]); + // 64 % 5 == 4 + assert_eq!(result.trim(), "4"); +} + +#[test] +fn test_classic_mod_op() { + let result = do_basic_brun(&vec![ + "brun".to_string(), + "(% (q . 13) (q . 10))".to_string(), + ]); + // 13 % 10 == 3 + assert_eq!(result.trim(), "3"); +} + +#[test] +fn test_modern_modpow() { + let program = do_basic_run(&vec![ + "run".to_string(), + "(mod (X Y Z) (include *standard-cl-23*) (modpow X Y Z))".to_string(), + ]); + assert_eq!(program.trim(), "(60 2 5 11)"); + let result = do_basic_brun(&vec!["brun".to_string(), program, "(2 7 10)".to_string()]); + // 128 % 10 == 8 + assert_eq!(result.trim(), "8"); +} + +#[test] +fn test_modern_mod_op() { + let program = do_basic_run(&vec![ + "run".to_string(), + "(mod (X Y) (include *standard-cl-23*) (% X Y))".to_string(), + ]); + assert_eq!(program.trim(), "(61 2 5)"); + let result = do_basic_brun(&vec!["brun".to_string(), program, "(137 6)".to_string()]); + // 137 % 6 == 5 + assert_eq!(result.trim(), "5"); +} + +#[test] +fn test_include_zero_bin() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23.1*) (embed-file lz bin lz.bin) (concat 1 lz))" + .to_string(), + ]); + assert_eq!(program, "(2 (1 14 (1 . 1) 2) (4 (1 . 0x0001) 1))"); +} + +#[test] +fn test_include_zero_bin_pre_fix() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23*) (embed-file lz bin lz.bin) (concat 1 lz))".to_string(), + ]); + assert_eq!(program, "(2 (1 14 (1 . 1) 2) (4 (1 . 1) 1))"); +} diff --git a/src/tests/compiler/cldb.rs b/src/tests/compiler/cldb.rs index cb168cb9..af286994 100644 --- a/src/tests/compiler/cldb.rs +++ b/src/tests/compiler/cldb.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use clvmr::allocator::Allocator; -use crate::classic::clvm_tools::cmds::{cldb_hierarchy, YamlElement}; +use crate::classic::clvm_tools::cmds::{cldb_hierarchy, CldbHierarchyArgs, YamlElement}; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::cldb::{hex_to_modern_sexp, CldbNoOverride, CldbRun, CldbRunEnv}; use crate::compiler::clvm::{start_step, RunStep}; @@ -49,6 +49,7 @@ fn run_clvm_in_cldb( symbols: HashMap, args: Rc, viewer: &mut V, + flags: u32, ) -> Option where V: StepOfCldbViewer, @@ -67,6 +68,7 @@ where Box::new(CldbNoOverride::new_symbols(symbols)), ); let mut cldbrun = CldbRun::new(runner, Rc::new(prim_map), Box::new(cldbenv), step); + let mut output: BTreeMap = BTreeMap::new(); loop { @@ -118,6 +120,7 @@ fn test_run_clvm_in_cldb() { symbols, args, &mut DoesntWatchCldb {}, + 0, ), Some("120".to_string()) ); @@ -171,6 +174,7 @@ fn compile_and_run_program_with_tree( input_program_text: &str, args_text: &str, search_paths: &[String], + flags: u32, ) -> Vec> { let mut allocator = Allocator::new(); let runner = Rc::new(DefaultProgramRunner::new()); @@ -201,7 +205,7 @@ fn compile_and_run_program_with_tree( let program_lines: Rc> = Rc::new(input_program_text.lines().map(|x| x.to_string()).collect()); - cldb_hierarchy( + cldb_hierarchy(CldbHierarchyArgs { runner, Rc::new(prim_map), Some(input_file.to_owned()), @@ -209,7 +213,8 @@ fn compile_and_run_program_with_tree( Rc::new(use_symbol_table), Rc::new(program.to_sexp()), args, - ) + flags, + }) } fn run_program_as_tree_from_hex( @@ -244,15 +249,16 @@ fn run_program_as_tree_from_hex( } let program_lines = Rc::new(vec![]); let runner = Rc::new(DefaultProgramRunner::new()); - cldb_hierarchy( + cldb_hierarchy(CldbHierarchyArgs { runner, - Rc::new(prim_map), - Some(file_name.to_owned()), - program_lines, - Rc::new(symbol_table), - program, + prim_map: Rc::new(prim_map), + input_file_name: Some(file_name.to_owned()), + lines: program_lines, + symbol_table: Rc::new(symbol_table), + prog: program, args, - ) + flags: 0, + }) } fn compare_run_output( @@ -279,7 +285,8 @@ fn test_cldb_hierarchy_mode() { .expect("test resources should exist: test_rec_1.cl"); let input_file = "./test_rec_1.cl"; - let result = compile_and_run_program_with_tree(&input_file, &input_program, "(3 2)", &vec![]); + let result = + compile_and_run_program_with_tree(&input_file, &input_program, "(3 2)", &vec![], 0); compare_run_output(result, run_entries); } @@ -366,7 +373,8 @@ fn test_cldb_explicit_throw() { program, HashMap::new(), args, - &mut watcher + &mut watcher, + 0 ), None ); @@ -391,6 +399,7 @@ fn test_clvm_operator_with_weird_tail() { HashMap::new(), args, &mut DoesntWatchCldb {}, + 0, ), Some("8".to_string()) ); diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 40d0aade..87b0b17d 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -2534,3 +2534,13 @@ fn test_almost_empty_lambda_gives_error() { assert!(res.is_err()); assert!(format!("{res:?}").contains("Must provide at least arguments and body to lambda")); } + +#[test] +fn test_odd_hex_works() { + let res = run_string( + &"(mod () (include *standard-cl-23*) (+ 1 0xf))".to_string(), + &"()".to_string(), + ) + .expect("should work"); + assert_eq!(res.to_string(), "16"); +}