Skip to content
This repository was archived by the owner on Jun 21, 2020. It is now read-only.

Commit cfe501e

Browse files
authored
Merge pull request #209 from enigmampc/EP-748-simplify-pub_interface
Ep 748 simplify pub interface
2 parents b597ed7 + e2a138e commit cfe501e

18 files changed

+1971
-405
lines changed

eng-wasm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ categories = ["wasm"]
1111
[dependencies]
1212
serde_json = "1.0"
1313
serde = { version = "1.0", default-features = false }
14-
eng-pwasm-abi = "0.3"
14+
eng-pwasm-abi = "0.3"

eng-wasm/derive/.rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# override global formatting. i want clean and standard rustfmt.

eng-wasm/derive/Cargo.toml

100755100644
Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
11
[package]
22
name = "eng-wasm-derive"
33
version = "0.1.6" # upgrade version in eng-wasm dependancy as well (if needed)
4-
authors = ["moria <[email protected]>"]
4+
authors = ["moria <[email protected]>", "Reuven Podmazo <[email protected]>"]
5+
edition = "2018"
56
license = "AGPL-3.0"
67
description = "Enigma library for creating Secret Contracts"
78
keywords = ["wasm", "webassembly", "blockchain", "sgx", "enigma"]
89
categories = ["wasm"]
910

11+
[lib]
12+
proc-macro = true
13+
1014
[dependencies]
11-
eng-wasm = { version = "0.1.6", path = "../" }
12-
proc-macro2 = "0.4"
13-
quote = "0.6"
14-
syn = { version = "0.15", features = ["full"] }
15-
#syn = { version = "0.15", features = ["full", "extra-traits"] } # for debug purposes
16-
failure = { version = "0.1.5", default-features = false, features = ["derive"] }
15+
proc-macro2 = "1.0"
16+
syn = { version = "1.0", features = ["full"] }
17+
quote = "1.0"
18+
failure = "0.1"
19+
parse-display = "0.1"
1720
ethabi = "6.1"
1821
serde_json = "1.0"
1922
tiny-keccak = "1.4"
2023

