diff --git a/.github/actions/setup-smplx/action.yml b/.github/actions/setup-smplx/action.yml index e118fdf..5b2eff4 100644 --- a/.github/actions/setup-smplx/action.yml +++ b/.github/actions/setup-smplx/action.yml @@ -17,6 +17,6 @@ runs: shell: bash run: | set -euo pipefail - REVISION="${{ inputs.commit-sha}}" + REVISION="${{ inputs.commit-sha }}" OWNER_REPO="${{ inputs.owner-repo }}" bash "$GITHUB_WORKSPACE/.github/scripts/setup-smplx" "${REVISION}" "${OWNER_REPO}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1d8ca2..2178d4a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,8 +46,6 @@ jobs: - name: Install simplex-cli uses: ./.github/actions/setup-smplx - with: - commit-sha: '3afcc04aae8a0a92722b28bc1d16ef27983d4aa1' - name: Generate contract artifacts shell: bash diff --git a/Cargo.lock b/Cargo.lock index 328caf1..d345b91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "ar_archive_writer" @@ -96,9 +96,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" dependencies = [ "aws-lc-sys", "zeroize", @@ -106,14 +106,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -288,12 +289,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] @@ -778,9 +779,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", @@ -924,6 +925,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1104,9 +1111,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] @@ -1280,8 +1287,9 @@ dependencies = [ [[package]] name = "simplicityhl" -version = "0.6.0-rc.0" -source = "git+https://github.com/BlockstreamResearch/SimplicityHL.git#4eb97f5dcb28d294f23bee15cb8f2e85027cd1f6" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361316795ec753230c421d964ab60940d20d5252c2d39272452528832c9e0ec5" dependencies = [ "base64 0.21.7", "chumsky", @@ -1312,8 +1320,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smplx-build" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f090cc306bc000e1f926d0fbbf92080626530095a3b4541caf8f6b8bedb0a62" dependencies = [ "glob", "globwalk", @@ -1330,8 +1339,9 @@ dependencies = [ [[package]] name = "smplx-macros" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6758957dde925b558d5453fbf39ca551ee3e0ae04b032686aa5444e695455595" dependencies = [ "smplx-build", "smplx-test", @@ -1340,8 +1350,9 @@ dependencies = [ [[package]] name = "smplx-regtest" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e96c8226c35603c08f37dda2fa319f4d822790c2f0d922d690a952399a4c92" dependencies = [ "electrsd", "hex", @@ -1355,13 +1366,14 @@ dependencies = [ [[package]] name = "smplx-sdk" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d02d154ff3b7459f86e60dd60edd693a7f60b91ba1ccb29c34be171796fce6" dependencies = [ "bip39", "bitcoin_hashes", + "bitcoincore-rpc", "dyn-clone", - "electrsd", "elements-miniscript", "hex", "minreq 3.0.0", @@ -1374,8 +1386,9 @@ dependencies = [ [[package]] name = "smplx-std" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d7cde217178eddb3f50572d2d728560388cc74899e38ca9aee0378f3d261db" dependencies = [ "either", "serde", @@ -1387,8 +1400,9 @@ dependencies = [ [[package]] name = "smplx-test" -version = "0.0.6" -source = "git+https://github.com/BlockstreamResearch/smplx.git?rev=3afcc04#3afcc04aae8a0a92722b28bc1d16ef27983d4aa1" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200a3f0cf072ffb8df5f841e478d7c46d5649d6d2f0487b5c72a0731d7c882a1" dependencies = [ "electrsd", "proc-macro2", @@ -1597,9 +1611,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -1610,9 +1624,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1620,9 +1634,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -1633,9 +1647,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] diff --git a/Cargo.toml b/Cargo.toml index 23aeac9..01718c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,7 @@ rust-version = "1.91.0" version = "0.1.0" [dependencies] -# todo: Replace git dependency with crates.io version that supports modules once available -smplx-std = { git = "https://github.com/BlockstreamResearch/smplx.git", rev = "3afcc04" } +smplx-std = "0.0.7" anyhow = { version = "1.0.101" } rand = { version = "0.8.6" } diff --git a/README.md b/README.md index c6ef5c7..209b95b 100644 --- a/README.md +++ b/README.md @@ -3,32 +3,22 @@ This repository contains the standard library for [SimplicityHL](https://github.com/BlockstreamResearch/SimplicityHL). > [!NOTE] -> If you are using the VS Code syntax highlighting extension, you may see errors because the extension does not support modules and imports yet. +> The VS Code syntax-highlighting extension does not yet support modules and imports, so you may see spurious errors when editing files in this repo. -## Dev Info -### Installation +## Installation -> Project currently uses Simplex version 0.0.6 from the dev branch. +> Project currently uses Simplex version `0.0.7`. -To compile the project, execute the following command: - -```bash -cargo build -``` - -To download simplexup, run: +Install `siplexup`, then use it to install the pinned Simplex toolchain: ```bash curl -L https://smplx.simplicity-lang.org | bash +simplexup ``` -To install a specific Simplex version (in this case from the specific commit): - -```bash -simplexup --commit 3afcc04aae8a0a92722b28bc1d16ef27983d4aa1 -``` +## Usage -### Compilation +### Build To compile the contracts, execute the following command: @@ -56,22 +46,21 @@ To run the tests using multiple threads: simplex test --test-threads 8 ``` -To run a specific test: +To run a specific test module: ```bash -simplex test test_name +simplex test u8_test ``` -### Linting - -To format the rust files, execute the following command: +To run a specific test: ```bash -cargo fmt +simplex test test_name ``` -To check the project for common mistakes: +### Lint & format ```bash +cargo fmt cargo clippy --workspace --all-targets --all-features -- -D warnings ``` diff --git a/Simplex.toml b/Simplex.toml index 1c78892..c522f64 100644 --- a/Simplex.toml +++ b/Simplex.toml @@ -1,10 +1,13 @@ -# Default Simplex Config +# DEFAULT CONFIG # [build] # src_dir = "./simf" # simf_files = ["*.simf"] # out_dir = "./src/artifacts" +# [dependencies] +# some_dep = { git = "", path = "" } + # [regtest] # mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean" # bitcoins = 10_000_000 @@ -16,6 +19,7 @@ # [test] # mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean" # bitcoins = 10_000_000 +# verbosity = 0 # [test.esplora] # url = "" diff --git a/simf/asserts_mock.simf b/simf/asserts_mock.simf deleted file mode 100644 index 32daeb6..0000000 --- a/simf/asserts_mock.simf +++ /dev/null @@ -1,102 +0,0 @@ -use crate::lib::asserts::{assert_eq_8, assert_eq_16, assert_eq_32, assert_eq_64, assert_eq_256, assert_none_8, assert_none_16, assert_none_32, assert_none_64,assert_none_128, assert_none_256}; - -use crate::helper::if_test_this_function; - -fn main() { - let function_index: u8 = witness::FUNCTION_INDEX; - - let first_arg_u8: Option = witness::FIRST_ARG_U8; - let second_arg_u8: Option = witness::SECOND_ARG_U8; - - let first_arg_u16: Option = witness::FIRST_ARG_U16; - let second_arg_u16: Option = witness::SECOND_ARG_U16; - - let first_arg_u32: Option = witness::FIRST_ARG_U32; - let second_arg_u32: Option = witness::SECOND_ARG_U32; - - let first_arg_u64: Option = witness::FIRST_ARG_U64; - let second_arg_u64: Option = witness::SECOND_ARG_U64; - - let first_arg_u128: Option = witness::FIRST_ARG_U128; - let second_arg_u128: Option = witness::SECOND_ARG_U128; - - let first_arg_u256: Option = witness::FIRST_ARG_U256; - let second_arg_u256: Option = witness::SECOND_ARG_U256; - - match if_test_this_function(0, function_index) { - true => { - assert_eq_8(unwrap(first_arg_u8), unwrap(second_arg_u8)); - }, - false => (), - }; - - match if_test_this_function(1, function_index) { - true => { - assert_eq_16(unwrap(first_arg_u16), unwrap(second_arg_u16)); - }, - false => (), - }; - - match if_test_this_function(2, function_index) { - true => { - assert_eq_32(unwrap(first_arg_u32), unwrap(second_arg_u32)); - }, - false => (), - }; - - match if_test_this_function(3, function_index) { - true => { - assert_eq_64(unwrap(first_arg_u64), unwrap(second_arg_u64)); - }, - false => (), - }; - - match if_test_this_function(4, function_index) { - true => { - assert_eq_256(unwrap(first_arg_u256), unwrap(second_arg_u256)); - }, - false => (), - }; - - match if_test_this_function(5, function_index) { - true => { - assert_none_8(first_arg_u8); - }, - false => (), - }; - - match if_test_this_function(6, function_index) { - true => { - assert_none_16(first_arg_u16); - }, - false => (), - }; - - match if_test_this_function(7, function_index) { - true => { - assert_none_32(first_arg_u32); - }, - false => (), - }; - - match if_test_this_function(8, function_index) { - true => { - assert_none_64(first_arg_u64); - }, - false => (), - }; - - match if_test_this_function(9, function_index) { - true => { - assert_none_128(first_arg_u128); - }, - false => (), - }; - - match if_test_this_function(10, function_index) { - true => { - assert_none_256(first_arg_u256); - }, - false => (), - }; -} diff --git a/simf/asserts_test.simf b/simf/asserts_test.simf new file mode 100644 index 0000000..c09675e --- /dev/null +++ b/simf/asserts_test.simf @@ -0,0 +1,39 @@ +use crate::lib::asserts::{assert_eq_8, assert_eq_16, assert_eq_32, assert_eq_64, assert_eq_256, assert_none_8, assert_none_16, assert_none_32, assert_none_64,assert_none_128, assert_none_256}; +use crate::helper::if_test_this_function; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a_u8: Option = witness::FIRST_ARG_U8; + let b_u8: Option = witness::SECOND_ARG_U8; + + let a_u16: Option = witness::FIRST_ARG_U16; + let b_u16: Option = witness::SECOND_ARG_U16; + + let a_u32: Option = witness::FIRST_ARG_U32; + let b_u32: Option = witness::SECOND_ARG_U32; + + let a_u64: Option = witness::FIRST_ARG_U64; + let b_u64: Option = witness::SECOND_ARG_U64; + + let a_u128: Option = witness::FIRST_ARG_U128; + let b_u128: Option = witness::SECOND_ARG_U128; + + let a_u256: Option = witness::FIRST_ARG_U256; + let b_u256: Option = witness::SECOND_ARG_U256; + + // Assert Eq + match if_test_this_function(0, fn_idx) { true => { assert_eq_8(unwrap(a_u8), unwrap(b_u8)); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert_eq_16(unwrap(a_u16), unwrap(b_u16)); }, false => (), }; + match if_test_this_function(2, fn_idx) { true => { assert_eq_32(unwrap(a_u32), unwrap(b_u32)); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert_eq_64(unwrap(a_u64), unwrap(b_u64)); }, false => (), }; + match if_test_this_function(4, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), }; + + // Assert None + match if_test_this_function(5, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; + match if_test_this_function(6, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; + match if_test_this_function(8, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; + match if_test_this_function(9, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; + match if_test_this_function(10, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; +} diff --git a/simf/logical_operations_mock.simf b/simf/logical_ops_test.simf similarity index 92% rename from simf/logical_operations_mock.simf rename to simf/logical_ops_test.simf index e428ec6..45e48e4 100644 --- a/simf/logical_operations_mock.simf +++ b/simf/logical_ops_test.simf @@ -2,7 +2,7 @@ use crate::lib::logical_operations::{not, or, and}; fn main() { assert!(not(false)); - assert!(not((not(true)))); + assert!(not(not(true))); assert!(or(true, false)); assert!(or(false, true)); diff --git a/simf/u16_mock.simf b/simf/u16_mock.simf deleted file mode 100644 index ffe58c0..0000000 --- a/simf/u16_mock.simf +++ /dev/null @@ -1,140 +0,0 @@ -use crate::lib::u16::{checked_add_16, safe_add_16, checked_sub_16, safe_sub_16, checked_mul_16, safe_mul_16, checked_div_16, safe_div_16}; - -use crate::helper::if_test_this_function; - -fn main() { - let function_index: u8 = witness::FUNCTION_INDEX; - let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; - - let first_arg: u16 = witness::FIRST_ARG; - let second_arg: u16 = witness::SECOND_ARG; - let result: u16 = witness::RESULT; - - // add - match if_test_this_function(0, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: Option = checked_add_16(first_arg, second_arg); - assert!(is_none::(overflowing_u16)); - }, - false => { - let fitting_u16: Option = checked_add_16(first_arg, second_arg); - assert!(jet::eq_16(unwrap(fitting_u16), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(1, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: u16 = safe_add_16(first_arg, second_arg); - }, - false => { - let fitting_u16: u16 = safe_add_16(first_arg, second_arg); - assert!(jet::eq_16(fitting_u16, result)); - } - } - }, - false => (), - }; - - // subtract - match if_test_this_function(2, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: Option = checked_sub_16(first_arg, second_arg); - assert!(is_none::(overflowing_u16)); - }, - false => { - let fitting_u16: Option = checked_sub_16(first_arg, second_arg); - assert!(jet::eq_16(unwrap(fitting_u16), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(3, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: u16 = safe_sub_16(first_arg, second_arg); - }, - false => { - let fitting_u16: u16 = safe_sub_16(first_arg, second_arg); - assert!(jet::eq_16(fitting_u16, result)); - } - } - }, - false => (), - }; - - // multiply - match if_test_this_function(4, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: Option = checked_mul_16(first_arg, second_arg); - assert!(is_none::(overflowing_u16)); - }, - false => { - let fitting_u16: Option = checked_mul_16(first_arg, second_arg); - assert!(jet::eq_16(unwrap(fitting_u16), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(5, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: u16 = safe_mul_16(first_arg, second_arg); - }, - false => { - let fitting_u16: u16 = safe_mul_16(first_arg, second_arg); - assert!(jet::eq_16(fitting_u16, result)); - } - } - }, - false => (), - }; - - // divide - match if_test_this_function(6, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: Option = checked_div_16(first_arg, second_arg); - assert!(is_none::(overflowing_u16)); - }, - false => { - let fitting_u16: Option = checked_div_16(first_arg, second_arg); - assert!(jet::eq_16(unwrap(fitting_u16), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(7, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u16: u16 = safe_div_16(first_arg, second_arg); - }, - false => { - let fitting_u16: u16 = safe_div_16(first_arg, second_arg); - assert!(jet::eq_16(fitting_u16, result)); - } - } - }, - false => (), - }; -} diff --git a/simf/u16_test.simf b/simf/u16_test.simf new file mode 100644 index 0000000..3a57f73 --- /dev/null +++ b/simf/u16_test.simf @@ -0,0 +1,37 @@ +use crate::lib::u16::{checked_add_16, safe_add_16, checked_sub_16, safe_sub_16, checked_mul_16, safe_mul_16, checked_div_16, safe_div_16}; +use crate::lib::asserts::{assert_none_16, assert_eq_16}; +use crate::helper::if_test_this_function; + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +fn assert_eq_opt(result: Option, expected: Option) { + match expected { + None => assert_none_16(result), + Some(e: u16) => assert_eq_16(unwrap(result), e), + } +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u16 = witness::FIRST_ARG; + let b: u16 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_16(a, b), expected); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_16(safe_add_16(a, b), unwrap(expected))); }, false => (), }; + + // sub + match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_16(a, b), expected); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_16(safe_sub_16(a, b), unwrap(expected))); }, false => (), }; + + // mul + match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_16(a, b), expected); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_16(safe_mul_16(a, b), unwrap(expected))); }, false => (), }; + + // div + match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_16(a, b), expected); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_16(safe_div_16(a, b), unwrap(expected))); }, false => (), }; +} diff --git a/simf/u32_mock.simf b/simf/u32_mock.simf deleted file mode 100644 index a1ae4b4..0000000 --- a/simf/u32_mock.simf +++ /dev/null @@ -1,140 +0,0 @@ -use crate::lib::u32::{checked_add_32, safe_add_32, checked_sub_32, safe_sub_32, checked_mul_32, safe_mul_32, checked_div_32, safe_div_32}; - -use crate::helper::if_test_this_function; - -fn main() { - let function_index: u8 = witness::FUNCTION_INDEX; - let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; - - let first_arg: u32 = witness::FIRST_ARG; - let second_arg: u32 = witness::SECOND_ARG; - let result: u32 = witness::RESULT; - - // add - match if_test_this_function(0, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: Option = checked_add_32(first_arg, second_arg); - assert!(is_none::(overflowing_u32)); - }, - false => { - let fitting_u32: Option = checked_add_32(first_arg, second_arg); - assert!(jet::eq_32(unwrap(fitting_u32), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(1, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: u32 = safe_add_32(first_arg, second_arg); - }, - false => { - let fitting_u32: u32 = safe_add_32(first_arg, second_arg); - assert!(jet::eq_32(fitting_u32, result)); - } - } - }, - false => (), - }; - - // subtract - match if_test_this_function(2, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: Option = checked_sub_32(first_arg, second_arg); - assert!(is_none::(overflowing_u32)); - }, - false => { - let fitting_u32: Option = checked_sub_32(first_arg, second_arg); - assert!(jet::eq_32(unwrap(fitting_u32), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(3, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: u32 = safe_sub_32(first_arg, second_arg); - }, - false => { - let fitting_u32: u32 = safe_sub_32(first_arg, second_arg); - assert!(jet::eq_32(fitting_u32, result)); - } - } - }, - false => (), - }; - - // multiply - match if_test_this_function(4, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: Option = checked_mul_32(first_arg, second_arg); - assert!(is_none::(overflowing_u32)); - }, - false => { - let fitting_u32: Option = checked_mul_32(first_arg, second_arg); - assert!(jet::eq_32(unwrap(fitting_u32), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(5, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: u32 = safe_mul_32(first_arg, second_arg); - }, - false => { - let fitting_u32: u32 = safe_mul_32(first_arg, second_arg); - assert!(jet::eq_32(fitting_u32, result)); - } - } - }, - false => (), - }; - - // divide - match if_test_this_function(6, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: Option = checked_div_32(first_arg, second_arg); - assert!(is_none::(overflowing_u32)); - }, - false => { - let fitting_u32: Option = checked_div_32(first_arg, second_arg); - assert!(jet::eq_32(unwrap(fitting_u32), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(7, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u32: u32 = safe_div_32(first_arg, second_arg); - }, - false => { - let fitting_u32: u32 = safe_div_32(first_arg, second_arg); - assert!(jet::eq_32(fitting_u32, result)); - } - } - }, - false => (), - }; -} diff --git a/simf/u32_test.simf b/simf/u32_test.simf new file mode 100644 index 0000000..6222ee8 --- /dev/null +++ b/simf/u32_test.simf @@ -0,0 +1,37 @@ +use crate::lib::u32::{checked_add_32, safe_add_32, checked_sub_32, safe_sub_32, checked_mul_32, safe_mul_32, checked_div_32, safe_div_32}; +use crate::lib::asserts::{assert_none_32, assert_eq_32}; +use crate::helper::if_test_this_function; + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +fn assert_eq_opt(result: Option, expected: Option) { + match expected { + None => assert_none_32(result), + Some(e: u32) => assert_eq_32(unwrap(result), e), + } +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u32 = witness::FIRST_ARG; + let b: u32 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_32(a, b), expected); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_32(safe_add_32(a, b), unwrap(expected))); }, false => (), }; + + // sub + match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_32(a, b), expected); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_32(safe_sub_32(a, b), unwrap(expected))); }, false => (), }; + + // mul + match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_32(a, b), expected); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_32(safe_mul_32(a, b), unwrap(expected))); }, false => (), }; + + // div + match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_32(a, b), expected); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_32(safe_div_32(a, b), unwrap(expected))); }, false => (), }; +} diff --git a/simf/u64_mock.simf b/simf/u64_mock.simf deleted file mode 100644 index 5f20922..0000000 --- a/simf/u64_mock.simf +++ /dev/null @@ -1,140 +0,0 @@ -use crate::lib::u64::{checked_add_64, safe_add_64, checked_sub_64, safe_sub_64, checked_mul_64, safe_mul_64, checked_div_64, safe_div_64}; - -use crate::helper::if_test_this_function; - -fn main() { - let function_index: u8 = witness::FUNCTION_INDEX; - let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; - - let first_arg: u64 = witness::FIRST_ARG; - let second_arg: u64 = witness::SECOND_ARG; - let result: u64 = witness::RESULT; - - // add - match if_test_this_function(0, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: Option = checked_add_64(first_arg, second_arg); - assert!(is_none::(overflowing_u64)); - }, - false => { - let fitting_u64: Option = checked_add_64(first_arg, second_arg); - assert!(jet::eq_64(unwrap(fitting_u64), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(1, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: u64 = safe_add_64(first_arg, second_arg); - }, - false => { - let fitting_u64: u64 = safe_add_64(first_arg, second_arg); - assert!(jet::eq_64(fitting_u64, result)); - } - } - }, - false => (), - }; - - // subtract - match if_test_this_function(2, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: Option = checked_sub_64(first_arg, second_arg); - assert!(is_none::(overflowing_u64)); - }, - false => { - let fitting_u64: Option = checked_sub_64(first_arg, second_arg); - assert!(jet::eq_64(unwrap(fitting_u64), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(3, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: u64 = safe_sub_64(first_arg, second_arg); - }, - false => { - let fitting_u64: u64 = safe_sub_64(first_arg, second_arg); - assert!(jet::eq_64(fitting_u64, result)); - } - } - }, - false => (), - }; - - // multiply - match if_test_this_function(4, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: Option = checked_mul_64(first_arg, second_arg); - assert!(is_none::(overflowing_u64)); - }, - false => { - let fitting_u64: Option = checked_mul_64(first_arg, second_arg); - assert!(jet::eq_64(unwrap(fitting_u64), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(5, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: u64 = safe_mul_64(first_arg, second_arg); - }, - false => { - let fitting_u64: u64 = safe_mul_64(first_arg, second_arg); - assert!(jet::eq_64(fitting_u64, result)); - } - } - }, - false => (), - }; - - // divide - match if_test_this_function(6, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: Option = checked_div_64(first_arg, second_arg); - assert!(is_none::(overflowing_u64)); - }, - false => { - let fitting_u64: Option = checked_div_64(first_arg, second_arg); - assert!(jet::eq_64(unwrap(fitting_u64), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(7, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u64: u64 = safe_div_64(first_arg, second_arg); - }, - false => { - let fitting_u64: u64 = safe_div_64(first_arg, second_arg); - assert!(jet::eq_64(fitting_u64, result)); - } - } - }, - false => (), - }; -} diff --git a/simf/u64_test.simf b/simf/u64_test.simf new file mode 100644 index 0000000..955d2c3 --- /dev/null +++ b/simf/u64_test.simf @@ -0,0 +1,37 @@ +use crate::lib::u64::{checked_add_64, safe_add_64, checked_sub_64, safe_sub_64, checked_mul_64, safe_mul_64, checked_div_64, safe_div_64}; +use crate::lib::asserts::{assert_none_64, assert_eq_64}; +use crate::helper::if_test_this_function; + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +fn assert_eq_opt(result: Option, expected: Option) { + match expected { + None => assert_none_64(result), + Some(e: u64) => assert_eq_64(unwrap(result), e), + } +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u64 = witness::FIRST_ARG; + let b: u64 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_64(a, b), expected); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_64(safe_add_64(a, b), unwrap(expected))); }, false => (), }; + + // sub + match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_64(a, b), expected); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_64(safe_sub_64(a, b), unwrap(expected))); }, false => (), }; + + // mul + match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_64(a, b), expected); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_64(safe_mul_64(a, b), unwrap(expected))); }, false => (), }; + + // div + match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_64(a, b), expected); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_64(safe_div_64(a, b), unwrap(expected))); }, false => (), }; + +} diff --git a/simf/u8_mock.simf b/simf/u8_mock.simf deleted file mode 100644 index d45fcd3..0000000 --- a/simf/u8_mock.simf +++ /dev/null @@ -1,140 +0,0 @@ -use crate::lib::u8::{checked_add_8, safe_add_8, checked_sub_8, safe_sub_8, checked_mul_8, safe_mul_8, checked_div_8, safe_div_8}; - -use crate::helper::if_test_this_function; - -fn main() { - let function_index: u8 = witness::FUNCTION_INDEX; - let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; - - let first_arg: u8 = witness::FIRST_ARG; - let second_arg: u8 = witness::SECOND_ARG; - let result: u8 = witness::RESULT; - - // add - match if_test_this_function(0, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: Option = checked_add_8(first_arg, second_arg); - assert!(is_none::(overflowing_u8)); - }, - false => { - let fitting_u8: Option = checked_add_8(first_arg, second_arg); - assert!(jet::eq_8(unwrap(fitting_u8), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(1, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: u8 = safe_add_8(first_arg, second_arg); - }, - false => { - let fitting_u8: u8 = safe_add_8(first_arg, second_arg); - assert!(jet::eq_8(fitting_u8, result)); - } - } - }, - false => (), - }; - - // subtract - match if_test_this_function(2, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: Option = checked_sub_8(first_arg, second_arg); - assert!(is_none::(overflowing_u8)); - }, - false => { - let fitting_u8: Option = checked_sub_8(first_arg, second_arg); - assert!(jet::eq_8(unwrap(fitting_u8), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(3, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: u8 = safe_sub_8(first_arg, second_arg); - }, - false => { - let fitting_u8: u8 = safe_sub_8(first_arg, second_arg); - assert!(jet::eq_8(fitting_u8, result)); - } - } - }, - false => (), - }; - - // multiply - match if_test_this_function(4, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: Option = checked_mul_8(first_arg, second_arg); - assert!(is_none::(overflowing_u8)); - }, - false => { - let fitting_u8: Option = checked_mul_8(first_arg, second_arg); - assert!(jet::eq_8(unwrap(fitting_u8), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(5, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: u8 = safe_mul_8(first_arg, second_arg); - }, - false => { - let fitting_u8: u8 = safe_mul_8(first_arg, second_arg); - assert!(jet::eq_8(fitting_u8, result)); - } - } - }, - false => (), - }; - - // divide - match if_test_this_function(6, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: Option = checked_div_8(first_arg, second_arg); - assert!(is_none::(overflowing_u8)); - }, - false => { - let fitting_u8: Option = checked_div_8(first_arg, second_arg); - assert!(jet::eq_8(unwrap(fitting_u8), result)); - } - } - }, - false => (), - }; - - match if_test_this_function(7, function_index) { - true => { - match if_test_overflow { - true => { - let overflowing_u8: u8 = safe_div_8(first_arg, second_arg); - }, - false => { - let fitting_u8: u8 = safe_div_8(first_arg, second_arg); - assert!(jet::eq_8(fitting_u8, result)); - } - } - }, - false => (), - }; -} diff --git a/simf/u8_test.simf b/simf/u8_test.simf new file mode 100644 index 0000000..dfd7b25 --- /dev/null +++ b/simf/u8_test.simf @@ -0,0 +1,37 @@ +use crate::lib::u8::{checked_add_8, safe_add_8, checked_sub_8, safe_sub_8, checked_mul_8, safe_mul_8, checked_div_8, safe_div_8}; +use crate::lib::asserts::{assert_none_8, assert_eq_8}; +use crate::helper::if_test_this_function; + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +fn assert_eq_opt(result: Option, expected: Option) { + match expected { + None => assert_none_8(result), + Some(e: u8) => assert_eq_8(unwrap(result), e), + } +} + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u8 = witness::FIRST_ARG; + let b: u8 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_8(a, b), expected); }, false => (), }; + match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_8(safe_add_8(a, b), unwrap(expected))); }, false => (), }; + + // sub + match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_8(a, b), expected); }, false => (), }; + match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_8(safe_sub_8(a, b), unwrap(expected))); }, false => (), }; + + // mul + match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_8(a, b), expected); }, false => (), }; + match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_8(safe_mul_8(a, b), unwrap(expected))); }, false => (), }; + + // div + match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_8(a, b), expected); }, false => (), }; + match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_8(safe_div_8(a, b), unwrap(expected))); }, false => (), }; +} diff --git a/tests/asserts_test.rs b/tests/asserts_test.rs index a13a988..5c2e82f 100644 --- a/tests/asserts_test.rs +++ b/tests/asserts_test.rs @@ -1,16 +1,16 @@ -use simplex::simplicityhl::elements::Script; +mod common; -use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; +use rand::Rng; -use simplicityhl_std::artifacts::asserts_mock::AssertsMockProgram; -use simplicityhl_std::artifacts::asserts_mock::derived_asserts_mock::{ - AssertsMockArguments, AssertsMockWitness, -}; - -mod helper; +use common::core::{Expect, run}; -use crate::helper::{cast_to_bool, generate_uints_in_one_range}; +use simplicityhl_std::artifacts::asserts_test::AssertsTestProgram; +use simplicityhl_std::artifacts::asserts_test::derived_asserts_test::{ + AssertsTestArguments, AssertsTestWitness, +}; +// Dispatch indices — must match the `if_test_this_function(N, ..)` arms in +// simf/asserts_test.simf. enum FunctionToTest { AssertEq8, AssertEq16, @@ -32,42 +32,36 @@ const DEFAULT_SOME_U64: Option = Some(0); const DEFAULT_SOME_U128: Option = Some(0); const DEFAULT_SOME_U256: Option<[u8; 32]> = Some([0; 32]); -pub enum IfTestSameValues { - DifferentValues, - SameValues, +fn program() -> AssertsTestProgram { + AssertsTestProgram::new(AssertsTestArguments {}) } -pub enum IfTestNoneValue { - NotNoneValue, - NoneValue, -} - -fn get_asserts_test_script(context: &simplex::TestContext) -> (AssertsMockProgram, Script) { - let arguments = AssertsMockArguments {}; - let asserts_program = AssertsMockProgram::new(arguments); +/// Returns two values in `[min, max]` that are equal when `same`, distinct otherwise. +pub fn generate_uints_in_one_range(same: bool, min_val: u128, max_val: u128) -> (u128, u128) { + let some_u = rand::thread_rng().gen_range(min_val..=max_val); - let asserts_script = asserts_program.get_script_pubkey(context.get_network()); - - (asserts_program, asserts_script) -} + if same { + return (some_u, some_u); + } -fn fund_script(context: &simplex::TestContext) -> anyhow::Result<()> { - let signer = context.get_default_signer(); + assert!( + min_val != max_val, + "cannot generate distinct values in a single-value range" + ); - let (_, asserts_script) = get_asserts_test_script(context); + let mut other_u = rand::thread_rng().gen_range(min_val..=max_val); - let tx_receipt = signer.send(asserts_script.clone(), 50)?; - println!("Broadcast: {}", tx_receipt); + while other_u == some_u { + other_u = rand::thread_rng().gen_range(min_val..=max_val); + } - Ok(()) + (some_u, other_u) } -fn generate_test_witness( - function_index: FunctionToTest, - if_same_values: bool, - if_none_value: bool, -) -> AssertsMockWitness { - let mut witness: AssertsMockWitness = AssertsMockWitness { +/// Builds the witness for one assert call. `same` controls the two `assert_eq` +/// args; `none` makes the single `assert_none` arg `None`. +fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTestWitness { + let mut witness = AssertsTestWitness { function_index: 0, first_arg_u8: DEFAULT_SOME_U8, second_arg_u8: DEFAULT_SOME_U8, @@ -83,500 +77,317 @@ fn generate_test_witness( second_arg_u256: DEFAULT_SOME_U256, }; - match function_index { + match function { FunctionToTest::AssertEq8 => { - let (first_arg, second_arg) = - generate_uints_in_one_range(if_same_values, 0, u8::MAX as u128); - - (witness.first_arg_u8, witness.second_arg_u8) = - (Some(first_arg as u8), Some(second_arg as u8)); + let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); + (witness.first_arg_u8, witness.second_arg_u8) = (Some(a as u8), Some(b as u8)); } FunctionToTest::AssertEq16 => { - let (first_arg, second_arg) = - generate_uints_in_one_range(if_same_values, 0, u16::MAX as u128); - - (witness.first_arg_u16, witness.second_arg_u16) = - (Some(first_arg as u16), Some(second_arg as u16)); + let (a, b) = generate_uints_in_one_range(same, 0, u16::MAX as u128); + (witness.first_arg_u16, witness.second_arg_u16) = (Some(a as u16), Some(b as u16)); } FunctionToTest::AssertEq32 => { - let (first_arg, second_arg) = - generate_uints_in_one_range(if_same_values, 0, u32::MAX as u128); - - (witness.first_arg_u32, witness.second_arg_u32) = - (Some(first_arg as u32), Some(second_arg as u32)); + let (a, b) = generate_uints_in_one_range(same, 0, u32::MAX as u128); + (witness.first_arg_u32, witness.second_arg_u32) = (Some(a as u32), Some(b as u32)); } FunctionToTest::AssertEq64 => { - let (first_arg, second_arg) = - generate_uints_in_one_range(if_same_values, 0, u64::MAX as u128); - - (witness.first_arg_u64, witness.second_arg_u64) = - (Some(first_arg as u64), Some(second_arg as u64)); + let (a, b) = generate_uints_in_one_range(same, 0, u64::MAX as u128); + (witness.first_arg_u64, witness.second_arg_u64) = (Some(a as u64), Some(b as u64)); } FunctionToTest::AssertEq256 => { - let (first_arg, second_arg) = - generate_uints_in_one_range(if_same_values, 0, u8::MAX as u128); - + let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); (witness.first_arg_u256, witness.second_arg_u256) = - (Some([first_arg as u8; 32]), Some([second_arg as u8; 32])); + (Some([a as u8; 32]), Some([b as u8; 32])); } FunctionToTest::AssertNone8 => { - if if_none_value { + if none { witness.first_arg_u8 = None; - }; + } } FunctionToTest::AssertNone16 => { - if if_none_value { + if none { witness.first_arg_u16 = None; - }; + } } FunctionToTest::AssertNone32 => { - if if_none_value { + if none { witness.first_arg_u32 = None; - }; + } } FunctionToTest::AssertNone64 => { - if if_none_value { + if none { witness.first_arg_u64 = None; - }; + } } FunctionToTest::AssertNone128 => { - if if_none_value { + if none { witness.first_arg_u128 = None; - }; + } } FunctionToTest::AssertNone256 => { - if if_none_value { + if none { witness.first_arg_u256 = None; - }; + } } } - witness.function_index = function_index as u8; + witness.function_index = function as u8; witness } -fn spend_script( +fn run_assert( context: &simplex::TestContext, - function_index: FunctionToTest, - if_same_values: IfTestSameValues, - if_none_value: IfTestNoneValue, + function: FunctionToTest, + same: bool, + none: bool, + expect: Expect, ) -> anyhow::Result<()> { - let signer = context.get_default_signer(); - let provider = context.get_default_provider(); - - let (asserts_program, asserts_script) = get_asserts_test_script(context); - - let asserts_utxos = provider.fetch_scripthash_utxos(&asserts_script)?; - - let mut ft = FinalTransaction::new(); - - let witness: AssertsMockWitness = generate_test_witness( - function_index, - cast_to_bool(if_same_values as u8), - cast_to_bool(if_none_value as u8), - ); - - ft.add_program_input( - PartialInput::new(asserts_utxos[0].clone()), - ProgramInput::new( - Box::new(asserts_program.as_ref().clone()), - Box::new(witness.clone()), - ), - RequiredSignature::None, - ); - - let tx_receipt = signer.broadcast(&ft)?; - println!("Broadcast: {}", tx_receipt); - - Ok(()) -} - -#[simplex::test] -fn assert_eq_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertEq8, - IfTestSameValues::SameValues, - IfTestNoneValue::NotNoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_eq_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertEq8, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_eq_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertEq16, - IfTestSameValues::SameValues, - IfTestNoneValue::NotNoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_eq_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertEq16, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_eq_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertEq32, - IfTestSameValues::SameValues, - IfTestNoneValue::NotNoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_eq_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertEq32, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_eq_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertEq64, - IfTestSameValues::SameValues, - IfTestNoneValue::NotNoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_eq_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertEq64, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_eq_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertEq256, - IfTestSameValues::SameValues, - IfTestNoneValue::NotNoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_eq_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertEq256, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_none_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - spend_script( - &context, - FunctionToTest::AssertNone8, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_none_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone8, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_none_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - spend_script( - &context, - FunctionToTest::AssertNone16, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; - - Ok(()) + run( + context, + program(), + build_witness(function, same, none), + expect, + ) } -#[simplex::test] -fn assert_none_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone16, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} - -#[simplex::test] -fn assert_none_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - spend_script( - &context, - FunctionToTest::AssertNone32, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; - - Ok(()) -} - -#[simplex::test] -fn assert_none_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone32, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); - - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); - - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); - - Ok(()) -} +mod asserts_test { + use super::*; -#[simplex::test] -fn assert_none_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; - - spend_script( - &context, - FunctionToTest::AssertNone64, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; - - Ok(()) -} + // ---------- assert_eq: happy = equal args, unhappy = distinct args ---------- + #[simplex::test] + fn assert_eq_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert(&context, FunctionToTest::AssertEq8, true, false, Expect::Ok) + } -#[simplex::test] -fn assert_none_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; + #[simplex::test] + fn assert_eq_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq8, + false, + false, + Expect::AssertFailed, + ) + } - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone64, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); + #[simplex::test] + fn assert_eq_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq16, + true, + false, + Expect::Ok, + ) + } - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); + #[simplex::test] + fn assert_eq_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq16, + false, + false, + Expect::AssertFailed, + ) + } - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); + #[simplex::test] + fn assert_eq_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq32, + true, + false, + Expect::Ok, + ) + } - Ok(()) -} + #[simplex::test] + fn assert_eq_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq32, + false, + false, + Expect::AssertFailed, + ) + } -#[simplex::test] -fn assert_none_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; + #[simplex::test] + fn assert_eq_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq64, + true, + false, + Expect::Ok, + ) + } - spend_script( - &context, - FunctionToTest::AssertNone128, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; + #[simplex::test] + fn assert_eq_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq64, + false, + false, + Expect::AssertFailed, + ) + } - Ok(()) -} + #[simplex::test] + fn assert_eq_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq256, + true, + false, + Expect::Ok, + ) + } -#[simplex::test] -fn assert_none_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; + #[simplex::test] + fn assert_eq_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertEq256, + false, + false, + Expect::AssertFailed, + ) + } - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone128, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); + // ---------- assert_none: happy = None arg, unhappy = Some arg ---------- + #[simplex::test] + fn assert_none_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone8, + false, + true, + Expect::Ok, + ) + } - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); + #[simplex::test] + fn assert_none_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone8, + false, + false, + Expect::AssertFailed, + ) + } - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); + #[simplex::test] + fn assert_none_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone16, + false, + true, + Expect::Ok, + ) + } - Ok(()) -} + #[simplex::test] + fn assert_none_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone16, + false, + false, + Expect::AssertFailed, + ) + } -#[simplex::test] -fn assert_none_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; + #[simplex::test] + fn assert_none_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone32, + false, + true, + Expect::Ok, + ) + } - spend_script( - &context, - FunctionToTest::AssertNone256, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NoneValue, - )?; + #[simplex::test] + fn assert_none_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone32, + false, + false, + Expect::AssertFailed, + ) + } - Ok(()) -} + #[simplex::test] + fn assert_none_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone64, + false, + true, + Expect::Ok, + ) + } -#[simplex::test] -fn assert_none_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - fund_script(&context)?; + #[simplex::test] + fn assert_none_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone64, + false, + false, + Expect::AssertFailed, + ) + } - let txid_result = spend_script( - &context, - FunctionToTest::AssertNone256, - IfTestSameValues::DifferentValues, - IfTestNoneValue::NotNoneValue, - ); + #[simplex::test] + fn assert_none_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone128, + false, + true, + Expect::Ok, + ) + } - assert!( - txid_result.is_err(), - "Expected this test to fail but it succeeded" - ); + #[simplex::test] + fn assert_none_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone128, + false, + false, + Expect::AssertFailed, + ) + } - let err: String = txid_result.unwrap_err().to_string(); - assert_eq!(err, "Failed to prune program: Jet failed during execution"); + #[simplex::test] + fn assert_none_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone256, + false, + true, + Expect::Ok, + ) + } - Ok(()) + #[simplex::test] + fn assert_none_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + run_assert( + &context, + FunctionToTest::AssertNone256, + false, + false, + Expect::AssertFailed, + ) + } } diff --git a/tests/common/core.rs b/tests/common/core.rs new file mode 100644 index 0000000..9b4d8e2 --- /dev/null +++ b/tests/common/core.rs @@ -0,0 +1,94 @@ +// Each `tests/*.rs` is a separate crate that mounts this module but uses only +// part of it, so per-crate dead-code analysis would warn about the rest. +#![allow(dead_code)] + +use simplex::program::{Program, WitnessTrait}; +use simplex::simplicityhl::elements::Script; +use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; + +#[derive(Clone, Copy)] +pub enum Expect { + /// The spend succeeds. + Ok, + /// A failed `assert!` in the contract. + AssertFailed, + /// Execution reached a pruned branch (e.g. `unwrap(None)`, a `safe_*` overflow). + PrunedBranch, +} + +impl Expect { + /// The exact broadcast error message for a failing expectation (`None` for `Ok`). + fn error_message(self) -> Option<&'static str> { + match self { + Expect::Ok => None, + Expect::AssertFailed => Some("Failed to prune program: Jet failed during execution"), + Expect::PrunedBranch => { + Some("Failed to prune program: Execution reached a pruned branch") + } + } + } +} + +/// Send sats to the program's script so it has a UTXO to spend. +pub fn fund( + context: &simplex::TestContext, + program: &impl AsRef, +) -> anyhow::Result