Skip to content

Commit

Permalink
fix(near-sdk-sim): allow borsh serialized arguments in sim macro (#345)
Browse files Browse the repository at this point in the history
* fix(near-sdk-sim): allow borsh serialized arguments in sim macro

* Update near-sdk-core/src/code_generator/trait_item_method_info.rs

* fix: formatting; ran `cargo fmt` at root

Added a format check to CI

* fix: address PR comment
  • Loading branch information
Willem Wyndham committed Mar 19, 2021
1 parent 0e3a8e8 commit 9d99077
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 68 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ jobs:
components: rustfmt
target: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v1
- name: Test Format
run: cargo fmt -- --check
- name: Test
run: cargo test --all
55 changes: 31 additions & 24 deletions near-sdk-core/src/code_generator/impl_item_method_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,24 +173,17 @@ impl ImplItemMethodInfo {
let has_input_args = attr_signature_info.input_args().next().is_some();

let pat_type_list = attr_signature_info.pat_type_list();
let json_args = if has_input_args {
let args: TokenStream2 = attr_signature_info
.input_args()
.fold(None, |acc: Option<TokenStream2>, value| {
let ident = &value.ident;
let ident_str = format!("{}", ident.to_string());
Some(match acc {
None => quote! { #ident_str: #ident },
Some(a) => quote! { #a, #ident_str: #ident },
})
})
.unwrap();
quote! {
let args = near_sdk::serde_json::json!({#args});
let serialize_args = if has_input_args {
match &attr_signature_info.input_serializer {
SerializerType::Borsh => crate::TraitItemMethodInfo::generate_serialier(
&attr_signature_info,
&attr_signature_info.input_serializer,
),
SerializerType::JSON => json_serialize(&attr_signature_info),
}
} else {
quote! {
let args = near_sdk::serde_json::json!({});
let args = vec![];
}
};

Expand All @@ -210,15 +203,12 @@ impl ImplItemMethodInfo {
&self, #pat_type_list
};
let ident_str = format!("{}", ident.to_string());
let body = if matches!(method_type, MethodType::View) {
quote! {
near_sdk::PendingContractTx::new(&self.account_id, #ident_str, args, true)
}
let is_view = if matches!(method_type, MethodType::View) {
quote! {true}
} else {
quote! {
near_sdk::PendingContractTx::new(&self.account_id, #ident_str, args, false)
}
quote! {false}
};

let non_bindgen_attrs = non_bindgen_attrs.iter().fold(TokenStream2::new(), |acc, value| {
quote! {
#acc
Expand All @@ -230,9 +220,26 @@ impl ImplItemMethodInfo {
#[cfg(not(target_arch = "wasm32"))]
#non_bindgen_attrs
pub fn #ident#generics(#params) #return_ident {
#json_args
#body
#serialize_args
near_sdk::PendingContractTx::new_from_bytes(&self.account_id, #ident_str, args, #is_view)
}
}
}
}

fn json_serialize(attr_signature_info: &AttrSigInfo) -> TokenStream2 {
let args: TokenStream2 = attr_signature_info
.input_args()
.fold(None, |acc: Option<TokenStream2>, value| {
let ident = &value.ident;
let ident_str = ident.to_string();
Some(match acc {
None => quote! { #ident_str: #ident },
Some(a) => quote! { #a, #ident_str: #ident },
})
})
.unwrap();
quote! {
let args = near_sdk::serde_json::json!({#args}).to_string().into_bytes();
}
}
30 changes: 28 additions & 2 deletions near-sdk-core/src/code_generator/item_impl_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,34 @@ mod tests {
let expected = quote!(
#[cfg(not(target_arch = "wasm32"))]
pub fn method(&self, k: String,) -> near_sdk::PendingContractTx {
let args = near_sdk::serde_json::json!({ "k" : k });
near_sdk::PendingContractTx::new(& self . account_id, "method", args, true)
let args = near_sdk::serde_json::json!({ "k": k })
.to_string()
.into_bytes();
near_sdk::PendingContractTx::new_from_bytes(&self.account_id, "method", args, true)
}
);
assert_eq!(expected.to_string(), actual.to_string());
}

#[test]
fn marshall_borsh() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str(r#"
pub fn borsh_test(&mut self, #[serializer(borsh)] a: String) {}
"#).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let actual = method_info.marshal_method();
let expected = quote!(
#[cfg(not(target_arch = "wasm32"))]
pub fn borsh_test(&self, a: String,) -> near_sdk::PendingContractTx {
#[derive(near_sdk :: borsh :: BorshSerialize)]
struct Input {
a: String,
}
let args = Input { a, };
let args = near_sdk::borsh::BorshSerialize::try_to_vec(&args)
.expect("Failed to serialize the cross contract args using Borsh.");
near_sdk::PendingContractTx::new_from_bytes(&self.account_id, "borsh_test", args, false)
}
);
assert_eq!(expected.to_string(), actual.to_string());
Expand Down
2 changes: 0 additions & 2 deletions near-sdk-core/src/code_generator/item_trait_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,3 @@ mod tests {
assert_eq!(actual.to_string(), expected.to_string());
}
}


60 changes: 36 additions & 24 deletions near-sdk-core/src/code_generator/trait_item_method_info.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::info_extractor::{InputStructType, SerializerType, TraitItemMethodInfo};
use crate::{
info_extractor::{InputStructType, SerializerType, TraitItemMethodInfo},
AttrSigInfo,
};
use quote::quote;
use syn::export::TokenStream2;

Expand All @@ -8,31 +11,13 @@ impl TraitItemMethodInfo {
let ident = &self.attr_sig_info.ident;
let ident_byte_str = &self.ident_byte_str;
let pat_type_list = self.attr_sig_info.pat_type_list();
let has_input_args = self.attr_sig_info.input_args().next().is_some();
let struct_decl;
let constructor;
let value_ser = if !has_input_args {
struct_decl = TokenStream2::new();
constructor = TokenStream2::new();
quote! {let args = vec![]; }
} else {
struct_decl = self.attr_sig_info.input_struct(InputStructType::Serialization);
let constructor_call = self.attr_sig_info.constructor_expr();
constructor = quote! {let args = #constructor_call;};
match self.attr_sig_info.result_serializer {
SerializerType::JSON => quote! {
let args = near_sdk::serde_json::to_vec(&args).expect("Failed to serialize the cross contract args using JSON.");
},
SerializerType::Borsh => quote! {
let args = near_sdk::borsh::BorshSerialize::try_to_vec(&args).expect("Failed to serialize the cross contract args using Borsh.");
},
}
};
let serialize = TraitItemMethodInfo::generate_serialier(
&self.attr_sig_info,
&self.attr_sig_info.result_serializer,
);
quote! {
pub fn #ident<T: ToString>(#pat_type_list __account_id: &T, __balance: near_sdk::Balance, __gas: near_sdk::Gas) -> near_sdk::Promise {
#struct_decl
#constructor
#value_ser
#serialize
near_sdk::Promise::new(__account_id.to_string())
.function_call(
#ident_byte_str.to_vec(),
Expand All @@ -43,4 +28,31 @@ impl TraitItemMethodInfo {
}
}
}

pub fn generate_serialier(
attr_sig_info: &AttrSigInfo,
serializer: &SerializerType,
) -> TokenStream2 {
let has_input_args = attr_sig_info.input_args().next().is_some();
if !has_input_args {
return quote! { let args = vec![]; };
}
let struct_decl = attr_sig_info.input_struct(InputStructType::Serialization);
let constructor_call = attr_sig_info.constructor_expr();
let constructor = quote! { let args = #constructor_call; };
let value_ser = match serializer {
SerializerType::JSON => quote! {
let args = near_sdk::serde_json::to_vec(&args).expect("Failed to serialize the cross contract args using JSON.");
},
SerializerType::Borsh => quote! {
let args = near_sdk::borsh::BorshSerialize::try_to_vec(&args).expect("Failed to serialize the cross contract args using Borsh.");
},
};

quote! {
#struct_decl
#constructor
#value_ser
}
}
}
14 changes: 3 additions & 11 deletions near-sdk-sim/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ pub(crate) fn key_to_b58(key: &[u8]) -> String {
impl ContractCache {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
data: Rc::new(RefCell::new(HashMap::new())),
}
Self { data: Rc::new(RefCell::new(HashMap::new())) }
}

fn path() -> PathBuf {
Expand All @@ -37,11 +35,7 @@ impl ContractCache {
let prefix = path.parent().unwrap();
std::fs::create_dir_all(prefix).unwrap();
// Ensure we can read, write, and create file if it doesn't exist
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
OpenOptions::new().read(true).write(true).create(true).open(path)
}

fn get_path(&self, key: &[u8]) -> PathBuf {
Expand All @@ -53,9 +47,7 @@ impl ContractCache {
}

pub fn insert(&self, key: &[u8], value: &[u8]) -> Option<Vec<u8>> {
(*self.data)
.borrow_mut()
.insert((*key).to_owned(), (*value).to_owned())
(*self.data).borrow_mut().insert((*key).to_owned(), (*value).to_owned())
}

pub fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
Expand Down
14 changes: 9 additions & 5 deletions near-sdk/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ pub struct PendingContractTx {

impl PendingContractTx {
pub fn new(receiver_id: &str, method: &str, args: serde_json::Value, is_view: bool) -> Self {
Self {
receiver_id: receiver_id.to_string(),
method: method.to_string(),
args: args.to_string().into_bytes(),
PendingContractTx::new_from_bytes(
receiver_id,
method,
args.to_string().into_bytes(),
is_view,
}
)
}

pub fn new_from_bytes(receiver_id: &str, method: &str, args: Vec<u8>, is_view: bool) -> Self {
Self { receiver_id: receiver_id.to_string(), method: method.to_string(), args, is_view }
}
}

Expand Down

0 comments on commit 9d99077

Please sign in to comment.