21-
[lib]
22-
proc-macro = true
24+
[dev-dependencies]
25+
syn = { version = "1.0", features = ["full", "extra-traits"] }
26+
eng-wasm = { path = '..' }
27+
28+
[[example]]
29+
name = 'struct-impl'
30+
crate-type = ["cdylib"]
31+
32+
[[example]]
33+
name = 'trait-impl'
34+
crate-type = ["cdylib"]
35+
36+
[[example]]
37+
name = 'trait-impl-rename'
38+
crate-type = ["cdylib"]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![no_std]
2+
3+
use eng_wasm_derive::pub_interface;
4+
5+
struct MyContract;
6+
7+
#[pub_interface]
8+
impl MyContract {
9+
/// constructor
10+
pub fn construct(_x: u32) {}
11+
12+
/// secret contract method
13+
pub fn expand(input: u32) -> u64 {
14+
Self::expand_impl(input)
15+
}
16+
17+
/// private method, not exported from contract
18+
fn expand_impl(input: u32) -> u64 {
19+
input as u64
20+
}
21+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![no_std]
2+
3+
use eng_wasm_derive::pub_interface;
4+
5+
struct MyContractImplementation;
6+
7+
#[pub_interface(MyContractImplementation)]
8+
trait MyContract {
9+
/// constructor
10+
fn construct(_x: u32);
11+
12+
/// secret contract method
13+
fn expand(input: u32) -> u64;
14+
}
15+
16+
impl MyContract for MyContractImplementation {
17+
fn construct(_x: u32) {}
18+
19+
fn expand(input: u32) -> u64 {
20+
Self::expand_impl(input)
21+
}
22+
}
23+
24+
impl MyContractImplementation {
25+
/// private method, not exported from contract
26+
fn expand_impl(input: u32) -> u64 {
27+
input as u64
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![no_std]
2+
3+
use eng_wasm_derive::pub_interface;
4+
5+
struct Contract;
6+
7+
#[pub_interface]
8+
trait MyContract {
9+
/// constructor
10+
fn construct(_x: u32);
11+
12+
/// secret contract method
13+
fn expand(input: u32) -> u64;
14+
}
15+
16+
impl MyContract for Contract {
17+
fn construct(_x: u32) {}
18+
19+
fn expand(input: u32) -> u64 {
20+
Self::expand_impl(input)
21+
}
22+
}
23+
24+
impl Contract {
25+
/// private method, not exported from contract
26+
fn expand_impl(input: u32) -> u64 {
27+
input as u64
28+
}
29+
}

eng-wasm/derive/src/eth_contract.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use std::fs::File;
2+
3+
use quote::quote;
4+
5+
use ethabi::{Contract, ParamType};
6+
7+
mod errors;
8+
mod ethereum;
9+
10+
use errors::EngWasmError;
11+
use ethereum::short_signature;
12+
13+
trait Write {
14+
fn write(&self) -> String;
15+
fn error(&self) -> String;
16+
}
17+
18+
impl Write for ParamType {
19+
/// Returns string which is a formatted representation of param.
20+
fn write(&self) -> String {
21+
match *self {
22+
ParamType::Address => "Address".to_owned(),
23+
ParamType::Bytes => "Vec<u8>".to_owned(),
24+
ParamType::FixedBytes(len) => format!("u8[{}]", len),
25+
ParamType::Int(len) => match len {
26+
32 | 64 => format!("i{}", len),
27+
_ => panic!("{}", self.error()),
28+
},
29+
ParamType::Uint(len) => match len {
30+
32 | 64 => format!("u{}", len),
31+
256 => "U256".to_owned(),
32+
_ => panic!("{}", self.error()),
33+
},
34+
ParamType::Bool => "bool".to_owned(),
35+
ParamType::String => "String".to_owned(),
36+
ParamType::FixedArray(ref param, len) => format!("{}[{}]", param.write(), len),
37+
ParamType::Array(ref param) => format!("Vec<{}>", param.write()),
38+
}
39+
}
40+
fn error(&self) -> String {
41+
format!("The type {} is not supported", self.to_string())
42+
}
43+
}
44+
45+
struct FunctionAst {
46+
name: syn::Ident,
47+
args_ast_types: Vec<syn::Type>,
48+
args_types: Vec<ParamType>,
49+
}
50+
51+
fn read_contract_file(file_path: String) -> Result<Box<File>, EngWasmError> {
52+
let file = File::open(file_path)?;
53+
let contents = Box::new(file);
54+
Ok(contents)
55+
}
56+
57+
fn generate_eth_functions(
58+
contract: &Contract,
59+
) -> Result<Vec<proc_macro2::TokenStream>, EngWasmError> {
60+
let mut functions: Vec<FunctionAst> = Vec::new();
61+
for function in &contract.functions {
62+
let mut args_ast_types = Vec::new();
63+
for input in &function.1.inputs {
64+
let arg_type: syn::Type = syn::parse_str(&input.kind.clone().write())?;
65+
args_ast_types.push(arg_type);
66+
}
67+
let args_types = function
68+
.1
69+
.inputs
70+
.iter()
71+
.map(|input| input.kind.clone())
72+
.collect();
73+
74+
let name = syn::Ident::new(&function.1.name, proc_macro2::Span::call_site());
75+
functions.push(FunctionAst {
76+
name,
77+
args_types,
78+
args_ast_types,
79+
})
80+
}
81+
82+
let result: Vec<proc_macro2::TokenStream> = functions
83+
.iter()
84+
.map(|function| {
85+
let function_name = &function.name;
86+
let args_ast_types = function.args_ast_types.clone();
87+
let sig_u32 = short_signature(&function_name.to_string(), &function.args_types);
88+
let sig = syn::Lit::Int(syn::LitInt::new(
89+
&format!("{}_u32", sig_u32 as u32),
90+
proc_macro2::Span::call_site(),
91+
));
92+
let args_number = syn::Lit::Int(syn::LitInt::new(
93+
&format!("{}_usize", args_ast_types.len() as usize),
94+
proc_macro2::Span::call_site(),
95+
));
96+
let args_names: Vec<syn::Ident> = function
97+
.args_ast_types
98+
.iter()
99+
.enumerate()
100+
.map(|item| {
101+
let mut arg = String::from("arg");
102+
arg.push_str(item.0.to_string().as_str());
103+
syn::Ident::new(&arg, proc_macro2::Span::call_site())
104+
})
105+
.collect();
106+
let args_names_copy = args_names.clone();
107+
quote! {
108+
fn #function_name(&self, #(#args_names: #args_ast_types),*){
109+
#![allow(unused_mut)]
110+
#![allow(unused_variables)]
111+
let mut payload = Vec::with_capacity(4 + #args_number * 32);
112+
payload.push((#sig >> 24) as u8);
113+
payload.push((#sig >> 16) as u8);
114+
payload.push((#sig >> 8) as u8);
115+
payload.push(#sig as u8);
116+
117+
let mut sink = eng_pwasm_abi::eth::Sink::new(#args_number);
118+
#(sink.push(#args_names_copy);)*
119+
sink.drain_to(&mut payload);
120+
write_ethereum_bridge(&payload, &self.addr);
121+
}
122+
}
123+
})
124+
.collect();
125+
126+
Ok(result)
127+
}
128+
129+
pub fn impl_eth_contract(
130+
args: proc_macro2::TokenStream,
131+
input: proc_macro2::TokenStream,
132+
) -> proc_macro2::TokenStream {
133+
let input_tokens = parse_macro_input2!(input as syn::ItemStruct);
134+
let struct_name = input_tokens.ident;
135+
let file_path = parse_macro_input2!(args as syn::LitStr);
136+
let contents: Box<File> = read_contract_file(file_path.value()).expect("Bad contract file");
137+
let contract = Contract::load(contents).unwrap();
138+
let it: Vec<proc_macro2::TokenStream> = generate_eth_functions(&contract).unwrap();
139+
140+
quote! {
141+
struct #struct_name {
142+
addr: Address,
143+
}
144+
impl EthContract{
145+
fn new(addr_str: /*Address*/&str) -> Self {
146+
use core::str::FromStr;
147+
148+
// Ethereum Addresses need to start with `0x` so we remove the first two characters
149+
let addr = Address::from_str(&addr_str[2..]).expect("Failed converting the address from hex");
150+
EthContract{ addr }
151+
}
152+
#(#it)*
153+
}
154+
}
155+
}
Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,37 @@
11
use failure::Fail;
2-
use std::string::ToString;
3-
use std::io;
2+
use std::{io, string::ToString};
43
use syn;
54

65
#[derive(Debug, Fail)]
76
pub enum EngWasmError {
87
#[fail(display = "I/O error: {:?}", error)]
9-
IoError{
10-
error: String,
11-
},
8+
IoError { error: String },
129
#[fail(display = "Json error: {}", error)]
13-
JsonError {
14-
error: String,
15-
},
10+
JsonError { error: String },
1611
#[fail(display = "Token parse error: {}", error)]
17-
TokenParseError {
18-
error: String,
19-
}
12+
TokenParseError { error: String },
2013
}
2114

22-
2315
impl From<io::Error> for EngWasmError {
2416
fn from(error: io::Error) -> Self {
25-
match error {
26-
_ => EngWasmError::IoError {error: error.to_string()},
17+
EngWasmError::IoError {
18+
error: error.to_string(),
2719
}
2820
}
2921
}
3022

31-
3223
impl From<serde_json::Error> for EngWasmError {
3324
fn from(err: serde_json::Error) -> Self {
34-
match err {
35-
_ => EngWasmError::JsonError {error: err.to_string()},
25+
EngWasmError::JsonError {
26+
error: err.to_string(),
3627
}
3728
}
3829
}
3930

4031
impl From<syn::parse::Error> for EngWasmError {
41-
fn from (err: syn::parse::Error) -> Self {
42-
match err {
43-
_ => EngWasmError::TokenParseError{error: err.to_string()}
32+
fn from(err: syn::parse::Error) -> Self {
33+
EngWasmError::TokenParseError {
34+
error: err.to_string(),
4435
}
4536
}
46-
}
37+
}

eng-wasm/derive/src/ethereum.rs renamed to eng-wasm/derive/src/eth_contract/ethereum.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
use ethabi::param_type::{ParamType, Writer};
12
use tiny_keccak::Keccak;
2-
use ethabi::param_type::{Writer, ParamType};
33

4-
5-
pub fn short_signature(name: &str, params: &[ParamType]) -> u32/*[u8; 4] */{
4+
pub fn short_signature(name: &str, params: &[ParamType]) -> u32 /*[u8; 4] */ {
65
let mut result = [0u8; 4];
76
fill_signature(name, params, &mut result);
87
u32::from_be_bytes(result)
98
}
109

1110
fn fill_signature(name: &str, params: &[ParamType], result: &mut [u8]) {
12-
let types = params.iter()
11+
let types = params
12+
.iter()
1313
.map(Writer::write)
1414
.collect::<Vec<String>>()
1515
.join(",");

eng-wasm/derive/src/into_ident.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub trait IntoIdent {
2+
fn into_ident(self) -> syn::Ident;
3+
}
4+
5+
impl IntoIdent for &str {
6+
fn into_ident(self) -> syn::Ident {
7+
quote::format_ident!("{}", self)
8+
}
9+
}

0 commit comments

Comments
 (0)