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

Commit 39cc487

Browse files
committed
removed the dependency on the order of function argument evaluation in pub_interface
Also slightly improved the generated code for dispatches to contract functions that do not take arguments.
1 parent 371518d commit 39cc487

File tree

1 file changed

+144
-90
lines changed

1 file changed

+144
-90
lines changed

eng-wasm/derive/src/pub_interface.rs

Lines changed: 144 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ fn generate_eng_wasm_aux_functions(
119119
0 => String::new(),
120120
length => {
121121
let mut data = Vec::with_capacity(length as usize);
122-
for _ in 0..length{
122+
for _ in 0..length {
123123
data.push(0);
124124
}
125125

@@ -146,7 +146,7 @@ fn generate_eng_wasm_aux_functions(
146146
0 => Vec::new(),
147147
length => {
148148
let mut data = Vec::with_capacity(length as usize);
149-
for _ in 0..length{
149+
for _ in 0..length {
150150
data.push(0);
151151
}
152152

@@ -174,15 +174,15 @@ fn generate_deploy_function(
174174
let input_pats_and_types = get_signature_input_pats_and_types(&constructor_signature);
175175
let expectations = get_contract_input_parsing_error_messages(&input_pats_and_types);
176176
let input_types = input_pats_and_types.iter().map(|(_pat, type_)| type_);
177+
let variables = generate_enumerated_idents("var_", input_pats_and_types.len());
177178

178179
return quote! {
179180
#[no_mangle]
180181
pub fn #deploy_func_name() {
181182
let args_ = args();
182183
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(&args_);
183-
<#implementor>::#constructor_name(#(
184-
stream.pop::<#input_types>().expect(#expectations),
185-
)*);
184+
#(let #variables = stream.pop::<#input_types>().expect(#expectations);)*
185+
<#implementor>::#constructor_name(#(#variables),*);
186186
}
187187
};
188188
} else {
@@ -242,6 +242,7 @@ fn generate_dispatch_function(
242242
let input_pats_and_types = get_signature_input_pats_and_types(&signature);
243243
let expectations = get_contract_input_parsing_error_messages(&input_pats_and_types);
244244
let input_types = input_pats_and_types.iter().map(|(_pat, type_)| type_);
245+
let variables = generate_enumerated_idents("var_", input_pats_and_types.len());
245246

246247
let return_value_count = match output_type {
247248
syn::ReturnType::Default => 0,
@@ -260,17 +261,26 @@ fn generate_dispatch_function(
260261
}
261262
};
262263

264+
// Make sure we only generate code for initializing the stream of inputs,
265+
// if we expect inputs at all
266+
let stream_initialization_snippet = match input_pats_and_types.len() {
267+
0 => quote!(),
268+
_ => quote!(let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);),
269+
};
270+
263271
match return_value_count {
264272
0 => Some(quote! {
265273
#method_name_as_string => {
266-
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
267-
<#implementor>::#method_name(#(stream.pop::<#input_types>().expect(#expectations),)*);
274+
#stream_initialization_snippet
275+
#(let #variables = stream.pop::<#input_types>().expect(#expectations);)*
276+
<#implementor>::#method_name(#(#variables),*);
268277
}
269278
}),
270279
_ => Some(quote! {
271280
#method_name_as_string => {
272-
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
273-
let result = <#implementor>::#method_name(#(stream.pop::<#input_types>().expect(#expectations),)*);
281+
#stream_initialization_snippet
282+
#(let #variables = stream.pop::<#input_types>().expect(#expectations);)*
283+
let result = <#implementor>::#method_name(#(#variables),*);
274284
// 32 is the size of each argument in the serialised form
275285
// The Sink.drain_to() method might resize this array if any
276286
// dynamically sized elements are returned, but if not, then only one
@@ -297,10 +307,62 @@ fn generate_dispatch_function(
297307
}
298308
}
299309

310+
/// Generate `count` identifiers with the specified prefix, and a decimal suffix in ascending order.
311+
///
312+
/// for example, calling `generate_enumerated_idents("var_", 5)` will generate a vector with the
313+
/// identifiers `var_0`, `var_1`, `var_2`, `var_3`, `var_4`.
314+
fn generate_enumerated_idents(prefix: &str, count: usize) -> Vec<syn::Ident> {
315+
(0..count)
316+
.map(|index| quote::format_ident!("{}{}", prefix, index))
317+
.collect()
318+
}
319+
300320
#[cfg(test)]
301321
mod tests {
302322
use super::*;
303323

324+
/// This is here to use as a sanity check on the full generated code.
325+
///
326+
/// To see what code is generated, comment out the `#[ignore]` line, and run
327+
/// ```sh
328+
/// cargo test show_output -- --nocapture
329+
/// ```
330+
/// Then, take the output from the console (between the two dotted lines, drop it into
331+
/// https://play.rust-lang.org/ , and under the tools menu, choose "Rustfmt".
332+
#[test]
333+
#[ignore]
334+
fn show_output() {
335+
let input = quote!(
336+
pub trait Erc20Interface {
337+
fn construct(contract_owner: H256, total_supply: U256);
338+
/// creates new tokens and sends to the specified address
339+
fn mint(owner: H256, addr: H256, tokens: U256, sig: Vec<u8>);
340+
/// get the total_supply
341+
fn total_supply() -> U256;
342+
/// get the balance of the specified address
343+
fn balance_of(token_owner: H256) -> U256;
344+
/// get the allowed amount of the owner tokens to be spent by the spender address
345+
fn allowance(owner: H256, spender: H256) -> U256;
346+
/// transfer tokens from 'from' address to the 'to' address.
347+
/// the function panics if the 'from' address does not have enough tokens.
348+
fn transfer(from: H256, to: H256, tokens: U256, sig: Vec<u8>);
349+
/// approve the 'spender' address to spend 'tokens' from the 'owner's address balance.
350+
/// the function panics if the 'owner' address does not have enough tokens.
351+
fn approve(token_owner: H256, spender: H256, tokens: U256, sig: Vec<u8>);
352+
/// 'spender' address transfers tokens on behalf of the owner address to the 'to' address.
353+
/// the function panics if the 'owner' address does not have enough tokens or the 'spender'
354+
/// address does not have enough tokens as well.
355+
fn transfer_from(owner: H256, spender: H256, to: H256, tokens: U256, sig: Vec<u8>);
356+
}
357+
);
358+
359+
let output = impl_pub_interface(quote!(), input);
360+
361+
eprintln!("{:-<80}", "");
362+
eprintln!("{}", output);
363+
eprintln!("{:-<80}", "");
364+
}
365+
304366
#[test]
305367
fn apply_macro_attr_works_on_trait() {
306368
let attr_tokens = quote!(Bar);
@@ -433,14 +495,13 @@ mod tests {
433495
pub fn deploy() {
434496
let args_ = args();
435497
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(&args_);
436-
<Contract>::construct(
437-
stream
438-
.pop::<H256>()
439-
.expect("could not decode argument `contract_owner` as `H256`"),
440-
stream
441-
.pop::<U256>()
442-
.expect("could not decode argument `total_supply` as `U256`"),
443-
);
498+
let var_0 = stream
499+
.pop::<H256>()
500+
.expect("could not decode argument `contract_owner` as `H256`");
501+
let var_1 = stream
502+
.pop::<U256>()
503+
.expect("could not decode argument `total_supply` as `U256`");
504+
<Contract>::construct(var_0, var_1);
444505
}
445506
);
446507

@@ -486,23 +547,21 @@ mod tests {
486547
match name {
487548
"mint" => {
488549
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
489-
<Contract>::mint(
490-
stream
491-
.pop::<H256>()
492-
.expect("could not decode argument `owner` as `H256`"),
493-
stream
494-
.pop::<H256>()
495-
.expect("could not decode argument `addr` as `H256`"),
496-
stream
497-
.pop::<U256>()
498-
.expect("could not decode argument `tokens` as `U256`"),
499-
stream
500-
.pop::<Vec<u8>>()
501-
.expect("could not decode argument `sig` as `Vec < u8 >`"),
502-
);
550+
let var_0 = stream
551+
.pop::<H256>()
552+
.expect("could not decode argument `owner` as `H256`");
553+
let var_1 = stream
554+
.pop::<H256>()
555+
.expect("could not decode argument `addr` as `H256`");
556+
let var_2 = stream
557+
.pop::<U256>()
558+
.expect("could not decode argument `tokens` as `U256`");
559+
let var_3 = stream
560+
.pop::<Vec<u8>>()
561+
.expect("could not decode argument `sig` as `Vec < u8 >`");
562+
<Contract>::mint(var_0, var_1, var_2, var_3);
503563
}
504564
"total_supply" => {
505-
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
506565
let result = <Contract>::total_supply();
507566
let mut result_bytes = eng_wasm::Vec::with_capacity(1usize * 32);
508567
let mut sink = eng_wasm::eng_pwasm_abi::eth::Sink::new(1usize);
@@ -517,11 +576,10 @@ mod tests {
517576
}
518577
"balance_of" => {
519578
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
520-
let result = <Contract>::balance_of(
521-
stream
522-
.pop::<H256>()
523-
.expect("could not decode argument `token_owner` as `H256`"),
524-
);
579+
let var_0 = stream
580+
.pop::<H256>()
581+
.expect("could not decode argument `token_owner` as `H256`");
582+
let result = <Contract>::balance_of(var_0);
525583
let mut result_bytes = eng_wasm::Vec::with_capacity(1usize * 32);
526584
let mut sink = eng_wasm::eng_pwasm_abi::eth::Sink::new(1usize);
527585
sink.push(result);
@@ -535,14 +593,13 @@ mod tests {
535593
}
536594
"allowance" => {
537595
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
538-
let result = <Contract>::allowance(
539-
stream
540-
.pop::<H256>()
541-
.expect("could not decode argument `owner` as `H256`"),
542-
stream
543-
.pop::<H256>()
544-
.expect("could not decode argument `spender` as `H256`"),
545-
);
596+
let var_0 = stream
597+
.pop::<H256>()
598+
.expect("could not decode argument `owner` as `H256`");
599+
let var_1 = stream
600+
.pop::<H256>()
601+
.expect("could not decode argument `spender` as `H256`");
602+
let result = <Contract>::allowance(var_0, var_1);
546603
let mut result_bytes = eng_wasm::Vec::with_capacity(1usize * 32);
547604
let mut sink = eng_wasm::eng_pwasm_abi::eth::Sink::new(1usize);
548605
sink.push(result);
@@ -556,57 +613,54 @@ mod tests {
556613
}
557614
"transfer" => {
558615
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
559-
<Contract>::transfer(
560-
stream
561-
.pop::<H256>()
562-
.expect("could not decode argument `from` as `H256`"),
563-
stream
564-
.pop::<H256>()
565-
.expect("could not decode argument `to` as `H256`"),
566-
stream
567-
.pop::<U256>()
568-
.expect("could not decode argument `tokens` as `U256`"),
569-
stream
570-
.pop::<Vec<u8>>()
571-
.expect("could not decode argument `sig` as `Vec < u8 >`"),
572-
);
616+
let var_0 = stream
617+
.pop::<H256>()
618+
.expect("could not decode argument `from` as `H256`");
619+
let var_1 = stream
620+
.pop::<H256>()
621+
.expect("could not decode argument `to` as `H256`");
622+
let var_2 = stream
623+
.pop::<U256>()
624+
.expect("could not decode argument `tokens` as `U256`");
625+
let var_3 = stream
626+
.pop::<Vec<u8>>()
627+
.expect("could not decode argument `sig` as `Vec < u8 >`");
628+
<Contract>::transfer(var_0, var_1, var_2, var_3);
573629
}
574630
"approve" => {
575631
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
576-
<Contract>::approve(
577-
stream
578-
.pop::<H256>()
579-
.expect("could not decode argument `token_owner` as `H256`"),
580-
stream
581-
.pop::<H256>()
582-
.expect("could not decode argument `spender` as `H256`"),
583-
stream
584-
.pop::<U256>()
585-
.expect("could not decode argument `tokens` as `U256`"),
586-
stream
587-
.pop::<Vec<u8>>()
588-
.expect("could not decode argument `sig` as `Vec < u8 >`"),
589-
);
632+
let var_0 = stream
633+
.pop::<H256>()
634+
.expect("could not decode argument `token_owner` as `H256`");
635+
let var_1 = stream
636+
.pop::<H256>()
637+
.expect("could not decode argument `spender` as `H256`");
638+
let var_2 = stream
639+
.pop::<U256>()
640+
.expect("could not decode argument `tokens` as `U256`");
641+
let var_3 = stream
642+
.pop::<Vec<u8>>()
643+
.expect("could not decode argument `sig` as `Vec < u8 >`");
644+
<Contract>::approve(var_0, var_1, var_2, var_3);
590645
}
591646
"transfer_from" => {
592647
let mut stream = eng_wasm::eng_pwasm_abi::eth::Stream::new(args);
593-
<Contract>::transfer_from(
594-
stream
595-
.pop::<H256>()
596-
.expect("could not decode argument `owner` as `H256`"),
597-
stream
598-
.pop::<H256>()
599-
.expect("could not decode argument `spender` as `H256`"),
600-
stream
601-
.pop::<H256>()
602-
.expect("could not decode argument `to` as `H256`"),
603-
stream
604-
.pop::<U256>()
605-
.expect("could not decode argument `tokens` as `U256`"),
606-
stream
607-
.pop::<Vec<u8>>()
608-
.expect("could not decode argument `sig` as `Vec < u8 >`"),
609-
);
648+
let var_0 = stream
649+
.pop::<H256>()
650+
.expect("could not decode argument `owner` as `H256`");
651+
let var_1 = stream
652+
.pop::<H256>()
653+
.expect("could not decode argument `spender` as `H256`");
654+
let var_2 = stream
655+
.pop::<H256>()
656+
.expect("could not decode argument `to` as `H256`");
657+
let var_3 = stream
658+
.pop::<U256>()
659+
.expect("could not decode argument `tokens` as `U256`");
660+
let var_4 = stream
661+
.pop::<Vec<u8>>()
662+
.expect("could not decode argument `sig` as `Vec < u8 >`");
663+
<Contract>::transfer_from(var_0, var_1, var_2, var_3, var_4);
610664
}
611665
_ => panic!("Unknown method called:\"{}\"", name),
612666
}

0 commit comments

Comments
 (0)