diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..8f535fafe --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,10 @@ +[alias] +be = "build --examples --target wasm32-unknown-unknown --release" +tt = "nextest run --release --all --no-fail-fast" +cc = "clippy --all -- -D warnings" +conta = "run --release -p conta" + +[target.wasm32-unknown-unknown] +rustflags = [ + "-C", "link-args=--import-memory", +] diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 112037fd3..f143e27cb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,11 +21,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@nextest - - name: Run Tests - run: cargo nextest run --all-features --no-fail-fast - - name: Build Examples - run: cd examples && cargo b --release + run: cargo build --examples --target wasm32-unknown-unknown --release + + - name: Run Tests + run: cargo nextest run --all --no-fail-fast --release check: name: Check @@ -37,4 +37,4 @@ jobs: - name: Format run: cargo fmt --check - name: Clippy - run: cargo clippy --all-features -- -D warnings + run: cargo clippy --all -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index a40007073..6c6a9b018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,13 +19,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -353,9 +354,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -363,9 +364,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -375,9 +376,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -387,9 +388,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cobs" @@ -669,6 +670,24 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "elko" +version = "0.1.5-pre.2" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", + "colored", + "etc", + "semver", + "serde", + "thiserror", + "toml", + "tracing", + "wasm-opt", + "zinkc", +] + [[package]] name = "elliptic-curve" version = "0.13.6" @@ -1675,9 +1694,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -1745,9 +1764,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -1940,9 +1959,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -2004,12 +2023,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -2320,7 +2339,7 @@ dependencies = [ [[package]] name = "zabi" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ "hex", "postcard", @@ -2329,6 +2348,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "zerocopy" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -2351,7 +2390,7 @@ dependencies = [ [[package]] name = "zingen" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ "anyhow", "evm-opcodes", @@ -2366,14 +2405,18 @@ dependencies = [ [[package]] name = "zink" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ + "anyhow", + "paste", "zink-codegen", + "zinkc-filetests", + "zint", ] [[package]] name = "zink-codegen" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ "proc-macro2", "quote", @@ -2383,9 +2426,10 @@ dependencies = [ [[package]] name = "zinkc" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ "anyhow", + "etc", "hex", "paste", "thiserror", @@ -2395,34 +2439,51 @@ dependencies = [ "wat", "zabi", "zingen", - "zint", ] [[package]] -name = "zinkup" -version = "0.1.4" +name = "zinkc-filetests" +version = "0.1.5-pre.2" dependencies = [ "anyhow", "cargo_metadata", - "clap", - "color-eyre", - "colored", - "etc", - "semver", - "serde", - "thiserror", - "toml", + "proc-macro2", + "quote", + "syn 2.0.38", "tracing", "tracing-subscriber", "wasm-opt", + "wat", + "zinkc", +] + +[[package]] +name = "zinkup" +version = "0.1.5-pre.2" +dependencies = [ + "anyhow", + "clap", + "color-eyre", + "elko", + "tracing-subscriber", + "zink", "zinkc", ] [[package]] name = "zint" -version = "0.1.4" +version = "0.1.5-pre.2" dependencies = [ + "anyhow", + "cargo_metadata", + "etc", "hex", "revm", + "serde", + "toml", "tracing", + "tracing-subscriber", + "wasm-opt", + "zabi", + "zinkc", ] diff --git a/Cargo.toml b/Cargo.toml index f7f8654c0..bd831bc97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,27 @@ -[workspace.package] -version = "0.1.4" -authors = ["clearloop"] -edition = "2021" -license = "GPL-3.0-only" -homepage = "https://github.com/clearloop/zink" -repository = "https://github.com/clearloop/zink.git" - [workspace] members = [ + "abi", "cli", + "cli/conta", + "cli/elko", "codegen", - "codegen/abi", "codegen/opcodes", "compiler", - "utils/*", - "zink", + "compiler/filetests", + # "tests", "zink/codegen", - "zint" + "zint", ] resolver = "2" +[workspace.package] +version = "0.1.5-pre.2" +authors = ["clearloop"] +edition = "2021" +license = "GPL-3.0-only" +homepage = "https://github.com/clearloop/zink" +repository = "https://github.com/clearloop/zink.git" + [workspace.dependencies] anyhow = "1.0.71" cargo_metadata = "0.15.4" @@ -52,16 +54,44 @@ wasm-opt = "0.113.0" wasmparser = "0.107.0" wat = "1.0.75" -# Local Dependencies. -zabi = { path = "codegen/abi", version = "=0.1.4" } -zinkup = { path = "cli", version = "=0.1.4" } +elko = { path = "cli/elko", version = "=0.1.5-pre.2" } opcodes = { package = "evm-opcodes", path = "codegen/opcodes", version = "=0.0.3", features = ["data"] } -zingen = { path = "codegen", version = "=0.1.4" } -zinkc = { path = "compiler", version = "=0.1.4" } -zink = { path = "zink", version = "=0.1.4" } -zink-codegen = { path = "zink/codegen", version = "=0.1.4" } -zint = { path = "zint", version = "=0.1.4" } +zabi = { path = "abi", version = "=0.1.5-pre.2" } +zinkup = { path = "cli", version = "=0.1.5-pre.2" } +zingen = { path = "codegen", version = "=0.1.5-pre.2" } +zinkc = { path = "compiler", version = "=0.1.5-pre.2" } +zinkc-filetests = { path = "compiler/filetests", version = "=0.1.5-pre.2" } +zink = { path = ".", version = "=0.1.5-pre.2" } +zink-codegen = { path = "zink/codegen", version = "=0.1.5-pre.2" } +zint = { path = "zint", version = "=0.1.5-pre.2" } [profile] dev = { panic = "abort"} release = { panic = "unwind" } + +# Zink Programming Language +# ------------------------- + +[package] +name = "zink" +description = "Standard library for zink projects." +documentation = "https://docs.rs/zink" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +readme = "zink/README.md" + +[lib] +path = "zink/src/lib.rs" + +[dependencies] +zink-codegen.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +anyhow.workspace = true +paste.workspace = true +zinkc-filetests.workspace = true +zint.workspace = true diff --git a/Conta.toml b/Conta.toml index 8fa2b928f..a6aad142c 100644 --- a/Conta.toml +++ b/Conta.toml @@ -1,8 +1,11 @@ packages = [ + "zabi", "zingen", - "zint", "zinkc", + "zinkc-filetests", + "zint", "zink-codegen", "zink", + "elko", "zinkup" ] diff --git a/RELEASES.md b/RELEASES.md new file mode 100644 index 000000000..a6beb9d12 --- /dev/null +++ b/RELEASES.md @@ -0,0 +1,110 @@ +## v0.1.5 + +### Added + +- Crate `zabi` +- Function dispatcher +- new `proc-macro` `zink::external` +- `dispatcher` flag for `elko` and `zinkc` +- Jump with offset in jump table +- `Contract` instance in `zint` +- Host function `emit_abi` +- filetests for the compiler + +## Changed + +- Map functions in codegen for different usages +- Move `zink` to the top level +- Move previous compiler tests to the top level +- Move examples out of crates + +--- + +## v0.1.4 + +### Added + +- `proc-macro` for storage +- `proc-macro` for event logging +- Update documents for storage and events + +### Fixed + +- Publishing logic of `conta` + +--- + +## v0.1.3 + +### Added + +- Event logging APIs +- Examples for logging +- Data section parser in `codegen` +- Documents for event logging APIs +- Benchmarks for event logging APIs + +--- + +## v0.1.2 + +### Added + +- Storage related built-in functions + - `sstore` and `sload` +- `impl_tests` for generating arithmetic tests +- Project logo +- rust-cache in CI +- Documents for storage APIs +- Benchmarks for event storage APIs + +--- + +## v0.1.1 + +### Added + +- Code section in `codegen` +- Instruction `select` +- Params test for `select` + +--- + +## V0.1.0 + +The MVP of the zink project, provides various tools for developing +EVM contracts with `rust` and `WASM`. + +### Binaries + +| name | description | +| ------- | ----------------------------------------------------------- | +| `elko` | Zink's package manager, can create and build zink project. | +| `zinkc` | The zink compiler, can compile simple wasm to EVM bytecode. | + +For supporting nearly everything, plz keep tuned for `v0.3.0`. + +### Components + +| name | description | +| --------- | --------------------------------------------------------- | +| `zinkgen` | Zink code generator | +| `zinkc` | Zink compiler | +| `zink` | Rust library for developing program with zink | +| `zint` | Basic test utils including evm wrapper for testing usages | +| `zinkup` | Zink toolchain installer | + +### Added + +- provided basic functionalities in `v0.1.0` to verify thoughts, the final target + of it is example `fibonaaci`, which means, everything used in the `fibonacci` example + now works! +- `add`, `sub`, `mul` are available now, plus all comparison operand like `gt`, `lt`, + `ge`, `le`, `bitwise` also have implementations **operators like `shr` require the + order of the stack will have bugs\***. +- The compilation of locals currently works without any hardcode, ideally, we don't + need to refactor it in the future! +- Same as locals, works without any hardcode, but some logic related to the jump table + need to be refactored after introducing `selector`. +- `if`, `else`, `block`, `loop`, `br_if` now works without any hardcode, need to add + `br_table`, `select`... to align wasm MVP in the future releases.~\* diff --git a/codegen/abi/Cargo.toml b/abi/Cargo.toml similarity index 94% rename from codegen/abi/Cargo.toml rename to abi/Cargo.toml index e058668ea..c52b34bba 100644 --- a/codegen/abi/Cargo.toml +++ b/abi/Cargo.toml @@ -2,7 +2,7 @@ name = "zabi" description = "Zink ABI generator" documentation = "https://docs.rs/zabi" -version = "0.1.4" +version.workspace = true authors.workspace = true edition.workspace = true homepage.workspace = true diff --git a/abi/README.md b/abi/README.md new file mode 100644 index 000000000..cbbcfa3ca --- /dev/null +++ b/abi/README.md @@ -0,0 +1,7 @@ +## ZABI + +EVM ABI for zink contracts. + +## LICENSE + +GPL-3.0-only diff --git a/codegen/abi/src/lib.rs b/abi/src/lib.rs similarity index 100% rename from codegen/abi/src/lib.rs rename to abi/src/lib.rs diff --git a/codegen/abi/src/result.rs b/abi/src/result.rs similarity index 100% rename from codegen/abi/src/result.rs rename to abi/src/result.rs diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8245688b4..ceac537bc 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,32 +10,26 @@ homepage.workspace = true repository.workspace = true [[bin]] -path = "bin/elko.rs" -name = "elko" -required-features = ["elko"] +name = "zinkc" +required-features = [ "zinkc" ] [[bin]] -path = "bin/zinkc.rs" -name = "zinkc" -required-features = ["zinkc"] +name = "elko" +required-features = [ "elko" ] [dependencies] anyhow.workspace = true -cargo_metadata = { workspace = true, optional = true } -clap = { workspace = true, features = ["derive"] } +clap = { workspace = true, features = [ "derive" ] } color-eyre.workspace = true -colored = { workspace = true, optional = true } -etc = { workspace = true, optional = true } -semver = { workspace = true, optional = true } -serde = { workspace = true, optional = true, features = [ "derive" ] } -thiserror = { workspace = true, optional = true } -toml = { workspace = true, optional = true } -tracing.workspace = true -tracing-subscriber = { workspace = true, features = ["std", "env-filter"] } -wasm-opt = { workspace = true, optional = true } +tracing-subscriber = { workspace = true, features = [ "env-filter" ] } + +elko = { workspace = true, optional = true } zinkc = { workspace = true, optional = true } +[dev-dependencies] +zink.workspace = true + [features] -default = ["elko", "zinkc"] -elko = [ "cargo_metadata", "colored", "etc", "semver", "serde", "thiserror", "toml", "wasm-opt", "zinkc" ] +default = [ "elko", "zinkc" ] +elko = [ "dep:elko" ] zinkc = [ "dep:zinkc" ] diff --git a/utils/conta/Cargo.toml b/cli/conta/Cargo.toml similarity index 100% rename from utils/conta/Cargo.toml rename to cli/conta/Cargo.toml diff --git a/utils/conta/README.md b/cli/conta/README.md similarity index 100% rename from utils/conta/README.md rename to cli/conta/README.md diff --git a/utils/conta/bin/conta.rs b/cli/conta/bin/conta.rs similarity index 100% rename from utils/conta/bin/conta.rs rename to cli/conta/bin/conta.rs diff --git a/utils/conta/src/cmd/bump.rs b/cli/conta/src/cmd/bump.rs similarity index 100% rename from utils/conta/src/cmd/bump.rs rename to cli/conta/src/cmd/bump.rs diff --git a/utils/conta/src/cmd/mod.rs b/cli/conta/src/cmd/mod.rs similarity index 100% rename from utils/conta/src/cmd/mod.rs rename to cli/conta/src/cmd/mod.rs diff --git a/utils/conta/src/cmd/publish.rs b/cli/conta/src/cmd/publish.rs similarity index 100% rename from utils/conta/src/cmd/publish.rs rename to cli/conta/src/cmd/publish.rs diff --git a/utils/conta/src/config.rs b/cli/conta/src/config.rs similarity index 100% rename from utils/conta/src/config.rs rename to cli/conta/src/config.rs diff --git a/utils/conta/src/lib.rs b/cli/conta/src/lib.rs similarity index 100% rename from utils/conta/src/lib.rs rename to cli/conta/src/lib.rs diff --git a/utils/conta/src/sed.rs b/cli/conta/src/sed.rs similarity index 100% rename from utils/conta/src/sed.rs rename to cli/conta/src/sed.rs diff --git a/cli/elko/Cargo.toml b/cli/elko/Cargo.toml new file mode 100644 index 000000000..8931e7b45 --- /dev/null +++ b/cli/elko/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "elko" +description = "Zink package manager." +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +anyhow.workspace = true +clap = { workspace = true, features = [ "derive" ] } +cargo_metadata.workspace = true +colored.workspace = true +etc.workspace = true +semver.workspace = true +serde = { workspace = true, features = [ "derive" ] } +thiserror.workspace = true +toml.workspace = true +tracing.workspace = true +wasm-opt.workspace = true +zinkc.workspace = true diff --git a/cli/elko/README.md b/cli/elko/README.md new file mode 100644 index 000000000..62bb3f3f9 --- /dev/null +++ b/cli/elko/README.md @@ -0,0 +1,30 @@ +# `elko` - Zink's package manager + +## Installation + +```bash +cargo install zinkup --features elko +``` + +## Usages + +```bash +elko +Package manager of zink. + +Usage: elko [OPTIONS] + +Commands: + new Create a new zink project + build Build zink project to EVM bytecode + help Print this message or the help of the given subcommand(s) + +Options: + -v, --verbose... Verbose mode (-v, -vv, -vvv, etc.) + -h, --help Print help + -V, --version Print version +``` + +## LICENSE + +GPL-3.0 diff --git a/cli/src/build.rs b/cli/elko/src/build.rs similarity index 91% rename from cli/src/build.rs rename to cli/elko/src/build.rs index 4e81cb3d3..05c757c6f 100644 --- a/cli/src/build.rs +++ b/cli/elko/src/build.rs @@ -1,5 +1,4 @@ //! Command `Build`. -#![cfg(feature = "elko")] use crate::utils::{Profile, WasmBuilder}; use anyhow::{anyhow, Result}; use clap::Parser; @@ -22,6 +21,9 @@ pub struct Build { /// Optimize with default optimizations #[clap(long)] pub release: bool, + /// If enable dispatcher. + #[clap(short, long)] + pub dispatcher: bool, } impl Build { @@ -67,7 +69,9 @@ impl Build { // Compile the wasm to evm bytecode. let wasm = fs::read(builder.output()?)?; - let bin = Compiler::default().compile(&wasm)?; + let bin = Compiler::default() + .dispatcher(self.dispatcher) + .compile(&wasm)?; let dst = builder.output()?.with_extension("bin"); fs::write(dst, bin)?; diff --git a/cli/elko/src/lib.rs b/cli/elko/src/lib.rs new file mode 100644 index 000000000..ae8dbeb14 --- /dev/null +++ b/cli/elko/src/lib.rs @@ -0,0 +1,7 @@ +//! Zink package manager. + +mod build; +mod new; +pub mod utils; + +pub use self::{build::Build, new::New}; diff --git a/cli/src/new.rs b/cli/elko/src/new.rs similarity index 98% rename from cli/src/new.rs rename to cli/elko/src/new.rs index c16d801e3..bdbf4c23b 100644 --- a/cli/src/new.rs +++ b/cli/elko/src/new.rs @@ -1,6 +1,4 @@ //! Command `New` -#![cfg(feature = "elko")] - use crate::utils::Manifest; use anyhow::{anyhow, Result}; use clap::Parser; diff --git a/cli/src/utils/manifest.rs b/cli/elko/src/utils/manifest.rs similarity index 100% rename from cli/src/utils/manifest.rs rename to cli/elko/src/utils/manifest.rs diff --git a/cli/src/utils/mod.rs b/cli/elko/src/utils/mod.rs similarity index 96% rename from cli/src/utils/mod.rs rename to cli/elko/src/utils/mod.rs index ef66c6bac..a270e8c3f 100644 --- a/cli/src/utils/mod.rs +++ b/cli/elko/src/utils/mod.rs @@ -1,5 +1,4 @@ //! CLI Utils -#![cfg(feature = "elko")] pub use self::{ manifest::Manifest, diff --git a/cli/src/utils/result.rs b/cli/elko/src/utils/result.rs similarity index 100% rename from cli/src/utils/result.rs rename to cli/elko/src/utils/result.rs diff --git a/cli/src/utils/wasm.rs b/cli/elko/src/utils/wasm.rs similarity index 99% rename from cli/src/utils/wasm.rs rename to cli/elko/src/utils/wasm.rs index 2d9b1373f..2f2209760 100644 --- a/cli/src/utils/wasm.rs +++ b/cli/elko/src/utils/wasm.rs @@ -141,7 +141,7 @@ impl WasmBuilder { // run the wasm optimizer OptimizationOptions::new_opt_level_4() - .debug_info(true) + .debug_info(false) .mvp_features_only() .set_converge() .run(src, self.output()?)?; diff --git a/cli/bin/elko.rs b/cli/src/bin/elko.rs similarity index 100% rename from cli/bin/elko.rs rename to cli/src/bin/elko.rs diff --git a/cli/bin/zinkc.rs b/cli/src/bin/zinkc.rs similarity index 100% rename from cli/bin/zinkc.rs rename to cli/src/bin/zinkc.rs diff --git a/cli/src/compile.rs b/cli/src/compile.rs index 7537c9fd9..6bd0ae5f9 100644 --- a/cli/src/compile.rs +++ b/cli/src/compile.rs @@ -16,6 +16,9 @@ pub struct Compile { /// Write output to \ #[clap(short, long)] output: Option, + /// If enable dispatcher. + #[clap(short, long)] + dispatcher: bool, } impl Compile { @@ -27,7 +30,9 @@ impl Compile { env::current_dir()?.join(self.input.with_extension("")) }; - let bin = Compiler::default().compile(&fs::read(&self.input)?)?; + let bin = Compiler::default() + .dispatcher(self.dispatcher) + .compile(&fs::read(&self.input)?)?; fs::write(output, bin)?; Ok(()) } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 3c9925479..ecdc45fef 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,5 +1,4 @@ -//! Zink command line tool -#![deny(missing_docs)] +//! Zink toolchain. use anyhow::Error; use clap::Parser; @@ -7,17 +6,12 @@ use color_eyre::{eyre::eyre, Result}; pub use commands::*; use tracing_subscriber::filter::EnvFilter; -mod build; mod compile; -mod new; -pub mod utils; - mod commands { - #[cfg(feature = "elko")] - pub use crate::{build::Build, new::New}; - #[cfg(feature = "zinkc")] pub use crate::compile::Compile; + #[cfg(feature = "elko")] + pub use elko::{Build, New}; } /// Shared application interface. diff --git a/codegen/src/dispatcher.rs b/codegen/src/dispatcher.rs index 0410a41a3..9f4e34469 100644 --- a/codegen/src/dispatcher.rs +++ b/codegen/src/dispatcher.rs @@ -210,29 +210,38 @@ impl<'d> Dispatcher<'d> { // 1. drop selector. // 2. load calldata to stack. // 3. jump to the callee function. - fn process(&mut self, sig: &FuncType) -> Result<()> { + fn process(&mut self, len: usize, last: bool) -> Result<()> { + let len = len as u8; + if last && len == 0 { + return Ok(()); + } + self.asm.increment_sp(1)?; let asm = self.asm.clone(); - let len = sig.params().len() as u8; - { - // TODO: check the safety of this. - // - // [ callee, ret, selector ] -> [ selector, callee, ret ] - self.asm.shift_stack(2, false)?; - // [ selector, callee, ret ] -> [ callee, ret ] - self.asm._drop()?; - // [ callee, ret ] -> [ param * len, callee, ret ] - for p in (0..len).rev() { - let offset = 4 + p * 32; - self.asm.push(&offset.to_ls_bytes())?; - self.asm._calldataload()?; + if !last { + // TODO: check the safety of this. + // + // [ callee, ret, selector ] -> [ selector, callee, ret ] + self.asm.shift_stack(2, false)?; + // [ selector, callee, ret ] -> [ callee, ret ] + self.asm._drop()?; + } + + if len > 0 { + // [ callee, ret ] -> [ param * len, callee, ret ] + for p in (0..len).rev() { + let offset = 4 + p * 32; + self.asm.push(&offset.to_ls_bytes())?; + self.asm._calldataload()?; + } + + // [ param * len, callee, ret ] -> [ ret, param * len, callee ] + self.asm.shift_stack(len + 1, false)?; + // [ ret, param * len, callee ] -> [ callee, ret, param * len ] + self.asm.shift_stack(len + 1, false)?; } - // [ param * len, callee, ret ] -> [ ret, param * len, callee ] - self.asm.shift_stack(len + 1, false)?; - // [ ret, param * len, callee ] -> [ callee, ret, param * len ] - self.asm.shift_stack(len + 1, false)?; self.asm._jump()?; } @@ -290,7 +299,10 @@ impl<'d> Dispatcher<'d> { self.asm.push(&selector_bytes)?; self.asm._eq()?; - self.process(&sig)?; + self.process(sig.params().len(), last)?; + if last { + self.asm.shift_stack(2, false)?; + } self.asm._jumpi()?; if !last { diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index c7c140901..b8bf08b8f 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -20,6 +20,6 @@ zingen.workspace = true hex.workspace = true wat.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"]} -zint.workspace = true paste.workspace = true zabi.workspace = true +etc.workspace = true diff --git a/compiler/filetests/Cargo.toml b/compiler/filetests/Cargo.toml new file mode 100644 index 000000000..442cb1a77 --- /dev/null +++ b/compiler/filetests/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "zinkc-filetests" +description = "Filetests for zinkc." +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lib] +path = "lib.rs" + +[dependencies] +anyhow.workspace = true + +[dev-dependencies] +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"]} +zinkc.workspace = true + +[build-dependencies] +anyhow.workspace = true +cargo_metadata.workspace = true +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true +wat.workspace = true +wasm-opt.workspace = true + +[features] +testing = [] diff --git a/compiler/filetests/build.rs b/compiler/filetests/build.rs new file mode 100644 index 000000000..50bfefada --- /dev/null +++ b/compiler/filetests/build.rs @@ -0,0 +1,222 @@ +//! Load all wat files to structured tests. + +use anyhow::Result; +use proc_macro2::Span; +use quote::ToTokens; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; +use syn::{parse_quote, ExprArray, ExprMatch, Ident, ItemImpl}; +use wasm_opt::OptimizationOptions; + +fn main() -> Result<()> { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=wat"); + + let item_impl = parse_tests()?; + fs::write( + env::var("OUT_DIR")?.parse::()?.join("tests.rs"), + item_impl.to_token_stream().to_string(), + )?; + + Ok(()) +} + +fn wasm_directory() -> Result { + cargo_metadata::MetadataCommand::new() + .no_deps() + .exec() + .map(|m| m.target_directory.join("wasm32-unknown-unknown").into()) + .map_err(Into::into) +} + +/// Read the contents of a directory, returning +/// all wat files. +fn list_wat(dir: impl AsRef, files: &mut Vec) -> Result<()> { + let entry = fs::read_dir(dir)?; + for entry in entry { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + list_wat(path, files)?; + } else if path.extension().unwrap_or_default() == "wat" { + files.push(path); + } + } + + Ok(()) +} + +/// Batch all wat files. +fn wat_files() -> Result> { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("wat"); + let mut files = Vec::new(); + list_wat(&path, &mut files)?; + + let excludes = ["as_if_else.wat"]; + + Ok(files + .into_iter() + .filter(|f| { + !excludes.contains( + &f.file_name() + .and_then(|n| n.to_str()) + .expect("file name not found"), + ) + }) + .collect()) +} + +fn examples() -> Result> { + let release = wasm_directory()?.join("release").join("examples"); + if !release.exists() { + return Ok(Default::default()); + } + + let with_commit_hash = |p: &PathBuf| -> bool { + let name = p + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(); + + // for example: addition-6313c94b67ad9699.wasm + let len = name.len(); + if let Some(index) = name.rfind('-') { + if len > 22 && index == len - 22 { + return true; + } + } + + false + }; + + let files = fs::read_dir(release)? + .filter_map(|e| { + let path = e.ok()?.path(); + if path.extension().unwrap_or_default() == "wasm" && !with_commit_hash(&path) { + Some(path) + } else { + None + } + }) + .collect::>(); + + for wasm in &files { + OptimizationOptions::new_opt_level_4() + .debug_info(false) + .mvp_features_only() + .set_converge() + .run(wasm, wasm)?; + } + + Ok(files) +} + +fn parse_tests() -> Result { + let mut item_impl: ItemImpl = parse_quote! { + /// Constant tests. + impl Test {} + }; + let mut examples_arr: ExprArray = parse_quote!([]); + let mut wat_files_arr: ExprArray = parse_quote!([]); + let mut match_expr: ExprMatch = parse_quote! { + match (module, name) {} + }; + + let mut push = |tests: &mut ExprArray, p: &PathBuf, bytes: &[u8]| { + let name = p + .with_extension("") + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + .to_string(); + + let module = p + .parent() + .expect("parent not found for {p:?}") + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + .to_string(); + + let mut expr: ExprArray = parse_quote!([]); + for byte in bytes { + expr.elems.push(parse_quote!(#byte)); + } + + let ident: Ident = { + let ident_name = module.to_uppercase() + "_" + &name.to_ascii_uppercase(); + let ident: Ident = Ident::new(&ident_name.replace('-', "_"), Span::call_site()); + let len = bytes.len(); + item_impl.items.push(parse_quote! { + #[doc = concat!(" path: ", #module, "::", #name)] + pub const #ident: [u8; #len] = #expr; + }); + + match_expr.arms.push(parse_quote! { + (#module, #name) => Test { + module: module.into(), + name: name.into(), + wasm: Self::#ident.to_vec(), + } + }); + ident + }; + + tests.elems.push(parse_quote! { + Test { + module: #module.into(), + name: #name.into(), + wasm: Self::#ident.to_vec() + } + }) + }; + + for wat in wat_files()? { + let wat_bytes = fs::read(&wat)?; + let wasm = wat::parse_bytes(&wat_bytes)?; + push(&mut wat_files_arr, &wat, &wasm); + } + + for example in examples()? { + let wasm = fs::read(&example)?; + push(&mut examples_arr, &example, &wasm); + } + + match_expr.arms.push(parse_quote! { + _ => return Err(anyhow::anyhow!("test not found: {{module: {}, name: {}}}", module, name)) + }); + + let funcs: ItemImpl = parse_quote! { + impl Test { + /// Load test from module and name. + pub fn load(module: &str, name: &str) -> anyhow::Result { + Ok(#match_expr) + } + + /// Example tests. + pub fn examples() -> Vec { + #examples_arr.to_vec() + } + + /// Wat files tests. + pub fn wat_files() -> Vec { + #wat_files_arr.to_vec() + } + + /// All tests. + pub fn all() -> Vec { + let mut tests = Self::examples(); + tests.extend(Self::wat_files()); + tests + } + } + }; + + item_impl.items.extend(funcs.items); + Ok(item_impl) +} diff --git a/compiler/filetests/lib.rs b/compiler/filetests/lib.rs new file mode 100644 index 000000000..14c4da3b6 --- /dev/null +++ b/compiler/filetests/lib.rs @@ -0,0 +1,88 @@ +#![deny(missing_docs)] +//! Zink filetests + +include!(concat!(env!("OUT_DIR"), "/tests.rs")); + +/// A wat test +#[derive(Clone)] +pub struct Test { + /// The module name + pub module: String, + /// The test name + pub name: String, + /// The test source + pub wasm: Vec, +} + +#[cfg(test)] +impl Test { + /// Compile test to evm bytecode. + pub fn compile(&self) -> anyhow::Result> { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .without_time() + .compact() + .try_init() + .ok(); + + let Test { module, name, wasm } = self; + tracing::info!("Compiling {}/{}", module, name); + + zinkc::Compiler::default() + .compile(&wasm) + .map(|v| v.to_vec()) + .map_err(Into::into) + } +} + +/// Generate tests for different modules. +#[macro_export] +macro_rules! impl_tests { + ( + tests: [$($test:ident),+], + modules: $modules:tt + ) => { + $( + impl_tests!(@test $test $modules); + )* + }; + (@test $test:ident [$($mod:expr),*]) => { + $( + paste::paste! { + #[test] + fn [<$mod _ $test>]() -> anyhow::Result<()> { + $test($mod) + } + } + )* + }; +} + +#[cfg(test)] +fn run(tests: &[Test]) { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .without_time() + .compact() + .try_init() + .ok(); + + for Test { module, name, wasm } in tests { + tracing::info!("Compiling {}/{}", module, name); + zinkc::Compiler::default() + .compile(&wasm) + .expect(&format!("Failed to compile {module}::{name}")); + } +} + +// TODO: #161 +// +// #[test] +// fn examples() { +// run(&Test::examples()) +// } + +#[test] +fn wat() { + run(&Test::wat_files()) +} diff --git a/compiler/wat/br_if/as_block_last.wat b/compiler/filetests/wat/br_if/as_block_last.wat similarity index 100% rename from compiler/wat/br_if/as_block_last.wat rename to compiler/filetests/wat/br_if/as_block_last.wat diff --git a/compiler/wat/br_if/as_if_else.wat b/compiler/filetests/wat/br_if/as_if_else.wat similarity index 100% rename from compiler/wat/br_if/as_if_else.wat rename to compiler/filetests/wat/br_if/as_if_else.wat diff --git a/compiler/wat/call/as_if.wat b/compiler/filetests/wat/call/as_if.wat similarity index 100% rename from compiler/wat/call/as_if.wat rename to compiler/filetests/wat/call/as_if.wat diff --git a/compiler/wat/call/dummy.wat b/compiler/filetests/wat/call/dummy.wat similarity index 100% rename from compiler/wat/call/dummy.wat rename to compiler/filetests/wat/call/dummy.wat diff --git a/compiler/wat/call/params.wat b/compiler/filetests/wat/call/params.wat similarity index 100% rename from compiler/wat/call/params.wat rename to compiler/filetests/wat/call/params.wat diff --git a/compiler/wat/i32add/locals.wat b/compiler/filetests/wat/i32add/locals.wat similarity index 100% rename from compiler/wat/i32add/locals.wat rename to compiler/filetests/wat/i32add/locals.wat diff --git a/compiler/wat/i32add/params.wat b/compiler/filetests/wat/i32add/params.wat similarity index 100% rename from compiler/wat/i32add/params.wat rename to compiler/filetests/wat/i32add/params.wat diff --git a/compiler/wat/i32add/tee.wat b/compiler/filetests/wat/i32add/tee.wat similarity index 100% rename from compiler/wat/i32add/tee.wat rename to compiler/filetests/wat/i32add/tee.wat diff --git a/compiler/wat/i32sub/locals.wat b/compiler/filetests/wat/i32sub/locals.wat similarity index 100% rename from compiler/wat/i32sub/locals.wat rename to compiler/filetests/wat/i32sub/locals.wat diff --git a/compiler/wat/i32sub/params.wat b/compiler/filetests/wat/i32sub/params.wat similarity index 100% rename from compiler/wat/i32sub/params.wat rename to compiler/filetests/wat/i32sub/params.wat diff --git a/compiler/wat/i64add/locals.wat b/compiler/filetests/wat/i64add/locals.wat similarity index 100% rename from compiler/wat/i64add/locals.wat rename to compiler/filetests/wat/i64add/locals.wat diff --git a/compiler/wat/i64add/params.wat b/compiler/filetests/wat/i64add/params.wat similarity index 100% rename from compiler/wat/i64add/params.wat rename to compiler/filetests/wat/i64add/params.wat diff --git a/compiler/wat/i64add/tee.wat b/compiler/filetests/wat/i64add/tee.wat similarity index 100% rename from compiler/wat/i64add/tee.wat rename to compiler/filetests/wat/i64add/tee.wat diff --git a/compiler/wat/i64sub/locals.wat b/compiler/filetests/wat/i64sub/locals.wat similarity index 100% rename from compiler/wat/i64sub/locals.wat rename to compiler/filetests/wat/i64sub/locals.wat diff --git a/compiler/wat/i64sub/params.wat b/compiler/filetests/wat/i64sub/params.wat similarity index 100% rename from compiler/wat/i64sub/params.wat rename to compiler/filetests/wat/i64sub/params.wat diff --git a/compiler/wat/if/basic.wat b/compiler/filetests/wat/if/basic.wat similarity index 100% rename from compiler/wat/if/basic.wat rename to compiler/filetests/wat/if/basic.wat diff --git a/compiler/wat/if/singular.wat b/compiler/filetests/wat/if/singular.wat similarity index 100% rename from compiler/wat/if/singular.wat rename to compiler/filetests/wat/if/singular.wat diff --git a/compiler/wat/log/log0.wat b/compiler/filetests/wat/log/log0.wat similarity index 100% rename from compiler/wat/log/log0.wat rename to compiler/filetests/wat/log/log0.wat diff --git a/compiler/wat/log/log1.wat b/compiler/filetests/wat/log/log1.wat similarity index 100% rename from compiler/wat/log/log1.wat rename to compiler/filetests/wat/log/log1.wat diff --git a/compiler/wat/log/log2.wat b/compiler/filetests/wat/log/log2.wat similarity index 100% rename from compiler/wat/log/log2.wat rename to compiler/filetests/wat/log/log2.wat diff --git a/compiler/wat/log/log3.wat b/compiler/filetests/wat/log/log3.wat similarity index 100% rename from compiler/wat/log/log3.wat rename to compiler/filetests/wat/log/log3.wat diff --git a/compiler/wat/log/log4.wat b/compiler/filetests/wat/log/log4.wat similarity index 100% rename from compiler/wat/log/log4.wat rename to compiler/filetests/wat/log/log4.wat diff --git a/compiler/wat/loop/as_br_if.wat b/compiler/filetests/wat/loop/as_br_if.wat similarity index 100% rename from compiler/wat/loop/as_br_if.wat rename to compiler/filetests/wat/loop/as_br_if.wat diff --git a/compiler/wat/loop/singular.wat b/compiler/filetests/wat/loop/singular.wat similarity index 100% rename from compiler/wat/loop/singular.wat rename to compiler/filetests/wat/loop/singular.wat diff --git a/compiler/wat/recursion/fibonacci.wat b/compiler/filetests/wat/recursion/fibonacci.wat similarity index 100% rename from compiler/wat/recursion/fibonacci.wat rename to compiler/filetests/wat/recursion/fibonacci.wat diff --git a/compiler/wat/select/params.wat b/compiler/filetests/wat/select/params.wat similarity index 100% rename from compiler/wat/select/params.wat rename to compiler/filetests/wat/select/params.wat diff --git a/compiler/wat/storage/basic.wat b/compiler/filetests/wat/storage/basic.wat similarity index 100% rename from compiler/wat/storage/basic.wat rename to compiler/filetests/wat/storage/basic.wat diff --git a/compiler/wat/storage/dispatcher.wat b/compiler/filetests/wat/storage/dispatcher.wat similarity index 100% rename from compiler/wat/storage/dispatcher.wat rename to compiler/filetests/wat/storage/dispatcher.wat diff --git a/compiler/wat/storage/load.wat b/compiler/filetests/wat/storage/load.wat similarity index 100% rename from compiler/wat/storage/load.wat rename to compiler/filetests/wat/storage/load.wat diff --git a/compiler/wat/storage/store.wat b/compiler/filetests/wat/storage/store.wat similarity index 100% rename from compiler/wat/storage/store.wat rename to compiler/filetests/wat/storage/store.wat diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index ba08ff657..42bfd56af 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -15,9 +15,9 @@ pub struct Compiler { } impl Compiler { - /// Embed dispatcher in bytecode. - pub fn with_dispatcher(&mut self) -> &mut Self { - self.dispatcher = true; + /// If embed dispatcher in bytecode. + pub fn dispatcher(mut self, dispatcher: bool) -> Self { + self.dispatcher = dispatcher; self } diff --git a/compiler/tests/add.rs b/compiler/tests/add.rs deleted file mode 100644 index aa85e2385..000000000 --- a/compiler/tests/add.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Addition tests for the zink compiler. -#![cfg(test)] - -use anyhow::Result; -use zint::{Bytes32, EVM}; - -mod common; - -fn params(module: &str) -> Result<()> { - let bytecode = common::load(module, "params")?; - - // add(1, 2) - let input = [1.to_bytes32(), 2.to_bytes32()].concat(); - let info = EVM::run(&bytecode, &input); - - assert_eq!(info.ret, [3.to_bytes32()].concat()); - Ok(()) -} - -fn locals(module: &str) -> Result<()> { - let bytecode = common::load(module, "locals")?; - let info = EVM::run(&bytecode, &[]); - - assert_eq!(info.ret, [30.to_bytes32()].concat()); - Ok(()) -} - -fn tee(module: &str) -> Result<()> { - let bytecode = common::load(module, "tee")?; - let info = EVM::run(&bytecode, &[]); - - assert_eq!(info.ret, [30.to_bytes32()].concat()); - Ok(()) -} - -impl_tests! { - tests: [params, locals, tee], - modules: ["i32add", "i64add"] -} diff --git a/compiler/tests/br_if.rs b/compiler/tests/br_if.rs deleted file mode 100644 index 084292ef8..000000000 --- a/compiler/tests/br_if.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! br_if tests for the zink compiler. -#![cfg(test)] - -use anyhow::Result; -use zint::{Bytes32, InstructionResult, EVM}; - -mod common; - -#[test] -fn as_block_last() -> Result<()> { - let bytecode = common::load("br_if", "as_block_last")?; - - let info = EVM::run(&bytecode, &0.to_bytes32()); - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, []); - - let info = EVM::run(&bytecode, &42.to_bytes32()); - assert_eq!(info.instr, InstructionResult::OutOfGas); - assert_eq!(info.ret, []); - - Ok(()) -} diff --git a/compiler/tests/call.rs b/compiler/tests/call.rs deleted file mode 100644 index d6a0fc292..000000000 --- a/compiler/tests/call.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! if-else tests for the zink compiler. -#![cfg(test)] - -use anyhow::Result; -use zint::{Bytes32, InstructionResult, EVM}; - -mod common; - -#[test] -fn dummy() -> Result<()> { - let bytecode = common::load("call", "dummy")?; - let info = EVM::run(&bytecode, &[]); - - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, []); - - Ok(()) -} - -#[test] -fn params() -> Result<()> { - let bytecode = common::load("call", "params")?; - - let input = [1.to_bytes32(), 2.to_bytes32()].concat(); - let info = EVM::run(&bytecode, &input); - - assert_eq!(info.ret, 3.to_bytes32()); - Ok(()) -} - -#[test] -fn as_if() -> Result<()> { - let bytecode = common::load("call", "as_if")?; - let info = EVM::run(&bytecode, &0.to_bytes32()); - assert_eq!(info.ret, 0.to_bytes32()); - - let info = EVM::run(&bytecode, &1.to_bytes32()); - assert_eq!(info.ret, 1.to_bytes32()); - - let info = EVM::run(&bytecode, &2.to_bytes32()); - assert_eq!(info.ret, 41.to_bytes32()); - - let info = EVM::run(&bytecode, &3.to_bytes32()); - assert_eq!(info.ret, 42.to_bytes32()); - Ok(()) -} diff --git a/compiler/tests/common/mod.rs b/compiler/tests/common/mod.rs deleted file mode 100644 index c38571d74..000000000 --- a/compiler/tests/common/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! Shared module for tests. - -use anyhow::Result; -use std::{fs, path::PathBuf}; -use tracing::trace; -use tracing_subscriber::EnvFilter; -use wat; -use zinkc::Compiler; - -mod macros; - -fn setup_logger() { - tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .without_time() - .compact() - .try_init() - .ok(); -} - -/// Setup test environment. -fn compile(compiler: Compiler, instr: &str, name: &str) -> Result> { - setup_logger(); - - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(format!("wat/{instr}/{name}.wat")); - trace!("Loading {path:?}"); - - let wat = fs::read(path)?; - let wasm = wat::parse_bytes(&wat)?; - let bytecode = compiler.compile(&wasm)?.to_vec(); - tracing::trace!("bytecode: {:?}", hex::encode(&bytecode)); - Ok(bytecode) -} - -/// Load wat as wasm binary from path. -pub fn load(instr: &str, name: &str) -> Result> { - compile(Compiler::default(), instr, name) -} - -#[allow(unused)] -/// Load wat as wasm binary from path with dispatcher enabled. -pub fn load_with_dispatcher(instr: &str, name: &str) -> Result> { - let mut compiler = Compiler::default(); - compiler.with_dispatcher(); - compile(compiler, instr, name) -} diff --git a/compiler/tests/loop.rs b/compiler/tests/loop.rs deleted file mode 100644 index 4ffecce3c..000000000 --- a/compiler/tests/loop.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! loop tests - -use anyhow::Result; -use zint::{Bytes32, InstructionResult, EVM}; - -mod common; - -#[test] -fn singular() -> Result<()> { - let bytecode = common::load("loop", "singular")?; - - let info = EVM::run(&bytecode, &[]); - assert_eq!(info.ret, 7.to_bytes32()); - - Ok(()) -} - -#[test] -fn as_br_if() -> Result<()> { - let bytecode = common::load("loop", "as_br_if")?; - - let info = EVM::run(&bytecode, 0.to_bytes32().as_ref()); - assert_eq!(info.instr, InstructionResult::OutOfGas); - - let info = EVM::run(&bytecode, 1.to_bytes32().as_ref()); - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, 7.to_bytes32()); - - Ok(()) -} diff --git a/compiler/tests/select.rs b/compiler/tests/select.rs deleted file mode 100644 index e2184e879..000000000 --- a/compiler/tests/select.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Tests for instruction `select`. - -use anyhow::Result; -use zint::{Bytes32, EVM}; - -mod common; - -#[test] -fn params() -> Result<()> { - let bytecode = common::load("select", "params")?; - - // returns the bigger number. - let input = [1.to_bytes32(), 2.to_bytes32()].concat(); - let info = EVM::run(&bytecode, &input); - assert_eq!(info.ret, [2.to_bytes32()].concat()); - - let input = [2.to_bytes32(), 1.to_bytes32()].concat(); - let info = EVM::run(&bytecode, &input); - assert_eq!(info.ret, [2.to_bytes32()].concat()); - Ok(()) -} diff --git a/compiler/tests/storage.rs b/compiler/tests/storage.rs deleted file mode 100644 index f73190ceb..000000000 --- a/compiler/tests/storage.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! storage tests -#![cfg(test)] - -use anyhow::Result; -use zint::{Bytes32, InstructionResult, EVM, U256}; - -mod common; - -#[test] -fn store() -> Result<()> { - let bytecode = common::load("storage", "store")?; - let key = 0; - let value = 42; - let info = EVM::run(&bytecode, &value.to_bytes32()); - - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, []); - assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); - - Ok(()) -} - -#[test] -fn load() -> Result<()> { - let bytecode = common::load("storage", "load")?; - let value = 42.to_bytes32(); - let info = EVM::run(&bytecode, &value); - - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, value); - - Ok(()) -} - -#[test] -fn basic() -> Result<()> { - let bytecode = common::load("storage", "basic")?; - let info = EVM::run(&bytecode, &42.to_bytes32()); - - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, 42.to_bytes32()); - - Ok(()) -} - -#[test] -fn dispatcher() -> Result<()> { - let bytecode = common::load_with_dispatcher("storage", "dispatcher")?; - - // TODO: testing set (#122) - { - let key = 0; - let value = 42; - let mut selector = zabi::selector(b"set(i32)").to_vec(); - selector = [selector, 42.to_bytes32().to_vec()].concat(); - let info = EVM::run(&bytecode, &selector); - assert_eq!(info.instr, InstructionResult::Return); - assert_eq!(info.ret, []); - assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); - } - - // let info = EVM::run(&bytecode, &42.to_bytes32()); - - // assert_eq!(info.instr, InstructionResult::Return); - // assert_eq!(info.ret, 42.to_bytes32()); - - Ok(()) -} diff --git a/compiler/tests/sub.rs b/compiler/tests/sub.rs deleted file mode 100644 index bd34af1f6..000000000 --- a/compiler/tests/sub.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Addition tests for the zink compiler. -#![cfg(test)] - -use anyhow::Result; -use zint::{Bytes32, EVM}; - -mod common; - -fn params(module: &str) -> Result<()> { - let bytecode = common::load(module, "params")?; - - // add(1, 2) - let input = [2.to_bytes32(), 1.to_bytes32()].concat(); - let info = EVM::run(&bytecode, &input); - - assert_eq!(info.ret, [1.to_bytes32()].concat()); - Ok(()) -} - -fn locals(module: &str) -> Result<()> { - let bytecode = common::load(module, "locals")?; - let info = EVM::run(&bytecode, &[]); - - assert_eq!(info.ret, [10.to_bytes32()].concat()); - Ok(()) -} - -impl_tests! { - tests: [params, locals], - modules: ["i32sub", "i64sub"] -} diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml deleted file mode 100644 index f8481b264..000000000 --- a/examples/.cargo/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[build] -target = "wasm32-unknown-unknown" - -[target.wasm32-unknown-unknown] -rustflags = [ - "-C", "link-args=--import-memory", -] diff --git a/examples/Cargo.lock b/examples/Cargo.lock deleted file mode 100644 index 0fc9552e5..000000000 --- a/examples/Cargo.lock +++ /dev/null @@ -1,255 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addition" -version = "0.1.0" -dependencies = [ - "zink", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cobs" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" - -[[package]] -name = "cpufeatures" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "fibonacci" -version = "0.0.0" -dependencies = [ - "zink", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "if-else" -version = "0.1.0" -dependencies = [ - "zink", -] - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "libc" -version = "0.2.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" - -[[package]] -name = "log" -version = "0.1.0" -dependencies = [ - "zink", -] - -[[package]] -name = "postcard" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" -dependencies = [ - "cobs", - "embedded-io", - "serde", -] - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "storage" -version = "0.1.0" -dependencies = [ - "zink", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "zabi" -version = "0.1.4" -dependencies = [ - "hex", - "postcard", - "serde", - "sha3", - "thiserror", -] - -[[package]] -name = "zink" -version = "0.1.4" -dependencies = [ - "zink-codegen", -] - -[[package]] -name = "zink-codegen" -version = "0.1.4" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "zabi", -] diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index f8d33d2c1..000000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[workspace.package] -edition = "2021" -version = "0.0.0" -authors = [ "clearloop" ] -license = "GPL-v3.0" - -[workspace] -resolver = "2" -members = [ - "addition", - "fibonacci", - "if-else", - "log", - "storage" -] - -[workspace.dependencies] -zink = { path = "../zink" } diff --git a/examples/addition/src/lib.rs b/examples/addition.rs similarity index 50% rename from examples/addition/src/lib.rs rename to examples/addition.rs index f67061969..f673a51dc 100644 --- a/examples/addition/src/lib.rs +++ b/examples/addition.rs @@ -1,8 +1,6 @@ //! Addition example. -#![no_std] - -// for the panic handler. -#[cfg(not(test))] +#![cfg_attr(target_arch = "wasm32", no_std)] +#![cfg_attr(target_arch = "wasm32", no_main)] extern crate zink; /// Adds two numbers together. @@ -10,3 +8,6 @@ extern crate zink; pub fn addition(x: u64, y: u64) -> u64 { x + y } + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} diff --git a/examples/addition/Cargo.toml b/examples/addition/Cargo.toml deleted file mode 100644 index 8e7172bf6..000000000 --- a/examples/addition/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "addition" -version = "0.1.0" -edition.workspace = true - -[lib] -crate-type = ["cdylib"] - -[dependencies] -zink.workspace = true diff --git a/examples/fibonacci/src/lib.rs b/examples/fibonacci.rs similarity index 52% rename from examples/fibonacci/src/lib.rs rename to examples/fibonacci.rs index 8a0dea500..2ace4e05f 100644 --- a/examples/fibonacci/src/lib.rs +++ b/examples/fibonacci.rs @@ -1,22 +1,25 @@ //! fibonacci example. -#![no_std] +#![cfg_attr(target_arch = "wasm32", no_std)] +#![cfg_attr(target_arch = "wasm32", no_main)] // for the panic handler. -#[cfg(not(test))] extern crate zink; /// Calculates the nth fibonacci number. -#[no_mangle] -pub extern "C" fn fibonacci(n: usize) -> usize { +#[zink::external] +pub fn fibonacci(n: usize) -> usize { recursion(n) } /// Calculates the nth fibonacci number using recursion. -#[no_mangle] -pub extern "C" fn recursion(n: usize) -> usize { +#[zink::external] +pub fn recursion(n: usize) -> usize { if n < 2 { n } else { recursion(n - 1) + recursion(n - 2) } } + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} diff --git a/examples/fibonacci/Cargo.toml b/examples/fibonacci/Cargo.toml deleted file mode 100644 index 5eb926250..000000000 --- a/examples/fibonacci/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "fibonacci" -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true - -[lib] -crate-type = ["cdylib"] - -[dependencies] -zink.workspace = true diff --git a/examples/if-else.rs b/examples/if-else.rs new file mode 100644 index 000000000..cc5b0cd3e --- /dev/null +++ b/examples/if-else.rs @@ -0,0 +1,18 @@ +//! if-else example. +#![cfg_attr(target_arch = "wasm32", no_std)] +#![cfg_attr(target_arch = "wasm32", no_main)] + +extern crate zink; + +/// Simple if-else condition +#[zink::external] +pub fn if_else(x: u64, y: u64) -> u64 { + if x > y { + x + } else { + y + } +} + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} diff --git a/examples/if-else/Cargo.toml b/examples/if-else/Cargo.toml deleted file mode 100644 index c0826ea89..000000000 --- a/examples/if-else/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "if-else" -version = "0.1.0" -edition.workspace = true - -[lib] -crate-type = ["cdylib"] - -[dependencies] -zink.workspace = true diff --git a/examples/if-else/src/lib.rs b/examples/if-else/src/lib.rs deleted file mode 100644 index 11cde6e56..000000000 --- a/examples/if-else/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! if-else example. -#![no_std] - -// for the panic handler. -#[cfg(not(test))] -extern crate zink; - -/// Simple if-else condition -#[no_mangle] -pub extern "C" fn if_else(x: u64, y: u64) -> u64 { - if x > y { - x - } else { - y - } -} diff --git a/examples/log.rs b/examples/log.rs new file mode 100644 index 000000000..6f101db78 --- /dev/null +++ b/examples/log.rs @@ -0,0 +1,39 @@ +//! Addition example. +#![cfg_attr(target_arch = "wasm32", no_std)] +#![cfg_attr(target_arch = "wasm32", no_main)] + +extern crate zink; + +use zink::Event; + +/// A `Ping` event. +#[derive(Event)] +struct Ping; + +#[zink::external] +pub fn log0() { + Ping.log0(); +} + +#[zink::external] +pub fn log1() { + Ping.log1(b"pong"); +} + +#[zink::external] +pub fn log2() { + Ping.log2(b"pong", b"ping"); +} + +#[zink::external] +pub fn log3() { + Ping.log3(b"pong", b"ping", b"pong"); +} + +#[zink::external] +pub fn log4() { + Ping.log4(b"pong", b"ping", b"pong", b"pong"); +} + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} diff --git a/examples/log/Cargo.toml b/examples/log/Cargo.toml deleted file mode 100644 index 9f59b2802..000000000 --- a/examples/log/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "log" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -zink.workspace = true diff --git a/examples/log/src/lib.rs b/examples/log/src/lib.rs deleted file mode 100644 index bf0b1ec0b..000000000 --- a/examples/log/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Addition example. -#![no_std] - -// for the panic handler. -#[cfg(not(test))] -extern crate zink; - -use zink::Event; - -/// A `Ping` event. -#[derive(Event)] -struct Ping; - -#[no_mangle] -pub extern "C" fn log0() { - Ping.log0(); -} - -#[no_mangle] -pub extern "C" fn log1() { - Ping.log1(b"pong"); -} - -#[no_mangle] -pub extern "C" fn log2() { - Ping.log2(b"pong", b"ping"); -} - -#[no_mangle] -pub extern "C" fn log3() { - Ping.log3(b"pong", b"ping", b"pong"); -} - -#[no_mangle] -pub extern "C" fn log4() { - Ping.log4(b"pong", b"ping", b"pong", b"pong"); -} diff --git a/examples/storage/src/lib.rs b/examples/storage.rs similarity index 80% rename from examples/storage/src/lib.rs rename to examples/storage.rs index b658a9496..9661e594c 100644 --- a/examples/storage/src/lib.rs +++ b/examples/storage.rs @@ -1,8 +1,7 @@ -//! Addition example. -#![no_std] +//! Storage example. +#![cfg_attr(target_arch = "wasm32", no_std)] +#![cfg_attr(target_arch = "wasm32", no_main)] -// for the panic handler. -#[cfg(not(test))] extern crate zink; use zink::Storage; @@ -35,3 +34,6 @@ pub fn set(value: i32) { pub fn get() -> i32 { Counter::get() } + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} diff --git a/examples/storage/Cargo.toml b/examples/storage/Cargo.toml deleted file mode 100644 index c9471aed2..000000000 --- a/examples/storage/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "storage" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -zink.workspace = true diff --git a/tests/add.rs b/tests/add.rs new file mode 100644 index 000000000..d8bfabcef --- /dev/null +++ b/tests/add.rs @@ -0,0 +1,40 @@ +//! Addition tests for the zink compiler. +#![cfg(test)] + +use anyhow::Result; +use zinkc_filetests::{impl_tests, Test}; +use zint::{Bytes32, Contract}; + +fn params(module: &str) -> Result<()> { + let mut contract = Contract::new(Test::load(module, "params")?.wasm) + .without_dispatcher() + .compile()?; + + // add(1, 2) + let info = contract.execute([1, 2])?; + assert_eq!(info.ret, [3.to_bytes32()].concat()); + Ok(()) +} + +fn locals(module: &str) -> Result<()> { + let mut contract = Contract::new(Test::load(module, "locals")?.wasm) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; + assert_eq!(info.ret, [30.to_bytes32()].concat()); + Ok(()) +} + +fn tee(module: &str) -> Result<()> { + let mut contract = Contract::new(Test::load(module, "tee")?.wasm) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; + assert_eq!(info.ret, [30.to_bytes32()].concat()); + Ok(()) +} + +impl_tests! { + tests: [params, locals, tee], + modules: ["i32add", "i64add"] +} diff --git a/tests/br_if.rs b/tests/br_if.rs new file mode 100644 index 000000000..258233f0b --- /dev/null +++ b/tests/br_if.rs @@ -0,0 +1,21 @@ +//! br_if tests for the zink compiler. +use anyhow::Result; +use zinkc_filetests::Test; +use zint::{Contract, InstructionResult}; + +#[test] +fn as_block_last() -> Result<()> { + let mut contract = Contract::new(Test::BR_IF_AS_BLOCK_LAST) + .without_dispatcher() + .compile()?; + + let info = contract.execute(&[0])?; + assert_eq!(info.instr, InstructionResult::Return); + assert!(info.ret.is_empty()); + + let info = contract.execute(&[42])?; + assert_eq!(info.instr, InstructionResult::OutOfGas); + assert!(info.ret.is_empty()); + + Ok(()) +} diff --git a/tests/call.rs b/tests/call.rs new file mode 100644 index 000000000..c5b0c04fa --- /dev/null +++ b/tests/call.rs @@ -0,0 +1,49 @@ +//! if-else tests for the zink compiler. +#![cfg(test)] + +use anyhow::Result; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract, InstructionResult}; + +#[test] +fn dummy() -> Result<()> { + let mut contract = Contract::new(Test::CALL_DUMMY) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; + + assert_eq!(info.instr, InstructionResult::Return); + assert!(info.ret.is_empty()); + Ok(()) +} + +#[test] +fn params() -> Result<()> { + let mut contract = Contract::new(Test::CALL_PARAMS) + .without_dispatcher() + .compile()?; + let info = contract.execute([1, 2])?; + + assert_eq!(info.ret, 3.to_bytes32()); + Ok(()) +} + +#[test] +fn as_if() -> Result<()> { + let mut contract = Contract::new(Test::CALL_AS_IF) + .without_dispatcher() + .compile()?; + + let info = contract.execute([0])?; + assert_eq!(info.ret, 0.to_bytes32()); + + let info = contract.execute([1])?; + assert_eq!(info.ret, 1.to_bytes32()); + + let info = contract.execute([2])?; + assert_eq!(info.ret, 41.to_bytes32()); + + let info = contract.execute([3])?; + assert_eq!(info.ret, 42.to_bytes32()); + Ok(()) +} diff --git a/compiler/tests/if.rs b/tests/if.rs similarity index 51% rename from compiler/tests/if.rs rename to tests/if.rs index 20c87966c..7ae1536ae 100644 --- a/compiler/tests/if.rs +++ b/tests/if.rs @@ -1,22 +1,22 @@ //! if-else tests for the zink compiler. -#![cfg(test)] - use anyhow::Result; -use zint::{Bytes32, InstructionResult, EVM}; - -mod common; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract, InstructionResult}; #[test] fn if_then() -> Result<()> { - let bytecode = common::load("if", "basic")?; + let mut contract = Contract::new(Test::IF_BASIC) + .without_dispatcher() + .compile()?; // Skip the condition. - let info = EVM::run(&bytecode, &[0; 32]); - assert_eq!(info.ret, [0; 32]); + let input = [0; 32]; + let info = contract.execute(&[input])?; + assert_eq!(info.ret, input); // Enter the if branch. let input = 1.to_bytes32(); - let info = EVM::run(&bytecode, &input); + let info = contract.execute(&[input])?; assert_eq!(info.ret, input); Ok(()) @@ -24,17 +24,19 @@ fn if_then() -> Result<()> { #[test] fn singular() -> Result<()> { - let bytecode = common::load("if", "singular")?; + let mut contract = Contract::new(Test::IF_SINGULAR) + .without_dispatcher() + .compile()?; // test if // // Enter if block if 1 - let info = EVM::run(&bytecode, &1.to_bytes32()); + let info = contract.execute(&[1])?; assert_eq!(info.instr, InstructionResult::Return); assert_eq!(info.ret, 7.to_bytes32()); // test else - let info = EVM::run(&bytecode, &0.to_bytes32()); + let info = contract.execute(&[0])?; assert_eq!(info.instr, InstructionResult::Return); assert_eq!(info.ret, 8.to_bytes32()); diff --git a/compiler/tests/common/macros.rs b/tests/lib.rs similarity index 95% rename from compiler/tests/common/macros.rs rename to tests/lib.rs index dfd6a625c..2108276b4 100644 --- a/compiler/tests/common/macros.rs +++ b/tests/lib.rs @@ -1,5 +1,3 @@ -//! Shared macros - #[macro_export] macro_rules! impl_tests { ( diff --git a/compiler/tests/log.rs b/tests/log.rs similarity index 68% rename from compiler/tests/log.rs rename to tests/log.rs index 68cc74afa..aa86da831 100644 --- a/compiler/tests/log.rs +++ b/tests/log.rs @@ -1,26 +1,28 @@ //! Tests for instruction `select`. use anyhow::Result; -use zint::{Bytes32, EVM}; - -mod common; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract}; #[test] fn log0() -> Result<()> { - let bytecode = common::load("log", "log0")?; + let mut contract = Contract::new(Test::LOG_LOG0) + .without_dispatcher() + .compile()?; // returns the bigger number. - let info = EVM::run(&bytecode, &[]); + let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); Ok(()) } #[test] fn log1() -> Result<()> { - let bytecode = common::load("log", "log1")?; + let mut contract = Contract::new(Test::LOG_LOG1) + .without_dispatcher() + .compile()?; - // returns the bigger number. - let info = EVM::run(&bytecode, &[]); + let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); assert_eq!( info.logs[0].topics[0].to_vec(), @@ -31,10 +33,11 @@ fn log1() -> Result<()> { #[test] fn log2() -> Result<()> { - let bytecode = common::load("log", "log2")?; + let mut contract = Contract::new(Test::LOG_LOG2) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; - // returns the bigger number. - let info = EVM::run(&bytecode, &[]); assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); assert_eq!( info.logs[0].topics[0].to_vec(), @@ -49,10 +52,11 @@ fn log2() -> Result<()> { #[test] fn log3() -> Result<()> { - let bytecode = common::load("log", "log3")?; + let mut contract = Contract::new(Test::LOG_LOG3) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; - // returns the bigger number. - let info = EVM::run(&bytecode, &[]); assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); assert_eq!( info.logs[0].topics[0].to_vec(), @@ -71,10 +75,11 @@ fn log3() -> Result<()> { #[test] fn log4() -> Result<()> { - let bytecode = common::load("log", "log4")?; + let mut contract = Contract::new(Test::LOG_LOG4) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; - // returns the bigger number. - let info = EVM::run(&bytecode, &[]); assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); assert_eq!( info.logs[0].topics[0].to_vec(), diff --git a/tests/loop.rs b/tests/loop.rs new file mode 100644 index 000000000..e1866de9d --- /dev/null +++ b/tests/loop.rs @@ -0,0 +1,32 @@ +//! loop tests + +use anyhow::Result; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract, InstructionResult}; + +#[test] +fn singular() -> Result<()> { + let mut contract = Contract::new(Test::LOOP_SINGULAR) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; + + assert_eq!(info.ret, 7.to_bytes32()); + + Ok(()) +} + +#[test] +fn as_br_if() -> Result<()> { + let mut contract = Contract::new(Test::LOOP_AS_BR_IF) + .without_dispatcher() + .compile()?; + let info = contract.execute([0])?; + assert_eq!(info.instr, InstructionResult::OutOfGas); + + let info = contract.execute([1])?; + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, 7.to_bytes32()); + + Ok(()) +} diff --git a/compiler/tests/recursion.rs b/tests/recursion.rs similarity index 52% rename from compiler/tests/recursion.rs rename to tests/recursion.rs index 458620db0..1ad1ed580 100644 --- a/compiler/tests/recursion.rs +++ b/tests/recursion.rs @@ -1,34 +1,35 @@ use anyhow::Result; -use zint::{Bytes32, EVM}; - -mod common; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract}; #[test] fn fibonacci() -> Result<()> { - let bytecode = common::load("recursion", "fibonacci")?; + let mut contract = Contract::new(Test::RECURSION_FIBONACCI) + .without_dispatcher() + .compile()?; // x = 0 - let info = EVM::run(&bytecode, &0.to_bytes32()); + let info = contract.execute([0])?; assert_eq!(0.to_bytes32().to_vec(), info.ret); // x = 1 - let info = EVM::run(&bytecode, &1.to_bytes32()); + let info = contract.execute([1])?; assert_eq!(1.to_bytes32().to_vec(), info.ret); // x = 2 - let info = EVM::run(&bytecode, &2.to_bytes32()); + let info = contract.execute([2])?; assert_eq!(1.to_bytes32().to_vec(), info.ret); // x = 3 - let info = EVM::run(&bytecode, &3.to_bytes32()); + let info = contract.execute([3])?; assert_eq!(2.to_bytes32().to_vec(), info.ret); // x = 4 - let info = EVM::run(&bytecode, &4.to_bytes32()); + let info = contract.execute([4])?; assert_eq!(3.to_bytes32().to_vec(), info.ret); // x = 5 - let info = EVM::run(&bytecode, &5.to_bytes32()); + let info = contract.execute([5])?; assert_eq!(5.to_bytes32().to_vec(), info.ret); Ok(()) diff --git a/tests/select.rs b/tests/select.rs new file mode 100644 index 000000000..9e3b0d0a9 --- /dev/null +++ b/tests/select.rs @@ -0,0 +1,18 @@ +//! Tests for instruction `select`. + +use anyhow::Result; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract}; + +#[test] +fn params() -> Result<()> { + let mut contract = Contract::new(Test::SELECT_PARAMS) + .without_dispatcher() + .compile()?; + let info = contract.execute([1, 2])?; + assert_eq!(info.ret, [2.to_bytes32()].concat()); + + let info = contract.execute([2, 1])?; + assert_eq!(info.ret, [2.to_bytes32()].concat()); + Ok(()) +} diff --git a/tests/storage.rs b/tests/storage.rs new file mode 100644 index 000000000..910024915 --- /dev/null +++ b/tests/storage.rs @@ -0,0 +1,82 @@ +//! storage tests +#![cfg(test)] + +use anyhow::Result; +use zinkc_filetests::Test; +use zint::{Bytes32, Contract, InstructionResult, U256}; + +#[test] +fn store() -> Result<()> { + let mut contract = Contract::new(Test::STORAGE_STORE) + .without_dispatcher() + .compile()?; + + let key = 0; + let value = 42; + let info = contract.execute([value])?; + assert!(info.ret.is_empty()); + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); + + Ok(()) +} + +#[test] +fn load() -> Result<()> { + let mut contract = Contract::new(Test::STORAGE_LOAD) + .without_dispatcher() + .compile()?; + + let value = 42; + let info = contract.execute([value])?; + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, value.to_bytes32()); + + Ok(()) +} + +#[test] +fn basic() -> Result<()> { + let mut contract = Contract::new(Test::STORAGE_BASIC) + .without_dispatcher() + .compile()?; + + let value = 42; + let info = contract.execute([value])?; + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, 42.to_bytes32()); + + Ok(()) +} + +#[test] +fn dispatcher() -> Result<()> { + let mut contract = Contract::new(Test::STORAGE_DISPATCHER).compile()?; + + { + let key = 0; + let value: i32 = 42; + let info = contract.execute(&[b"set(i32)".to_vec(), value.to_bytes32().to_vec()])?; + assert!(info.ret.is_empty()); + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); + } + + { + let info = contract.execute(&["get()"])?; + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, 0.to_bytes32()); + } + + { + let key = 0; + let value = 42; + let info = + contract.execute(&[b"set_and_get(i32)".to_vec(), value.to_bytes32().to_vec()])?; + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, value.to_bytes32()); + assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); + } + + Ok(()) +} diff --git a/tests/sub.rs b/tests/sub.rs new file mode 100644 index 000000000..dc4b175ae --- /dev/null +++ b/tests/sub.rs @@ -0,0 +1,31 @@ +//! Addition tests for the zink compiler. +#![cfg(test)] + +use anyhow::Result; +use zinkc_filetests::{impl_tests, Test}; +use zint::{Bytes32, Contract}; + +fn params(module: &str) -> Result<()> { + let mut contract = Contract::new(Test::load(module, "params")?.wasm) + .without_dispatcher() + .compile()?; + let info = contract.execute([2, 1])?; + + assert_eq!(info.ret, [1.to_bytes32()].concat()); + Ok(()) +} + +fn locals(module: &str) -> Result<()> { + let mut contract = Contract::new(Test::load(module, "locals")?.wasm) + .without_dispatcher() + .compile()?; + let info = contract.execute::<()>([])?; + + assert_eq!(info.ret, [10.to_bytes32()].concat()); + Ok(()) +} + +impl_tests! { + tests: [params, locals], + modules: ["i32sub", "i64sub"] +} diff --git a/zink/Cargo.toml b/zink/Cargo.toml deleted file mode 100644 index cd5418501..000000000 --- a/zink/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "zink" -description = "Standard library for zink projects." -documentation = "https://docs.rs/zink" -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -zink-codegen.workspace = true diff --git a/zink/codegen/src/selector.rs b/zink/codegen/src/selector.rs index 70754e5c8..823ff55b0 100644 --- a/zink/codegen/src/selector.rs +++ b/zink/codegen/src/selector.rs @@ -24,6 +24,7 @@ pub fn external(mut item: ItemFn) -> TokenStream { parse_quote! { #[no_mangle] + #[cfg(target_arch = "wasm32")] #[doc = #doc] pub extern "C" fn #ident() { unsafe { diff --git a/zink/src/ffi.rs b/zink/src/ffi.rs new file mode 100644 index 000000000..7bd4364ca --- /dev/null +++ b/zink/src/ffi.rs @@ -0,0 +1,48 @@ +//! Zink FFI. + +#[link(wasm_import_module = "zinkc")] +#[allow(improper_ctypes)] +extern "C" { + /// Emit ABI to host state. + pub fn emit_abi(ptr: u32, len: u32); + +} + +/// EVM interfaces. +pub mod evm { + #[link(wasm_import_module = "evm")] + #[allow(improper_ctypes)] + extern "C" { + /// Store a value in the storage + pub fn sstore(value: i32, key: i32); + + /// Load a value from the storage + pub fn sload(key: i32) -> i32; + + /// Append log record with no topics + pub fn log0(name: &'static [u8]); + + /// Append log record with one topics + pub fn log1(name: &'static [u8], topic1: &'static [u8]); + + /// Append log record with two topics + pub fn log2(name: &'static [u8], topic1: &'static [u8], topic2: &'static [u8]); + + /// Append log record with three topics + pub fn log3( + name: &'static [u8], + topic1: &'static [u8], + topic2: &'static [u8], + topic3: &'static [u8], + ); + + /// Append log record with four topics + pub fn log4( + name: &'static [u8], + topic1: &'static [u8], + topic2: &'static [u8], + topic3: &'static [u8], + topic4: &'static [u8], + ); + } +} diff --git a/zink/src/ffi/evm.rs b/zink/src/ffi/evm.rs deleted file mode 100644 index 09af6e9ec..000000000 --- a/zink/src/ffi/evm.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! EVM imports - -// EVM interfaces -// -// TODO: Align to 256-bit #20. -#[link(wasm_import_module = "evm")] -#[allow(improper_ctypes)] -extern "C" { - // i32 -> 8 bytes - - /// Store a value in the storage - pub fn sstore(value: i32, key: i32); - - /// Load a value from the storage - pub fn sload(key: i32) -> i32; - - /// Append log record with no topics - pub fn log0(name: &'static [u8]); - - /// Append log record with one topics - pub fn log1(name: &'static [u8], topic1: &'static [u8]); - - /// Append log record with two topics - pub fn log2(name: &'static [u8], topic1: &'static [u8], topic2: &'static [u8]); - - /// Append log record with three topics - pub fn log3( - name: &'static [u8], - topic1: &'static [u8], - topic2: &'static [u8], - topic3: &'static [u8], - ); - - /// Append log record with four topics - pub fn log4( - name: &'static [u8], - topic1: &'static [u8], - topic2: &'static [u8], - topic3: &'static [u8], - topic4: &'static [u8], - ); - - /// Copy code running in current environment to memory - pub fn codecopy(destOffset: u32, codeOffset: u32, size: u32); -} diff --git a/zink/src/ffi/mod.rs b/zink/src/ffi/mod.rs deleted file mode 100644 index 534022296..000000000 --- a/zink/src/ffi/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Zink bindings for compilation -//! -//! Host functions in this module will not -//! being compiled to bytecode, but will be -//! called by the compiler. - -pub mod evm; - -// Zinkc interfaces -#[link(wasm_import_module = "zinkc")] -#[allow(improper_ctypes)] -extern "C" { - /// Emit ABI to host state. - pub fn emit_abi(ptr: u32, len: u32); -} diff --git a/zink/src/lib.rs b/zink/src/lib.rs index 45894a708..9743d93bc 100644 --- a/zink/src/lib.rs +++ b/zink/src/lib.rs @@ -9,7 +9,7 @@ pub use traits::{Event, Storage}; pub use zink_codegen::{external, storage, Event}; // Panic hook implementation -#[cfg(not(test))] +#[cfg(target_arch = "wasm32")] #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} diff --git a/zint/Cargo.toml b/zint/Cargo.toml index 00b7cf11c..aa116405b 100644 --- a/zint/Cargo.toml +++ b/zint/Cargo.toml @@ -10,6 +10,15 @@ homepage.workspace = true repository.workspace = true [dependencies] +anyhow.workspace = true +cargo_metadata.workspace = true +etc.workspace = true hex.workspace = true revm.workspace = true +serde = { workspace = true, features = [ "derive" ] } tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"]} +toml.workspace = true +wasm-opt.workspace = true +zabi.workspace = true +zinkc.workspace = true diff --git a/zint/src/bytes.rs b/zint/src/bytes.rs index 5e530fe42..90707ad06 100644 --- a/zint/src/bytes.rs +++ b/zint/src/bytes.rs @@ -4,6 +4,9 @@ pub trait Bytes32: Sized { /// Convert type to the lowest significant bytes 32. fn to_bytes32(&self) -> [u8; 32]; + + /// Convert type to vec of bytes. + fn to_vec(&self) -> Vec; } /// Implement Bytes32 for types. @@ -27,6 +30,10 @@ macro_rules! impl_bytes32 { bytes[(32 - ls_bytes.len())..].copy_from_slice(&ls_bytes); bytes } + + fn to_vec(&self) -> Vec { + self.to_le_bytes().to_vec() + } } )+ }; @@ -38,6 +45,20 @@ impl Bytes32 for Vec { bytes[(32 - self.len())..].copy_from_slice(self); bytes } + + fn to_vec(&self) -> Vec { + self.clone() + } +} + +impl Bytes32 for [u8; 32] { + fn to_bytes32(&self) -> [u8; 32] { + *self + } + + fn to_vec(&self) -> Vec { + self.as_ref().into() + } } impl Bytes32 for &[u8] { @@ -46,6 +67,32 @@ impl Bytes32 for &[u8] { bytes[(32 - self.len())..].copy_from_slice(self); bytes } + + fn to_vec(&self) -> Vec { + (*self).into() + } +} + +impl Bytes32 for () { + fn to_bytes32(&self) -> [u8; 32] { + [0; 32] + } + + fn to_vec(&self) -> Vec { + Default::default() + } +} + +impl Bytes32 for &str { + fn to_bytes32(&self) -> [u8; 32] { + let mut bytes = [0u8; 32]; + bytes[(32 - self.len())..].copy_from_slice(self.as_bytes()); + bytes + } + + fn to_vec(&self) -> Vec { + self.as_bytes().into() + } } impl_bytes32!(i8, u8, i16, u16, i32, u32, usize, i64, u64, i128, u128); diff --git a/zint/src/contract.rs b/zint/src/contract.rs new file mode 100644 index 000000000..07700e742 --- /dev/null +++ b/zint/src/contract.rs @@ -0,0 +1,140 @@ +//! Contract Instance + +use crate::{Bytes32, Info, EVM}; +use anyhow::{anyhow, Result}; +use serde::Deserialize; +use std::{ + fs, + path::{Path, PathBuf}, +}; +use wasm_opt::OptimizationOptions; +use zinkc::Compiler; + +/// Cargo Package for parsing package name. +#[derive(Deserialize)] +struct Package { + name: String, +} + +/// Contract instance for testing. +#[derive(Default)] +pub struct Contract { + /// The bytecode of the contract. + pub bytecode: Vec, + /// If enable dispatcher. + pub dispatcher: bool, + /// The source WASM of the contract. + pub wasm: Vec, +} + +impl Contract { + /// Get the current target directory. + fn target_dir() -> Result { + cargo_metadata::MetadataCommand::new() + .no_deps() + .exec() + .map_err(Into::into) + .map(|metadata| { + metadata + .target_directory + .join("wasm32-unknown-unknown") + .into() + }) + } + + /// Run wasm-opt on the given WASM file. + fn wasm_opt(wasm: impl AsRef) -> Result<()> { + OptimizationOptions::new_opt_level_4() + .debug_info(false) + .mvp_features_only() + .set_converge() + .run(&wasm, &wasm) + .map_err(Into::into) + } + + /// Create new contract + pub fn new(wasm: impl AsRef<[u8]>) -> Self { + crate::setup_logger(); + + Self { + wasm: wasm.as_ref().into(), + dispatcher: true, + ..Default::default() + } + } + + /// Disable dispatcher. + pub fn without_dispatcher(mut self) -> Self { + self.dispatcher = false; + self + } + + /// Compile WASM to EVM bytecode. + pub fn compile(mut self) -> Result { + self.bytecode = Compiler::default() + .dispatcher(self.dispatcher) + .compile(&self.wasm)? + .to_vec(); + + tracing::trace!("bytecode: {:?}", hex::encode(&self.bytecode)); + Ok(self) + } + + /// Load zink contract defined in the current + /// package. + pub fn current() -> Result { + let manifest = fs::read_to_string(etc::find_up("Cargo.toml")?)?; + let name = toml::from_str::(&manifest)?.name; + + Self::search(&name) + } + + /// Search for zink contract in the target + /// directory. + pub fn search(name: &str) -> Result { + let target = Self::target_dir()?; + let search = |profile: &str| -> Result { + let target = target.join(profile); + let mut wasm = target.join(name).with_extension("wasm"); + if !wasm.exists() { + wasm = target.join("examples").join(name).with_extension("wasm"); + } + + if wasm.exists() { + Ok(wasm) + } else { + Err(anyhow::anyhow!("{} not found", wasm.to_string_lossy())) + } + }; + + let wasm = search("release").or_else(|_| search("debug"))?; + Self::wasm_opt(&wasm)?; + + tracing::debug!("loading contract from {}", wasm.display()); + Ok(Self::new(fs::read(wasm)?)) + } + + /// Execute the contract. + pub fn execute(&mut self, inputs: impl AsRef<[Param]>) -> Result + where + Param: Bytes32, + { + let mut calldata = Vec::new(); + let mut inputs = inputs.as_ref(); + if self.dispatcher { + if inputs.is_empty() { + return Err(anyhow!("no selector provided")); + } + + calldata.extend_from_slice(&zabi::selector(&inputs[0].to_vec())); + inputs = &inputs[1..]; + } + + for input in inputs { + calldata.extend_from_slice(&input.to_bytes32()); + } + + tracing::debug!("calldata: 0x{:?}", hex::encode(&calldata)); + Ok(EVM::run(&self.bytecode, &calldata)) + } +} diff --git a/zint/src/lib.rs b/zint/src/lib.rs index 8e2f791db..87d828137 100644 --- a/zint/src/lib.rs +++ b/zint/src/lib.rs @@ -2,9 +2,22 @@ #![deny(missing_docs)] mod bytes; +mod contract; mod evm; pub use self::{ bytes::Bytes32, + contract::Contract, evm::{Info, InstructionResult, EVM, U256}, }; +use tracing_subscriber::EnvFilter; + +/// Set up the logger. +pub fn setup_logger() { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .without_time() + .compact() + .try_init() + .ok(); +}