Skip to content

Commit

Permalink
feat(abi): conditonal compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
clearloop committed Dec 16, 2023
1 parent 0fcfc91 commit 008c46b
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 116 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 18 additions & 5 deletions abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@ license.workspace = true
repository.workspace = true

[dependencies]
hex.workspace = true
postcard = { workspace = true, default-features = false, features = [ "use-std" ] }
serde = { workspace = true, features = [ "derive" ] }
sha3.workspace = true
thiserror.workspace = true
evm-abi.workspace = true

# optional features
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 }

# TODO: introduce feature alloc.
[features]
default = [ "hex", "selector", "syn" ]
bytes = [ "postcard", "serde" ]
hex = [ "dep:hex", "thiserror", "bytes" ]
selector = [ "sha3" ]
serde = [ "dep:serde", "evm-abi/serde" ]
syn = [ "dep:syn", "evm-abi/syn" ]
46 changes: 0 additions & 46 deletions abi/src/codec.rs

This file was deleted.

88 changes: 68 additions & 20 deletions abi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,79 @@
//! EVM ABI implementation
//! Zink ABI implementation
//!
//! https://docs.soliditylang.org/en/latest/abi-spec.html#json
pub use self::result::{Error, Result};
use serde::{Deserialize, Serialize};
//! Currently just a wrapper of solidity ABI.
mod codec;
mod result;
pub mod util;
pub mod result;
pub mod selector;

use core::ops::{Deref, DerefMut};

/// Function ABI.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Abi {
/// Function name.
pub name: String,
/// Function inputs.
pub inputs: Vec<String>,
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Abi(evm_abi::Abi);

impl Deref for Abi {
type Target = evm_abi::Abi;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Abi {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

#[cfg(feature = "bytes")]
impl Abi {
/// Get function signature.
pub fn signature(&self) -> String {
self.name.clone() + "(" + &self.inputs.join(",") + ")"
/// Convert [`Abi`] to bytes.
pub fn to_bytes(&self) -> postcard::Result<Vec<u8>> {
postcard::to_stdvec(self).map_err(Into::into)
}

/// Convert bytes to [`Abi`].
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> postcard::Result<Self> {
postcard::from_bytes(bytes.as_ref()).map_err(Into::into)
}
}

#[cfg(feature = "hex")]
mod hex_impl {
use crate::{result::Result, Abi};

impl Abi {
/// Convert [`Abi`] to hex string.
pub fn to_hex(&self) -> Result<String> {
Ok("0x".to_string() + &hex::encode(self.to_bytes()?))
}

/// Convert hex string to [`Abi`].
pub fn from_hex(hex: impl AsRef<str>) -> Result<Self> {
Self::from_bytes(hex::decode(hex.as_ref().trim_start_matches("0x"))?)
.map_err(Into::into)
}
}

impl ToString for Abi {
fn to_string(&self) -> String {
self.to_hex().unwrap_or_default()
}
}

/// Get function selector.
pub fn selector(&self) -> [u8; 4] {
let sig = self.signature();
util::selector(sig.as_bytes())
impl core::str::FromStr for Abi {
type Err = crate::result::Error;

fn from_str(hex: &str) -> Result<Self> {
Self::from_hex(hex)
}
}
}

#[cfg(feature = "syn")]
impl From<&syn::Signature> for Abi {
fn from(sig: &syn::Signature) -> Self {
Self(evm_abi::Abi::from(sig))
}
}
1 change: 1 addition & 0 deletions abi/src/result.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Abi results
#![cfg(feature = "hex")]

/// ABI error
#[derive(Debug, thiserror::Error)]
Expand Down
39 changes: 39 additions & 0 deletions abi/src/selector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Zink ABI utils
#![cfg(feature = "selector")]

use crate::Abi;
use sha3::{Digest, Keccak256};

/// Generate a keccak hash of the input (sha3)
pub fn keccak256(input: &[u8]) -> [u8; 32] {
let mut hasher = Keccak256::new();
hasher.update(input);
hasher.finalize().into()
}

/// Parse selector from bytes.
pub fn parse(bytes: &[u8]) -> [u8; 4] {
let mut selector = [0u8; 4];
selector.copy_from_slice(&keccak256(bytes)[..4]);
selector
}

impl Abi {
/// Get function signature.
pub fn signature(&self) -> String {
self.name.clone()
+ "("
+ &self
.inputs
.iter()
.map(|i| i.ty.as_ref())
.collect::<Vec<_>>()
.join(",")
+ ")"
}

/// Get function selector.
pub fn selector(&self) -> [u8; 4] {
parse(self.signature().as_bytes())
}
}
17 changes: 0 additions & 17 deletions abi/src/util.rs

This file was deleted.

2 changes: 1 addition & 1 deletion codegen/src/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl<'d> Dispatcher<'d> {
tracing::trace!(
"Emitting selector {:?} for function: {}",
selector_bytes,
abi.signature()
abi.name,
);

let func = self.query_func(&abi.name)?;
Expand Down
2 changes: 1 addition & 1 deletion codegen/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
pub enum Error {
/// Failed to parse function ABI.
#[error(transparent)]
Abi(#[from] zabi::Error),
Abi(#[from] zabi::result::Error),
/// Failed to parse WASM with binary reader.
#[error(transparent)]
BinaryReader(#[from] wasmparser::BinaryReaderError),
Expand Down
1 change: 1 addition & 0 deletions codegen/src/selector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

5 changes: 4 additions & 1 deletion evm/abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ repository.workspace = true

[dependencies]
serde = { workspace = true, optional = true }
syn = { workspace = true, optional = true }
quote = { workspace = true, optional = true }

[features]
default = [ "serde" ]
default = [ "serde", "syn" ]
syn = [ "dep:syn", "quote" ]
22 changes: 22 additions & 0 deletions evm/abi/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ pub struct Abi {
pub inputs: Vec<Input>,
}

#[cfg(feature = "syn")]
impl From<&syn::Signature> for Abi {
fn from(sig: &syn::Signature) -> Self {
let args = sig.inputs.iter().filter_map(|arg| {
if let syn::FnArg::Typed(syn::PatType { ty, .. }) = arg {
Some(Input {
name: sig.ident.to_string(),
ty: crate::Param::from(ty),
})
} else {
None
}
});

Abi {
name: sig.ident.to_string(),
inputs: args.collect(),
ty: Type::Function,
}
}
}

/// Solidity ABI type.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down
25 changes: 22 additions & 3 deletions evm/abi/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ pub enum Param {
UInt32,
/// A 64-bit unsigned integer.
UInt64,
/// An unknown type.
Unknown,
}

impl From<&str> for Param {
fn from(s: &str) -> Self {
match s {
"i32" | "int32" => Param::Int32,
"i64" | "int64" => Param::Int64,
"u32" | "uint32" => Param::UInt32,
"u64" | "uint64" => Param::UInt64,
_ => Param::Unknown,
}
}
}

impl AsRef<str> for Param {
Expand All @@ -31,12 +45,17 @@ impl AsRef<str> for Param {
Param::Int64 => "int64",
Param::UInt32 => "uint32",
Param::UInt64 => "uint64",
Param::Unknown => "unknown",
}
}
}

impl ToString for Param {
fn to_string(&self) -> String {
self.as_ref().to_string()
#[cfg(feature = "syn")]
impl From<&Box<syn::Type>> for Param {
fn from(ty: &Box<syn::Type>) -> Self {
use quote::ToTokens;

let ident = ty.into_token_stream().to_string();
Self::from(ident.as_str())
}
}
Loading

0 comments on commit 008c46b

Please sign in to comment.