From 399ecfcd393a596aa46faf373a20182d46cd09a8 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 28 Dec 2023 19:06:49 +0800 Subject: [PATCH] feat(zinkc): introduce artifact as compiler output (#210) * feat(compiler): introduce instance artifact as compiler output * refactor(compiler): remove config constructor * refactor(zint): use pure instead of without_dispatcher * feat(zint): introduce module lookup * feat(codegen): remove lifetime for dispatcher * chore(abi): use tiny-keccak instead of sha3 * docs(RELEASES): append release note for v0.1.10 * chore(deps): update dependencies --- Cargo.lock | 138 ++++++++++++---------------- Cargo.toml | 26 +++--- RELEASES.md | 10 +++ abi/Cargo.toml | 5 +- abi/src/selector.rs | 8 +- codegen/Cargo.toml | 2 +- codegen/src/codegen/constructor.rs | 24 ++--- codegen/src/codegen/dispatcher.rs | 69 +++++++------- compiler/Cargo.toml | 6 +- compiler/src/artifact.rs | 46 ++++++++++ compiler/src/cli.rs | 8 +- compiler/src/compiler.rs | 39 +++----- compiler/src/config.rs | 9 +- compiler/src/lib.rs | 2 + elko/src/build.rs | 4 +- examples/constructor.rs | 7 +- tests/add.rs | 12 +-- tests/br_if.rs | 4 +- tests/call.rs | 12 +-- tests/if.rs | 8 +- tests/log.rs | 20 ++--- tests/loop.rs | 8 +- tests/recursion.rs | 4 +- tests/select.rs | 4 +- tests/storage.rs | 12 +-- tests/sub.rs | 8 +- zink/codegen/Cargo.toml | 2 +- zink/codegen/src/selector.rs | 6 +- zint/src/contract.rs | 139 +++++++++-------------------- zint/src/lib.rs | 1 + zint/src/lookup.rs | 59 ++++++++++++ 31 files changed, 341 insertions(+), 361 deletions(-) create mode 100644 compiler/src/artifact.rs create mode 100644 zint/src/lookup.rs diff --git a/Cargo.lock b/Cargo.lock index 0ab3567e2..c3a99ae6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,25 +63,24 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" dependencies = [ "alloy-rlp-derive", "arrayvec", "bytes", - "smol_str", ] [[package]] name = "alloy-rlp-derive" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" +checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -134,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.76" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" +checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" [[package]] name = "arrayvec" @@ -208,7 +207,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.42", + "syn 2.0.43", "which", ] @@ -395,7 +394,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -527,9 +526,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" +checksum = "e9fc0c733f71e58dedf4f034cd2a266f80b94cc9ed512729e1798651b68c2cba" dependencies = [ "cc", "cxxbridge-flags", @@ -539,9 +538,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" +checksum = "51bc81d2664db24cf1d35405f66e18a85cffd4d49ab930c71a5c6342a410f38c" dependencies = [ "cc", "codespan-reporting", @@ -549,24 +548,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] name = "cxxbridge-flags" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" +checksum = "8511afbe34ea242697784da5cb2c5d4a0afb224ca8b136bdf93bfe180cbe5884" [[package]] name = "cxxbridge-macro" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" +checksum = "5c6888cd161769d65134846d4d4981d5a6654307cc46ec83fb917e530aea5f84" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -626,7 +625,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elko" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "cargo_metadata", @@ -674,7 +673,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -879,15 +878,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1091,9 +1081,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -1168,7 +1158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1532,7 +1522,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1548,9 +1538,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -1566,16 +1556,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -1607,22 +1587,13 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - [[package]] name = "sol-abi" version = "0.0.1" dependencies = [ "quote", "serde", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1698,9 +1669,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.42" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -1715,15 +1686,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1737,22 +1708,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1836,7 +1807,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -2193,9 +2164,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" dependencies = [ "memchr", ] @@ -2211,15 +2182,15 @@ dependencies = [ [[package]] name = "zabi" -version = "0.1.9" +version = "0.1.10" dependencies = [ "hex", "postcard", "serde", - "sha3", "sol-abi", - "syn 2.0.42", + "syn 2.0.43", "thiserror", + "tiny-keccak", ] [[package]] @@ -2239,7 +2210,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -2259,12 +2230,12 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] name = "zingen" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "evm-opcodes", @@ -2279,7 +2250,7 @@ dependencies = [ [[package]] name = "zink" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "paste", @@ -2290,23 +2261,24 @@ dependencies = [ [[package]] name = "zink-codegen" -version = "0.1.9" +version = "0.1.10" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", "zabi", ] [[package]] name = "zinkc" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "ccli", "etc", "hex", "paste", + "serde", "serde_json", "thiserror", "tracing", @@ -2320,13 +2292,13 @@ dependencies = [ [[package]] name = "zinkc-filetests" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "cargo_metadata", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", "tracing", "tracing-subscriber", "wat", @@ -2335,7 +2307,7 @@ dependencies = [ [[package]] name = "zint" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "cargo_metadata", diff --git a/Cargo.toml b/Cargo.toml index c7ba3c30c..bcfbf2934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.1.9" +version = "0.1.10" authors = ["clearloop"] edition = "2021" license = "GPL-3.0-only" @@ -25,7 +25,7 @@ homepage = "https://github.com/clearloop/zink" repository = "https://github.com/clearloop/zink.git" [workspace.dependencies] -anyhow = "1.0.76" +anyhow = "1.0.77" cargo_metadata = "0.18.1" ccli = "0.0.1" colored = "2.1.0" @@ -40,10 +40,10 @@ revm = { version = "3.5.0", default-features = false } semver = "1.0.20" serde = { version = "1.0.193", default-features = false } serde_json = "1.0.108" -sha3 = "0.10.8" smallvec = "1.11.2" -syn = { version = "2.0.42", features = [ "full" ] } -thiserror = "1.0.51" +syn = { version = "2.0.43", features = [ "full" ] } +thiserror = "1.0.52" +tiny-keccak = "2.0.2" toml = "0.8.8" tracing = "0.1.40" tracing-subscriber = "0.3.18" @@ -56,14 +56,14 @@ opcodes = { package = "evm-opcodes", path = "evm/opcodes", version = "=0.0.3", f sol-abi = { path = "evm/abi", version = "=0.0.1" } ## Zink packages -elko = { path = "elko", version = "0.1.9" } -filetests = { package = "zinkc-filetests", path = "compiler/filetests", version = "0.1.9" } -zabi = { path = "abi", version = "0.1.9" } -zingen = { path = "codegen", version = "0.1.9" } -zink = { path = ".", version = "0.1.9" } -zink-codegen = { path = "zink/codegen", version = "0.1.9" } -zinkc = { path = "compiler", version = "0.1.9" } -zint = { path = "zint", version = "0.1.9" } +elko = { path = "elko", version = "0.1.10" } +filetests = { package = "zinkc-filetests", path = "compiler/filetests", version = "0.1.10" } +zabi = { path = "abi", version = "0.1.10" } +zingen = { path = "codegen", version = "0.1.10" } +zink = { path = ".", version = "0.1.10" } +zink-codegen = { path = "zink/codegen", version = "0.1.10" } +zinkc = { path = "compiler", version = "0.1.10" } +zint = { path = "zint", version = "0.1.10" } [workspace.metadata.conta] packages = [ diff --git a/RELEASES.md b/RELEASES.md index 80db66d47..ba44d0195 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,13 @@ +## v0.1.10 + +## Changes + +- gather wasm related logic to module wasm in `codegen` +- introduce WASM environment for in `codegen` +- Structured compiler output of `zinkc` +- Renaming `without_dispatcher` to `pure` in `zint` +- use `tiny-keccak` instead of `sha3` in `zabi` + ## v0.1.9 ### Changes diff --git a/abi/Cargo.toml b/abi/Cargo.toml index f8b6cab79..93487d1dc 100644 --- a/abi/Cargo.toml +++ b/abi/Cargo.toml @@ -16,15 +16,14 @@ sol-abi.workspace = true hex = { workspace = true, optional = true } postcard = { workspace = true, default-features = false, features = [ "use-std" ], optional = true } serde = { workspace = true, features = [ "derive" ], optional = true } -sha3 = { workspace = true, optional = true } syn = { workspace = true, optional = true } thiserror = { workspace = true, optional = true } +tiny-keccak = { workspace = true, optional = true, features = [ "sha3" ] } # TODO: introduce feature alloc. [features] -default = [ "hex", "selector", "syn" ] bytes = [ "postcard", "serde" ] hex = [ "dep:hex", "thiserror", "bytes" ] -selector = [ "sha3" ] +selector = [ "tiny-keccak" ] serde = [ "dep:serde", "sol-abi/serde" ] syn = [ "dep:syn", "sol-abi/syn" ] diff --git a/abi/src/selector.rs b/abi/src/selector.rs index 387d4fc1f..7f5e15f34 100644 --- a/abi/src/selector.rs +++ b/abi/src/selector.rs @@ -2,13 +2,15 @@ #![cfg(feature = "selector")] use crate::Abi; -use sha3::{Digest, Keccak256}; +use tiny_keccak::{Hasher, Sha3}; /// Generate a keccak hash of the input (sha3) pub fn keccak256(input: &[u8]) -> [u8; 32] { - let mut hasher = Keccak256::new(); + let mut hasher = Sha3::v256(); + let mut output = [0; 32]; hasher.update(input); - hasher.finalize().into() + hasher.finalize(&mut output); + output } /// Parse selector from bytes. diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 27c02e478..b561fee29 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -18,4 +18,4 @@ smallvec.workspace = true thiserror.workspace = true tracing.workspace = true wasmparser.workspace = true -zabi.workspace = true +zabi = { workspace = true, features = [ "hex", "selector", "syn" ] } diff --git a/codegen/src/codegen/constructor.rs b/codegen/src/codegen/constructor.rs index 0721d356c..92a5dd5b1 100644 --- a/codegen/src/codegen/constructor.rs +++ b/codegen/src/codegen/constructor.rs @@ -46,18 +46,6 @@ impl Constructor { }) } - /// Returns the length of instructions. - fn return_instr_length(init_code_length: usize, runtime_bytecode_length: usize) -> usize { - let mut expected_length = - runtime_bytecode_length.to_ls_bytes().len() + init_code_length.to_ls_bytes().len() + 3; - - if init_code_length < 0xff && init_code_length + expected_length > 0xff { - expected_length += 1; - } - - expected_length - } - /// Concat the constructor code. /// /// Here we override the memory totally with @@ -115,4 +103,16 @@ impl Constructor { Ok(self.masm.buffer().into()) } + + /// Returns the length of instructions. + fn return_instr_length(init_code_length: usize, runtime_bytecode_length: usize) -> usize { + let mut expected_length = + runtime_bytecode_length.to_ls_bytes().len() + init_code_length.to_ls_bytes().len() + 3; + + if init_code_length < 0xff && init_code_length + expected_length > 0xff { + expected_length += 1; + } + + expected_length + } } diff --git a/codegen/src/codegen/dispatcher.rs b/codegen/src/codegen/dispatcher.rs index f3ad8d239..3f4c5cce6 100644 --- a/codegen/src/codegen/dispatcher.rs +++ b/codegen/src/codegen/dispatcher.rs @@ -1,5 +1,7 @@ //! Code generator for EVM dispatcher. +use std::collections::BTreeMap; + use crate::{ codegen::code::ExtFunc, wasm::{self, Env, Functions, ToLSBytes}, @@ -9,31 +11,55 @@ use wasmparser::{FuncType, Operator}; use zabi::Abi; /// Code generator for EVM dispatcher. -pub struct Dispatcher<'d> { +pub struct Dispatcher { + /// ABI for the current function + pub abi: Vec, /// Code buffer pub asm: MacroAssembler, /// WASM environment pub env: Env, /// Module functions - pub funcs: &'d Functions<'d>, + pub funcs: BTreeMap, /// Jump table pub table: JumpTable, - /// ABI for the current function - /// - /// TODO: refactor this. (#206) - pub abi: Vec, } -impl<'d> Dispatcher<'d> { +impl Dispatcher { /// Create dispatcher with functions. - pub fn new(env: Env, funcs: &'d Functions<'d>) -> Self { - Self { + pub fn new(env: Env, funcs: &Functions<'_>) -> Result { + let funcs = funcs + .values() + .map(|func| Ok((func.index(), func.sig()?))) + .collect::>()?; + + Ok(Self { + abi: Default::default(), asm: Default::default(), env, funcs, table: Default::default(), - abi: Default::default(), + }) + } + + /// Emit compiled code to the given buffer. + pub fn finish(&mut self, selectors: Functions<'_>, table: &mut JumpTable) -> Result> { + if selectors.is_empty() { + return Err(Error::SelectorNotFound); + } + + self.asm._push0()?; + self.asm._calldataload()?; + self.asm.push(&[0xe0])?; + self.asm._shr()?; + + let mut len = selectors.len(); + for (_, func) in selectors.iter() { + self.emit_selector(func, len == 1)?; + len -= 1; } + + table.merge(self.table.clone(), 0)?; + Ok(self.asm.buffer().into()) } /// Query exported function from selector. @@ -178,7 +204,7 @@ impl<'d> Dispatcher<'d> { .funcs .get(&func) .ok_or(Error::FuncNotFound(func))? - .sig()?; + .clone(); // TODO: optimize this on parameter length (#165) { @@ -220,25 +246,4 @@ impl<'d> Dispatcher<'d> { Ok(()) } - - /// Emit compiled code to the given buffer. - pub fn finish(&mut self, selectors: Functions<'_>, table: &mut JumpTable) -> Result> { - if selectors.is_empty() { - return Err(Error::SelectorNotFound); - } - - self.asm._push0()?; - self.asm._calldataload()?; - self.asm.push(&[0xe0])?; - self.asm._shr()?; - - let mut len = selectors.len(); - for (_, func) in selectors.iter() { - self.emit_selector(func, len == 1)?; - len -= 1; - } - - table.merge(self.table.clone(), 0)?; - Ok(self.asm.buffer().into()) - } } diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 5f343db85..64498aa43 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -23,19 +23,21 @@ zingen.workspace = true # Optional dependencies ccli = { workspace = true, optional = true } +serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } wasm-opt = { workspace = true, optional = true } [dev-dependencies] hex.workspace = true wat.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter"]} +tracing-subscriber = { workspace = true, features = [ "env-filter" ] } paste.workspace = true zabi.workspace = true etc.workspace = true [features] -cli = [ "ccli", "serde_json", "utils" ] +cli = [ "ccli", "serde_json", "utils", "serde" ] +serde = [ "dep:serde", "zabi/serde" ] utils = [ "wasm-opt" ] [package.metadata.docs.rs] diff --git a/compiler/src/artifact.rs b/compiler/src/artifact.rs new file mode 100644 index 000000000..6db40ec4c --- /dev/null +++ b/compiler/src/artifact.rs @@ -0,0 +1,46 @@ +//! Zink compiler artifact + +use crate::{Compiler, Config}; +use wasmparser::FuncType; +use zabi::Abi; +use zingen::Constructor; + +/// Zink compiler artifact +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Default, Debug)] +pub struct Artifact { + /// Contract ABIs + pub abi: Vec, + /// Bytecode of the contract. + pub bytecode: Vec, + /// Compiler configuration. + pub config: Config, + /// Runtime bytecode of the contract. + pub runtime_bytecode: Vec, +} + +impl TryFrom<(Compiler, Option)> for Artifact { + type Error = anyhow::Error; + + fn try_from( + (compiler, constructor): (Compiler, Option), + ) -> Result { + let Compiler { + abi, + buffer, + config, + .. + } = compiler; + + let bytecode = Constructor::new(constructor, buffer.clone())? + .finish()? + .to_vec(); + + Ok(Self { + abi, + bytecode, + config, + runtime_bytecode: buffer.to_vec(), + }) + } +} diff --git a/compiler/src/cli.rs b/compiler/src/cli.rs index d4bbac03e..bc86c280e 100644 --- a/compiler/src/cli.rs +++ b/compiler/src/cli.rs @@ -32,11 +32,11 @@ impl Compile { env::current_dir()?.join(self.input.with_extension("")) }; - let mut compiler = Compiler::new(Config::default().dispatcher(self.dispatcher)); - let bin = compiler.compile(&fs::read(&self.input)?)?; + let compiler = Compiler::new(Config::default().dispatcher(self.dispatcher)); + let artifact = compiler.compile(&fs::read(&self.input)?)?; output.parent().map(fs::create_dir_all); - fs::write(&output, bin)?; + fs::write(&output, artifact.bytecode)?; if !self.abi { return Ok(()); @@ -52,7 +52,7 @@ impl Compile { ) .with_extension("abi.json"); - fs::write(abi, serde_json::to_string_pretty(&compiler.abi())?)?; + fs::write(abi, serde_json::to_string_pretty(&artifact.abi)?)?; Ok(()) } } diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 5ccb8cd90..0bc1db1c0 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -1,24 +1,23 @@ //! Zink compiler -use crate::{parser::Parser, Config, Error, Result}; -use wasmparser::FuncType; +use crate::{parser::Parser, Artifact, Config, Error, Result}; use zabi::Abi; use zingen::{ wasm::{self, Env}, - Buffer, Constructor, Dispatcher, Function, JumpTable, BUFFER_LIMIT, + Buffer, Dispatcher, Function, JumpTable, BUFFER_LIMIT, }; /// Zink Compiler #[derive(Default)] pub struct Compiler { /// ABIs of the compiled contract. - abi: Vec, + pub(crate) abi: Vec, /// EVM bytecode buffer. - buffer: Buffer, - /// Global jump table. - table: JumpTable, + pub(crate) buffer: Buffer, /// Compiler configuration. pub config: Config, + /// Global jump table. + table: JumpTable, } impl Compiler { @@ -33,7 +32,7 @@ impl Compiler { /// Compile wasm module to evm bytecode. /// /// Returns runtime bytecode. - pub fn compile(&mut self, wasm: &[u8]) -> Result { + pub fn compile(mut self, wasm: &[u8]) -> Result { let mut parser = Parser::try_from(wasm)?; let constructor = parser.remove_constructor(); @@ -46,24 +45,20 @@ impl Compiler { self.table.code_offset(self.buffer.len() as u16); self.table.relocate(&mut self.buffer)?; - if self.config.constructor { - self.bytecode(constructor) - } else { - Ok(self.buffer.clone()) - } + Artifact::try_from((self, constructor)).map_err(Into::into) } /// Compile EVM dispatcher. /// /// Drain selectors anyway, if dispatcher is /// enabled, compile dispatcher. - pub fn compile_dispatcher(&mut self, parser: &mut Parser) -> Result<()> { + fn compile_dispatcher(&mut self, parser: &mut Parser) -> Result<()> { let selectors = parser.funcs.drain_selectors(&parser.exports); if !self.config.dispatcher { return Ok(()); } - let mut dispatcher = Dispatcher::new(parser.to_env(), &parser.funcs); + let mut dispatcher = Dispatcher::new(parser.to_env(), &parser.funcs)?; let buffer = dispatcher.finish(selectors, &mut self.table)?; self.buffer.extend_from_slice(&buffer); @@ -76,7 +71,7 @@ impl Compiler { } /// Compile WASM function. - pub fn compile_func(&mut self, env: Env, mut func: wasm::Function<'_>) -> Result<()> { + fn compile_func(&mut self, env: Env, mut func: wasm::Function<'_>) -> Result<()> { let func_index = func.index(); let sig = func.sig()?; @@ -111,16 +106,4 @@ impl Compiler { Ok(()) } - - /// Get the abi of the compiled contract. - pub fn abi(&self) -> Vec { - self.abi.clone() - } - - /// Returns bytecode. - fn bytecode(&self, constructor: Option) -> Result { - Constructor::new(constructor, self.buffer.clone())? - .finish() - .map_err(Into::into) - } } diff --git a/compiler/src/config.rs b/compiler/src/config.rs index c3f73452c..279f902d1 100644 --- a/compiler/src/config.rs +++ b/compiler/src/config.rs @@ -6,11 +6,10 @@ use ccli::clap; /// Zink compiler configuration. #[derive(Debug, Default)] #[cfg_attr(feature = "cli", derive(clap::Parser))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Config { /// If enable dispatcher. pub dispatcher: bool, - /// If enable constructor. - pub constructor: bool, } impl Config { @@ -19,10 +18,4 @@ impl Config { self.dispatcher = dispatcher; self } - - /// With constructor value. - pub fn constructor(mut self, constructor: bool) -> Self { - self.constructor = constructor; - self - } } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index f429d8b87..25611710b 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -2,11 +2,13 @@ #![deny(missing_docs)] pub use crate::{ + artifact::Artifact, compiler::Compiler, config::Config, result::{Error, Result}, }; +mod artifact; pub mod cli; mod compiler; mod config; diff --git a/elko/src/build.rs b/elko/src/build.rs index e5d2cc008..d6508f034 100644 --- a/elko/src/build.rs +++ b/elko/src/build.rs @@ -61,10 +61,10 @@ impl Build { // Compile the wasm to evm bytecode. let wasm = fs::read(builder.output()?)?; let config = Config::default().dispatcher(self.config.dispatcher); - let bin = Compiler::new(config).compile(&wasm)?; + let artifact = Compiler::new(config).compile(&wasm)?; let dst = builder.output()?.with_extension("bin"); - fs::write(dst, bin)?; + fs::write(dst, artifact.bytecode)?; Ok(()) } } diff --git a/examples/constructor.rs b/examples/constructor.rs index 492a6a92b..719049103 100644 --- a/examples/constructor.rs +++ b/examples/constructor.rs @@ -35,13 +35,10 @@ fn main() {} fn deploy() -> anyhow::Result<()> { use zint::{Bytes32, Contract, EVM}; - let contract = Contract::search("constructor")? - .without_dispatcher() - .constructor(true) - .compile()?; + let contract = Contract::search("constructor")?.compile()?; let mut evm = EVM::default(); - let mut info = evm.deploy(&contract.bytecode)?; + let mut info = evm.deploy(&contract.bytecode())?; info = evm .calldata(&contract.encode(&["get()"])?) .call(info.address)?; diff --git a/tests/add.rs b/tests/add.rs index 5ded6631a..7b35c1508 100644 --- a/tests/add.rs +++ b/tests/add.rs @@ -6,8 +6,8 @@ use 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() + let mut contract = Contract::from(Test::load(module, "params")?.wasm) + .pure() .compile()?; // add(1, 2) @@ -17,8 +17,8 @@ fn params(module: &str) -> Result<()> { } fn locals(module: &str) -> Result<()> { - let mut contract = Contract::new(Test::load(module, "locals")?.wasm) - .without_dispatcher() + let mut contract = Contract::from(Test::load(module, "locals")?.wasm) + .pure() .compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.ret, [30.to_bytes32()].concat()); @@ -26,8 +26,8 @@ fn locals(module: &str) -> Result<()> { } fn tee(module: &str) -> Result<()> { - let mut contract = Contract::new(Test::load(module, "tee")?.wasm) - .without_dispatcher() + let mut contract = Contract::from(Test::load(module, "tee")?.wasm) + .pure() .compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.ret, [30.to_bytes32()].concat()); diff --git a/tests/br_if.rs b/tests/br_if.rs index 9935aebe3..aa64630e8 100644 --- a/tests/br_if.rs +++ b/tests/br_if.rs @@ -5,9 +5,7 @@ use zint::{Contract, Halt, OutOfGasError}; #[test] fn as_block_last() -> Result<()> { - let mut contract = Contract::new(Test::BR_IF_AS_BLOCK_LAST) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::BR_IF_AS_BLOCK_LAST).pure().compile()?; let info = contract.execute(&[0])?; assert!(info.ret.is_empty()); diff --git a/tests/call.rs b/tests/call.rs index 08a163adb..c61572832 100644 --- a/tests/call.rs +++ b/tests/call.rs @@ -7,9 +7,7 @@ use zint::{Bytes32, Contract}; #[test] fn dummy() -> Result<()> { - let mut contract = Contract::new(Test::CALL_DUMMY) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::CALL_DUMMY).pure().compile()?; let info = contract.execute::<()>([])?; assert!(info.ret.is_empty()); @@ -18,9 +16,7 @@ fn dummy() -> Result<()> { #[test] fn params() -> Result<()> { - let mut contract = Contract::new(Test::CALL_PARAMS) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::CALL_PARAMS).pure().compile()?; let info = contract.execute([1, 2])?; assert_eq!(info.ret, 3.to_bytes32()); @@ -29,9 +25,7 @@ fn params() -> Result<()> { #[test] fn as_if() -> Result<()> { - let mut contract = Contract::new(Test::CALL_AS_IF) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::CALL_AS_IF).pure().compile()?; let info = contract.execute([0])?; assert_eq!(info.ret, 0.to_bytes32()); diff --git a/tests/if.rs b/tests/if.rs index 935b3ec99..ec12477bd 100644 --- a/tests/if.rs +++ b/tests/if.rs @@ -5,9 +5,7 @@ use zint::{Bytes32, Contract}; #[test] fn if_then() -> Result<()> { - let mut contract = Contract::new(Test::IF_BASIC) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::IF_BASIC).pure().compile()?; // Skip the condition. let input = [0; 32]; @@ -24,9 +22,7 @@ fn if_then() -> Result<()> { #[test] fn singular() -> Result<()> { - let mut contract = Contract::new(Test::IF_SINGULAR) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::IF_SINGULAR).pure().compile()?; // test if // diff --git a/tests/log.rs b/tests/log.rs index 2f45c9812..4d67f438a 100644 --- a/tests/log.rs +++ b/tests/log.rs @@ -6,9 +6,7 @@ use zint::{Bytes32, Contract}; #[test] fn log0() -> Result<()> { - let mut contract = Contract::new(Test::LOG_LOG0) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOG_LOG0).pure().compile()?; // returns the bigger number. let info = contract.execute::<()>([])?; @@ -18,9 +16,7 @@ fn log0() -> Result<()> { #[test] fn log1() -> Result<()> { - let mut contract = Contract::new(Test::LOG_LOG1) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOG_LOG1).pure().compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); @@ -33,9 +29,7 @@ fn log1() -> Result<()> { #[test] fn log2() -> Result<()> { - let mut contract = Contract::new(Test::LOG_LOG2) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOG_LOG2).pure().compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); @@ -52,9 +46,7 @@ fn log2() -> Result<()> { #[test] fn log3() -> Result<()> { - let mut contract = Contract::new(Test::LOG_LOG3) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOG_LOG3).pure().compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); @@ -75,9 +67,7 @@ fn log3() -> Result<()> { #[test] fn log4() -> Result<()> { - let mut contract = Contract::new(Test::LOG_LOG4) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOG_LOG4).pure().compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.logs[0].data.to_vec(), b"Ping".to_vec().to_bytes32()); diff --git a/tests/loop.rs b/tests/loop.rs index 128b4d1d4..0af208c3b 100644 --- a/tests/loop.rs +++ b/tests/loop.rs @@ -6,9 +6,7 @@ use zint::{Bytes32, Contract, Halt, OutOfGasError}; #[test] fn singular() -> Result<()> { - let mut contract = Contract::new(Test::LOOP_SINGULAR) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOOP_SINGULAR).pure().compile()?; let info = contract.execute::<()>([])?; assert_eq!(info.ret, 7.to_bytes32()); @@ -18,9 +16,7 @@ fn singular() -> Result<()> { #[test] fn as_br_if() -> Result<()> { - let mut contract = Contract::new(Test::LOOP_AS_BR_IF) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::LOOP_AS_BR_IF).pure().compile()?; let info = contract.execute([0])?; assert_eq!( info.halt, diff --git a/tests/recursion.rs b/tests/recursion.rs index 52d14beb9..b50d5f024 100644 --- a/tests/recursion.rs +++ b/tests/recursion.rs @@ -4,9 +4,7 @@ use zint::{Bytes32, Contract}; #[test] fn fibonacci() -> Result<()> { - let mut contract = Contract::new(Test::RECURSION_FIBONACCI) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::RECURSION_FIBONACCI).pure().compile()?; // x = 0 let info = contract.execute([0])?; diff --git a/tests/select.rs b/tests/select.rs index eda2598a9..0ad4c4f61 100644 --- a/tests/select.rs +++ b/tests/select.rs @@ -6,9 +6,7 @@ use zint::{Bytes32, Contract}; #[test] fn params() -> Result<()> { - let mut contract = Contract::new(Test::SELECT_PARAMS) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::SELECT_PARAMS).pure().compile()?; let info = contract.execute([1, 2])?; assert_eq!(info.ret, [2.to_bytes32()].concat()); diff --git a/tests/storage.rs b/tests/storage.rs index 31cc03e39..78e10ffb4 100644 --- a/tests/storage.rs +++ b/tests/storage.rs @@ -7,9 +7,7 @@ use zint::{Bytes32, Contract, U256}; #[test] fn store() -> Result<()> { - let mut contract = Contract::new(Test::STORAGE_STORE) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::STORAGE_STORE).pure().compile()?; let key = 0u64; let value = 42u64; @@ -22,9 +20,7 @@ fn store() -> Result<()> { #[test] fn load() -> Result<()> { - let mut contract = Contract::new(Test::STORAGE_LOAD) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::STORAGE_LOAD).pure().compile()?; let value = 42; let info = contract.execute([value])?; @@ -35,9 +31,7 @@ fn load() -> Result<()> { #[test] fn basic() -> Result<()> { - let mut contract = Contract::new(Test::STORAGE_BASIC) - .without_dispatcher() - .compile()?; + let mut contract = Contract::from(Test::STORAGE_BASIC).pure().compile()?; let value = 42; let info = contract.execute([value])?; diff --git a/tests/sub.rs b/tests/sub.rs index 0b8f8c93f..14cc5149d 100644 --- a/tests/sub.rs +++ b/tests/sub.rs @@ -6,8 +6,8 @@ use 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() + let mut contract = Contract::from(Test::load(module, "params")?.wasm) + .pure() .compile()?; let info = contract.execute([2, 1])?; @@ -16,8 +16,8 @@ fn params(module: &str) -> Result<()> { } fn locals(module: &str) -> Result<()> { - let mut contract = Contract::new(Test::load(module, "locals")?.wasm) - .without_dispatcher() + let mut contract = Contract::from(Test::load(module, "locals")?.wasm) + .pure() .compile()?; let info = contract.execute::<()>([])?; diff --git a/zink/codegen/Cargo.toml b/zink/codegen/Cargo.toml index 9a8bef0e9..6e05dc850 100644 --- a/zink/codegen/Cargo.toml +++ b/zink/codegen/Cargo.toml @@ -16,4 +16,4 @@ proc-macro = true proc-macro2.workspace = true quote.workspace = true syn.workspace = true -zabi.workspace = true +zabi = { workspace = true, features = [ "hex", "syn" ] } diff --git a/zink/codegen/src/selector.rs b/zink/codegen/src/selector.rs index 8e358caae..72358a3e9 100644 --- a/zink/codegen/src/selector.rs +++ b/zink/codegen/src/selector.rs @@ -16,8 +16,8 @@ pub fn external(mut item: ItemFn) -> TokenStream { let selector: ItemFn = { let func = item.sig.ident.clone().to_string(); let ident = Ident::new(&(func.clone() + "_selector"), Span::call_site()); - let selector = Abi::from(&item.sig).to_hex().expect("ABI is not supported"); - let selector_len = selector.len() as u32; + let abi = Abi::from(&item.sig).to_hex().expect("ABI is not supported"); + let abi_len = abi.len() as u32; let doc = " EVM selector for the function `".to_string() + &func + "`"; parse_quote! { @@ -26,7 +26,7 @@ pub fn external(mut item: ItemFn) -> TokenStream { #[doc = #doc] pub extern "C" fn #ident() { unsafe { - zink::ffi::emit_abi(#selector.as_ptr() as u32, #selector_len); + zink::ffi::emit_abi(#abi.as_ptr() as u32, #abi_len); } } } diff --git a/zint/src/contract.rs b/zint/src/contract.rs index 2fa02e0a0..2120d76cf 100644 --- a/zint/src/contract.rs +++ b/zint/src/contract.rs @@ -1,58 +1,26 @@ //! Contract Instance -use crate::{Bytes32, Info, EVM}; +use crate::{lookup, Bytes32, Info, EVM}; use anyhow::{anyhow, Result}; -use serde::Deserialize; -use std::{fs, path::PathBuf}; -use zabi::Abi; -use zinkc::{Compiler, Config}; - -/// Cargo Manifest for parsing package. -#[derive(Deserialize)] -struct Manifest { - /// The package. - pub package: Package, -} - -/// Cargo Package for parsing package name. -#[derive(Deserialize)] -struct Package { - /// Package name. - pub name: String, -} +use std::fs; +use zinkc::{Artifact, Compiler, Config}; /// Contract instance for testing. #[derive(Default)] pub struct Contract { - /// The bytecode of the contract. - pub bytecode: Vec, /// If enable dispatcher. pub dispatcher: bool, - /// If enable constructor. - pub constructor: bool, - /// The ABI of the contract. - pub abi: Vec, + /// The artifact of the contract. + pub artifact: Artifact, /// 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() - }) - } - - /// Create new contract - pub fn new(wasm: impl AsRef<[u8]>) -> Self { +impl From for Contract +where + T: AsRef<[u8]>, +{ + fn from(wasm: T) -> Self { crate::setup_logger(); Self { @@ -61,36 +29,22 @@ impl Contract { ..Default::default() } } +} - /// Disable dispatcher. - pub fn constructor(mut self, constructor: bool) -> Self { - self.constructor = constructor; - self - } - - /// Disable dispatcher. - pub fn without_dispatcher(mut self) -> Self { - self.dispatcher = false; - self - } - - /// Get the JSON ABI of the contract. - pub fn json_abi(&self) -> Result { - serde_json::to_string_pretty(&self.abi).map_err(Into::into) +impl Contract { + /// Get the bytecode of the contract. + pub fn bytecode(&self) -> &[u8] { + &self.artifact.bytecode } /// Compile WASM to EVM bytecode. pub fn compile(mut self) -> Result { - let config = Config::default() - .constructor(self.constructor) - .dispatcher(self.dispatcher); - - let mut compiler = Compiler::new(config); - self.bytecode = compiler.compile(&self.wasm)?.to_vec(); - self.abi = compiler.abi(); + let config = Config::default().dispatcher(self.dispatcher); + let compiler = Compiler::new(config); + self.artifact = compiler.compile(&self.wasm)?; tracing::debug!("abi: {:#}", self.json_abi()?); - tracing::debug!("bytecode: {:?}", hex::encode(&self.bytecode)); + tracing::debug!("bytecode: {:?}", hex::encode(&self.artifact.bytecode)); Ok(self) } @@ -100,37 +54,7 @@ impl Contract { /// NOTE: This only works if the current contract /// is not an example. pub fn current() -> Result { - let manifest = fs::read_to_string(etc::find_up("Cargo.toml")?)?; - let name = toml::from_str::(&manifest)?.package.name; - - Self::search(&name) - } - - /// Search for zink contract in the target - /// directory. - pub fn search(name: &str) -> Result { - crate::setup_logger(); - - 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"))?; - zinkc::utils::wasm_opt(&wasm, &wasm)?; - - tracing::debug!("loading contract from {}", wasm.display()); - Ok(Self::new(fs::read(wasm)?)) + Self::search(&lookup::pkg_name()?) } /// Encode call data @@ -161,6 +85,27 @@ impl Contract { where Param: Bytes32, { - EVM::interp(&self.bytecode, &self.encode(inputs)?) + EVM::interp(&self.artifact.runtime_bytecode, &self.encode(inputs)?) + } + + /// Get the JSON ABI of the contract. + pub fn json_abi(&self) -> Result { + serde_json::to_string_pretty(&self.artifact.abi).map_err(Into::into) + } + + /// Disable dispatcher. + pub fn pure(mut self) -> Self { + self.dispatcher = false; + self + } + + /// Search for zink contract in the target directory. + pub fn search(name: &str) -> Result { + crate::setup_logger(); + let wasm = lookup::wasm(name)?; + zinkc::utils::wasm_opt(&wasm, &wasm)?; + + tracing::debug!("loading contract from {}", wasm.display()); + Ok(Self::from(fs::read(wasm)?)) } } diff --git a/zint/src/lib.rs b/zint/src/lib.rs index 1f91fabb8..789be21fd 100644 --- a/zint/src/lib.rs +++ b/zint/src/lib.rs @@ -4,6 +4,7 @@ mod bytes; mod contract; mod evm; +mod lookup; pub use self::{ bytes::Bytes32, diff --git a/zint/src/lookup.rs b/zint/src/lookup.rs new file mode 100644 index 000000000..e51b813c1 --- /dev/null +++ b/zint/src/lookup.rs @@ -0,0 +1,59 @@ +//! Binary lookup util + +use anyhow::Result; +use serde::Deserialize; +use std::{fs, path::PathBuf}; + +/// Cargo Manifest for parsing package. +#[derive(Deserialize)] +struct Manifest { + /// The package. + pub package: Package, +} + +/// Cargo Package for parsing package name. +#[derive(Deserialize)] +struct Package { + /// Package name. + pub name: String, +} + +/// Get the name of the current package. +pub fn pkg_name() -> Result { + let manifest = fs::read_to_string(etc::find_up("Cargo.toml")?)?; + Ok(toml::from_str::(&manifest)?.package.name) +} + +/// Get the wasm binary of the provided name from the target directory. +pub fn wasm(name: &str) -> Result { + let target = 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())) + } + }; + + search("release").or_else(|_| search("debug")) +} + +/// 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() + }) +}