Skip to content

Commit

Permalink
feat(zinkc): introduce artifact as compiler output (#210)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
clearloop authored Dec 28, 2023
1 parent d74eb34 commit 399ecfc
Show file tree
Hide file tree
Showing 31 changed files with 341 additions and 361 deletions.
138 changes: 55 additions & 83 deletions Cargo.lock

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ members = [
resolver = "2"

[workspace.package]
version = "0.1.9"
version = "0.1.10"
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.76"
anyhow = "1.0.77"
cargo_metadata = "0.18.1"
ccli = "0.0.1"
colored = "2.1.0"
Expand All @@ -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"
Expand All @@ -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 = [
Expand Down
10 changes: 10 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 2 additions & 3 deletions abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
8 changes: 5 additions & 3 deletions abi/src/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ] }
24 changes: 12 additions & 12 deletions codegen/src/codegen/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
69 changes: 37 additions & 32 deletions codegen/src/codegen/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Code generator for EVM dispatcher.

use std::collections::BTreeMap;

use crate::{
codegen::code::ExtFunc,
wasm::{self, Env, Functions, ToLSBytes},
Expand All @@ -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<Abi>,
/// Code buffer
pub asm: MacroAssembler,
/// WASM environment
pub env: Env,
/// Module functions
pub funcs: &'d Functions<'d>,
pub funcs: BTreeMap<u32, FuncType>,
/// Jump table
pub table: JumpTable,
/// ABI for the current function
///
/// TODO: refactor this. (#206)
pub abi: Vec<Abi>,
}

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<Self> {
let funcs = funcs
.values()
.map(|func| Ok((func.index(), func.sig()?)))
.collect::<Result<_>>()?;

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<Vec<u8>> {
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.
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<Vec<u8>> {
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())
}
}
6 changes: 4 additions & 2 deletions compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
46 changes: 46 additions & 0 deletions compiler/src/artifact.rs
Original file line number Diff line number Diff line change
@@ -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<Abi>,
/// Bytecode of the contract.
pub bytecode: Vec<u8>,
/// Compiler configuration.
pub config: Config,
/// Runtime bytecode of the contract.
pub runtime_bytecode: Vec<u8>,
}

impl TryFrom<(Compiler, Option<FuncType>)> for Artifact {
type Error = anyhow::Error;

fn try_from(
(compiler, constructor): (Compiler, Option<FuncType>),
) -> Result<Self, Self::Error> {
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(),
})
}
}
8 changes: 4 additions & 4 deletions compiler/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(());
Expand All @@ -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(())
}
}
Loading

0 comments on commit 399ecfc

Please sign in to comment.