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

Commit 493eebd

Browse files
committed
MERGE: Merged develop into ptt
2 parents 932446a + ad2a484 commit 493eebd

File tree

35 files changed

+1994
-329
lines changed

35 files changed

+1994
-329
lines changed

eng_wasm/Cargo.toml

100644100755
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ authors = ["moria <moria@enigma.co>"]
66
[dependencies]
77
serde_json = "1.0"
88
serde = "1.0"
9+
pwasm-abi = { git = "https://github.com/enigmampc/pwasm-abi.git" }
10+
failure_derive="=0.1.1"
11+
failure = { version = "=0.1.1", default-features = false, features = ["derive"] }
12+
syn = { version = "0.15.12", features = ["full", "extra-traits"] }
13+
tiny-keccak = "1.4"
14+
ethabi = "6.1.0"
15+
byteorder = "1"

eng_wasm/dispatch/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "eng_wasm_dispatch"
3+
version = "0.1.0"
4+
5+
[dependencies]
6+
eng_wasm = {path = "../../eng_wasm"}
7+
proc-macro2 = "0.4"
8+
quote = "0.6.8"
9+
syn = { version = "0.15.12", features = ["full", "extra-traits"] }
10+
serde_json = "1.0"
11+
ethabi = "6.1.0"
12+
13+
[lib]
14+
proc-macro = true

eng_wasm/dispatch/src/lib.rs

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#![recursion_limit="128"]
2+
extern crate eng_wasm;
3+
extern crate proc_macro2;
4+
#[macro_use] extern crate quote;
5+
extern crate proc_macro;
6+
#[macro_use]
7+
extern crate syn;
8+
extern crate serde_json;
9+
extern crate ethabi;
10+
11+
use eng_wasm::*;
12+
use std::fs::File;
13+
use std::string::ToString;
14+
//use std::io::prelude::*;
15+
use std::convert::*;
16+
use ethabi::{Contract, ParamType};
17+
18+
fn generate_eng_wasm_aux_functions() -> proc_macro2::TokenStream{
19+
quote!{
20+
#[no_mangle]
21+
pub fn function_name() -> String {
22+
23+
let length_result = unsafe { eng_wasm::external::fetch_function_name_length() };
24+
25+
match length_result {
26+
0 => "".to_string(),
27+
length => {
28+
let mut data = Vec::with_capacity(length as usize);
29+
for _ in 0..length{
30+
data.push(0);
31+
}
32+
33+
unsafe {
34+
eng_wasm::external::fetch_function_name(data.as_mut_ptr());
35+
}
36+
from_utf8(&data).unwrap().to_string()
37+
}
38+
}
39+
}
40+
#[no_mangle]
41+
pub fn args() -> String {
42+
let length_result = unsafe { external::fetch_args_length() };
43+
44+
match length_result {
45+
0 => "".to_string(),
46+
length => {
47+
let mut data = Vec::with_capacity(length as usize);
48+
for _ in 0..length{
49+
data.push(0);
50+
}
51+
52+
unsafe {
53+
external::fetch_args(data.as_mut_ptr());
54+
}
55+
from_utf8(&data).unwrap().to_string()
56+
}
57+
}
58+
}
59+
60+
}
61+
}
62+
63+
fn generate_dispatch(input: syn::Item) -> proc_macro2::TokenStream{
64+
let v;
65+
let functions= match input {
66+
syn::Item::Trait(input) => {
67+
v = input.items;
68+
v.iter()
69+
},
70+
_ => panic!(),
71+
};
72+
73+
let it: Vec<proc_macro2::TokenStream> = functions.filter_map(|item| {
74+
match item {
75+
syn::TraitItem::Method(item) => {
76+
let func = item.sig.ident.clone();
77+
let arg_types: Vec<proc_macro2::TokenStream> = item.sig.decl.inputs.iter().filter_map(|arg| match arg {
78+
// Argument captured by a name
79+
syn::FnArg::Captured(arg_captured) => {
80+
let ty = &arg_captured.ty;
81+
Some(quote!{#ty})
82+
},
83+
// Argument without a name
84+
syn::FnArg::Ignored(type_only) => {
85+
Some(quote!{#type_only})
86+
},
87+
_ => None,
88+
}).collect();
89+
90+
let name = &func.to_string();
91+
//println!("METHOD {:#?} TYPES {:#?}", item, arg_types);
92+
Some(quote!{
93+
#name => {
94+
let mut stream = pwasm_abi::eth::Stream::new(args.as_bytes());
95+
96+
Contract::#func(#(stream.pop::<#arg_types>().expect("argument decoding failed")),*);
97+
98+
}
99+
})
100+
},
101+
_ => None,
102+
}
103+
}).collect();
104+
105+
106+
quote! {
107+
pub fn dispatch(name: &str, args: &str){
108+
match name{
109+
#(#it,)*
110+
_=>panic!(),
111+
}
112+
}
113+
}
114+
}
115+
116+
#[proc_macro_attribute]
117+
#[allow(unused_variables, unused_mut)]
118+
pub fn dispatch(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
119+
let input_tokens = parse_macro_input!(input as syn::Item);
120+
let disp = generate_dispatch(input_tokens.clone());
121+
let eng_wasm_aux = generate_eng_wasm_aux_functions();
122+
let result = quote! {
123+
#eng_wasm_aux
124+
#input_tokens
125+
#disp
126+
127+
#[no_mangle]
128+
pub fn call(){
129+
dispatch(&function_name(), &args());
130+
}
131+
};
132+
proc_macro::TokenStream::from(result)
133+
}
134+
135+
//--------------------------------------------------------------------------------------------------
136+
137+
trait Write{
138+
fn write(&self) -> String;
139+
fn error(&self) -> String;
140+
}
141+
142+
impl Write for ParamType{
143+
/// Returns string which is a formatted represenation of param.
144+
fn write(&self) -> String {
145+
match *self{
146+
ParamType::Address => "Address".to_owned(),
147+
ParamType::Bytes => "Vec<u8>".to_owned(),
148+
ParamType::FixedBytes(len) => format!("u8[{}]", len),
149+
ParamType::Int(len) => match len{
150+
32 | 64 => format!("i{}", len),
151+
_ => panic!("{}", self.error()),
152+
},
153+
ParamType::Uint(len) => match len{
154+
32 | 64 => format!("i{}", len),
155+
256 => "U256".to_owned(),
156+
_ => panic!("{}", self.error()),
157+
},
158+
ParamType::Bool => "bool".to_owned(),
159+
ParamType::String => "String".to_owned(),
160+
ParamType::FixedArray(ref param, len) => format!("{}[{}]", param.write(), len),
161+
ParamType::Array(ref param) => format!("Vec<{}>", param.write()),
162+
}
163+
}
164+
fn error(&self) -> String{
165+
format!("The type {} is not supported", self.to_string())
166+
}
167+
}
168+
169+
#[derive(Debug)]
170+
struct FunctionAst {
171+
name: syn::Ident,
172+
args_ast_types: Vec<syn::Type>,
173+
args_types: Vec<ParamType>,
174+
}
175+
176+
fn read_contract_file(file_path: String) -> Result<Box<File>, EngWasmError>{
177+
let file = File::open(file_path)?;
178+
let contents = Box::new(file);
179+
Ok(contents)
180+
}
181+
182+
fn generate_eth_functions(contract: &Contract) -> Result<Box<Vec<proc_macro2::TokenStream>>,EngWasmError>{
183+
let mut functions: Vec<FunctionAst> = Vec::new();
184+
for function in &contract.functions{
185+
let mut args_ast_types = Vec::new();
186+
for input in &function.1.inputs{
187+
let arg_type: syn::Type = syn::parse_str(&input.kind.clone().write())?;
188+
args_ast_types.push(arg_type);
189+
}
190+
let args_types = function.1.inputs.iter().map(|input| {
191+
input.kind.clone()
192+
}).collect();
193+
194+
let name = syn::Ident::new(&function.1.name, proc_macro2::Span::call_site());
195+
functions.push(FunctionAst{name, args_types, args_ast_types})
196+
}
197+
198+
let result: Vec<proc_macro2::TokenStream> = functions.iter().map(|function| {
199+
let function_name = &function.name;
200+
let args_ast_types = function.args_ast_types.clone();
201+
let sig_u32 = short_signature(&function_name.to_string(), &function.args_types);
202+
let sig = syn::Lit::Int(syn::LitInt::new(sig_u32 as u64, syn::IntSuffix::U32, proc_macro2::Span::call_site()));
203+
let args_number = syn::Lit::Int(syn::LitInt::new(args_ast_types.len() as u64,
204+
syn::IntSuffix::Usize,
205+
proc_macro2::Span::call_site()));
206+
let args_names: Vec<syn::Ident> = function.args_ast_types.iter().enumerate().map(|item| {
207+
let mut arg = String::from("arg");
208+
arg.push_str(item.0.to_string().as_str());
209+
syn::Ident::new(&arg, proc_macro2::Span::call_site())
210+
}).collect();
211+
let args_names_copy = args_names.clone();
212+
quote!{
213+
fn #function_name(&self, #(#args_names: #args_ast_types),*){
214+
#![allow(unused_mut)]
215+
#![allow(unused_variables)]
216+
let mut payload = Vec::with_capacity(4 + #args_number * 32);
217+
payload.push((#sig >> 24) as u8);
218+
payload.push((#sig >> 16) as u8);
219+
payload.push((#sig >> 8) as u8);
220+
payload.push(#sig as u8);
221+
222+
let mut sink = pwasm_abi::eth::Sink::new(#args_number);
223+
#(sink.push(#args_names_copy);)*
224+
sink.drain_to(&mut payload);
225+
write_ethereum_payload(payload);
226+
write_ethereum_contract_addr(&self.addr);
227+
}
228+
}
229+
}).collect();
230+
231+
Ok(Box::new(result))
232+
}
233+
234+
#[proc_macro_attribute]
235+
#[allow(unused_variables, unused_mut)]
236+
pub fn eth_contract(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
237+
let input_tokens = parse_macro_input!(input as syn::ItemStruct);
238+
let struct_name = input_tokens.ident;
239+
let file_path = parse_macro_input!(args as syn::LitStr);
240+
let mut contents: Box<File> = read_contract_file(file_path.value()).expect("Bad contract file");
241+
let contract = Contract::load(contents).unwrap();
242+
let it: Vec<proc_macro2::TokenStream> = *generate_eth_functions(&contract).unwrap();
243+
244+
let result = quote! {
245+
struct #struct_name{
246+
addr: [u8;20],
247+
}
248+
impl EthContract{
249+
fn new(addr_str: /*Address*/&str) -> Self {
250+
EthContract{addr: From::from(Address::from(addr_str.as_bytes()))}
251+
}
252+
#(#it)*
253+
}
254+
};
255+
proc_macro::TokenStream::from(result)
256+
}

eng_wasm/src/eng_wasm_errors.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use super::failure::Fail;
2+
use internal_std::String;
3+
use internal_std::ToString;
4+
use internal_std::io;
5+
use syn;
6+
7+
#[derive(Debug, Fail)]
8+
pub enum EngWasmError {
9+
#[fail(display = "I/O error: {:?}", error)]
10+
IoError{
11+
error: String,
12+
},
13+
#[fail(display = "Json error: {}", error)]
14+
JsonError {
15+
error: String,
16+
},
17+
#[fail(display = "Token parse error: {}", error)]
18+
TokenParseError {
19+
error: String,
20+
}
21+
}
22+
23+
24+
impl From<std::io::Error> for EngWasmError {
25+
fn from(error: io::Error) -> Self {
26+
match error {
27+
_ => EngWasmError::IoError {error: error.to_string()},
28+
}
29+
}
30+
}
31+
32+
33+
impl From<serde_json::Error> for EngWasmError {
34+
fn from(err: serde_json::Error) -> Self {
35+
match err {
36+
_ => EngWasmError::JsonError {error: err.to_string()},
37+
}
38+
}
39+
}
40+
41+
impl From<syn::parse::Error> for EngWasmError {
42+
fn from (err: syn::parse::Error) -> Self {
43+
match err {
44+
_ => EngWasmError::TokenParseError{error: err.to_string()}
45+
}
46+
}
47+
}

eng_wasm/src/ethereum.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use internal_std::Vec;
2+
use internal_std::String;
3+
use internal_std::SliceConcatExt;
4+
use tiny_keccak::Keccak;
5+
use ethabi::param_type::{Writer, ParamType};
6+
use byteorder::{BigEndian, ByteOrder};
7+
8+
9+
pub fn short_signature(name: &str, params: &[ParamType]) -> u32/*[u8; 4] */{
10+
let mut result = [0u8; 4];
11+
fill_signature(name, params, &mut result);
12+
BigEndian::read_u32(&result.as_ref()[0..4])
13+
}
14+
15+
fn fill_signature(name: &str, params: &[ParamType], result: &mut [u8]) {
16+
let types = params.iter()
17+
.map(Writer::write)
18+
.collect::<Vec<String>>()
19+
.join(",");
20+
21+
let data: Vec<u8> = From::from(eformat!("{}({})", name, types).as_str());
22+
23+
let mut sponge = Keccak::new_keccak256();
24+
sponge.update(&data);
25+
sponge.finalize(result);
26+
}

eng_wasm/src/internal_std.rs

100644100755
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
extern crate std;
1+
pub extern crate std;
22

33
pub use self::std::fmt;
44
//pub use self::std::prelude::v1::*;
55
pub use self::std::iter;
66
pub use self::std::string::{ToString, String};
77
pub use self::std::vec::Vec;
8+
pub use self::std::str::from_utf8;
9+
pub use self::std::io;
10+
pub use self::std::slice::SliceConcatExt;
811

912
//pub fn zeroed_vec(s: usize) -> Vec<u8> {
1013
// vec![0u8; s]

0 commit comments

Comments
 (0)