From 9bf17ee749b3649e0ca0084ee9b8bc3c3950f006 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Tue, 3 Aug 2021 15:23:36 +0300 Subject: [PATCH 01/13] WIP --- crates/codec/src/api/builder/call.rs | 28 ++++----- crates/codec/src/api/json/call.rs | 28 +++++---- crates/codec/src/api/json/calldata.rs | 2 +- crates/codec/src/api/json/spawn.rs | 2 +- crates/codec/src/call.rs | 23 ++++---- crates/runtime/src/func_env.rs | 12 ++-- crates/runtime/src/runtime/call.rs | 6 +- crates/runtime/src/runtime/default.rs | 84 +++++++++++++++------------ crates/types/src/transaction/mod.rs | 27 ++++----- 9 files changed, 110 insertions(+), 102 deletions(-) diff --git a/crates/codec/src/api/builder/call.rs b/crates/codec/src/api/builder/call.rs index 05bfe11d8..012536ddb 100644 --- a/crates/codec/src/api/builder/call.rs +++ b/crates/codec/src/api/builder/call.rs @@ -9,7 +9,7 @@ pub struct CallBuilder { version: Option, target: Option
, func_name: Option, - // verifydata: Option>, + verifydata: Option>, calldata: Option>, } @@ -26,14 +26,14 @@ pub struct CallBuilder { /// let target = Address::of("@target").into(); /// /// let func_name = "do_work"; -/// // let verifydata = vec![0x10, 0x20, 0x30]; +/// let verifydata = vec![0x10, 0x20, 0x30]; /// let calldata = vec![0x10, 0x20, 0x30]; /// /// let bytes = CallBuilder::new() /// .with_version(0) /// .with_target(&target) /// .with_func(func_name) -/// // .with_verifydata(&verifydata) +/// .with_verifydata(&verifydata) /// .with_calldata(&calldata) /// .build(); /// @@ -43,7 +43,7 @@ pub struct CallBuilder { /// version: 0, /// target, /// func_name: func_name.to_string(), -/// // verifydata, +/// verifydata, /// calldata, /// }; /// @@ -58,7 +58,7 @@ impl CallBuilder { version: None, target: None, func_name: None, - // verifydata: None, + verifydata: None, calldata: None, } } @@ -78,10 +78,10 @@ impl CallBuilder { self } - // pub fn with_verifydata(mut self, verifydata: &[u8]) -> Self { - // self.verifydata = Some(verifydata.to_vec()); - // self - // } + pub fn with_verifydata(mut self, verifydata: &[u8]) -> Self { + self.verifydata = Some(verifydata.to_vec()); + self + } pub fn with_calldata(mut self, calldata: &[u8]) -> Self { self.calldata = Some(calldata.to_vec()); @@ -93,10 +93,10 @@ impl CallBuilder { let target = self.target.unwrap(); let func_name = self.func_name.unwrap(); - // let verifydata = match self.verifydata { - // None => vec![], - // Some(verifydata) => verifydata.to_vec(), - // }; + let verifydata = match self.verifydata { + None => vec![], + Some(verifydata) => verifydata.to_vec(), + }; let calldata = match self.calldata { None => vec![], @@ -107,7 +107,7 @@ impl CallBuilder { version, target, func_name, - // verifydata, + verifydata, calldata, }; diff --git a/crates/codec/src/api/json/call.rs b/crates/codec/src/api/json/call.rs index d7ef046e3..c1da8603a 100644 --- a/crates/codec/src/api/json/call.rs +++ b/crates/codec/src/api/json/call.rs @@ -5,7 +5,7 @@ use std::io::Cursor; use svm_types::Transaction; -use super::calldata::{decode_raw_calldata, DecodedCallData}; +use super::calldata::{decode_raw_input, DecodedCallData}; use super::serde_types::*; use crate::api::json::{JsonError, JsonSerdeUtils}; @@ -63,12 +63,10 @@ pub fn decode_call(json: &str) -> Result { let encoded_call = EncodedData::from_json_str(json)?; let tx = { let mut cursor = Cursor::new(&encoded_call.data.0[..]); + crate::call::decode_call(&mut cursor).unwrap() }; - // let verifydata = json::bytes_to_str(&tx.verifydata); - // let verifydata = json::decode_calldata(&json!({ "calldata": verifydata }))?; - Ok(DecodedCall::from(tx).to_json()) } @@ -77,7 +75,7 @@ struct DecodedCall { version: u16, target: AddressWrapper, func_name: String, - // verifydata: String, + verifydata: EncodedOrDecodedCalldata, calldata: EncodedOrDecodedCalldata, } @@ -86,10 +84,12 @@ impl JsonSerdeUtils for DecodedCall {} impl From for Transaction { fn from(decoded: DecodedCall) -> Self { let target = decoded.target.into(); + Transaction { version: decoded.version, func_name: decoded.func_name, target, + verifydata: decoded.verifydata.encode(), calldata: decoded.calldata.encode(), } } @@ -101,8 +101,12 @@ impl From for DecodedCall { version: tx.version, target: AddressWrapper::from(&tx.target), func_name: tx.func_name.clone(), + verifydata: EncodedOrDecodedCalldata::Decoded( + DecodedCallData::new(&decode_raw_input(tx.verifydata()).unwrap().to_string()) + .unwrap(), + ), calldata: EncodedOrDecodedCalldata::Decoded( - DecodedCallData::new(&decode_raw_calldata(&tx.calldata).unwrap().to_string()) + DecodedCallData::new(&decode_raw_input(tx.calldata()).unwrap().to_string()) .unwrap(), ), } @@ -243,8 +247,8 @@ mod tests { "version": 0, "target": "10203040506070809000A0B0C0D0E0F0ABCDEFFF", "func_name": "do_something", - // "verifydata": verifydata["calldata"], - "calldata": calldata["data"], + "verifydata": verifydata["verifydata"], + "calldata": calldata["calldata"], }) .to_string(); @@ -257,10 +261,10 @@ mod tests { "version": 0, "target": "10203040506070809000A0B0C0D0E0F0ABCDEFFF", "func_name": "do_something", - // "verifydata": { - // "abi": ["bool", "i8"], - // "data": [true, 3] - // }, + "verifydata": { + "abi": ["bool", "i8"], + "data": [true, 3] + }, "calldata": { "abi": ["i32", "i64"], "data": [10, 20] diff --git a/crates/codec/src/api/json/calldata.rs b/crates/codec/src/api/json/calldata.rs index 6d36ef28f..7c3d35ba0 100644 --- a/crates/codec/src/api/json/calldata.rs +++ b/crates/codec/src/api/json/calldata.rs @@ -27,7 +27,7 @@ pub fn encode_calldata(json: &str) -> Result { Ok(EncodedData { data: calldata }.to_json()) } -pub fn decode_raw_calldata(data: &[u8]) -> Result { +pub fn decode_raw_input(data: &[u8]) -> Result { let calldata = CallData::new(data); Ok(calldata_to_json(calldata)) } diff --git a/crates/codec/src/api/json/spawn.rs b/crates/codec/src/api/json/spawn.rs index d8679d06d..de94b1eaf 100644 --- a/crates/codec/src/api/json/spawn.rs +++ b/crates/codec/src/api/json/spawn.rs @@ -56,7 +56,7 @@ impl JsonSerdeUtils for DecodedSpawn {} impl From for DecodedSpawn { fn from(spawn: SpawnAccount) -> Self { let template_addr = TemplateAddrWrapper(spawn.template_addr().clone()); - let decoded_calldata = super::calldata::decode_raw_calldata(&spawn.calldata).unwrap(); + let decoded_calldata = super::calldata::decode_raw_input(&spawn.calldata).unwrap(); Self { version: spawn.version, diff --git a/crates/codec/src/call.rs b/crates/codec/src/call.rs index d93025cae..a385de5cd 100644 --- a/crates/codec/src/call.rs +++ b/crates/codec/src/call.rs @@ -23,16 +23,16 @@ use std::io::Cursor; use crate::{calldata, version}; use crate::{Field, ParseError, ReadExt, WriteExt}; -/// Encodes a raw [`Transaction`] +/// Encodes a binary [`Transaction`] pub fn encode_call(tx: &Transaction, w: &mut Vec) { encode_version(tx, w); encode_target(tx, w); encode_func(tx, w); - // encode_verifydata(tx, w); + encode_verifydata(tx, w); encode_calldata(tx, w); } -/// Parsing a raw [`Transaction`]. +/// Parsing a binary [`Transaction`]. /// /// Returns the parsed transaction as [`Transaction`] struct. /// On failure, returns `ParseError` @@ -40,14 +40,14 @@ pub fn decode_call(cursor: &mut Cursor<&[u8]>) -> Result) { } fn encode_func(tx: &Transaction, w: &mut Vec) { - let func = tx.function(); + let func = tx.func_name(); w.write_string(func); } -// fn encode_verifydata(tx: &Transaction, w: &mut Vec) { -// let verifydata = &tx.verifydata; - -// calldata::encode_calldata(verifydata, w) -// } +fn encode_verifydata(tx: &Transaction, w: &mut Vec) { + let verifydata = tx.verifydata(); + calldata::encode_calldata(verifydata, w) +} fn encode_calldata(tx: &Transaction, w: &mut Vec) { let calldata = tx.calldata(); @@ -115,7 +114,7 @@ mod tests { version: 0, target: Address::of("@target").into(), func_name: "do_work".to_string(), - // verifydata: vec![0x10, 0x0, 0x30], + verifydata: vec![0xAA, 0xBB, 0xCC], calldata: vec![0x10, 0x0, 0x30], }; diff --git a/crates/runtime/src/func_env.rs b/crates/runtime/src/func_env.rs index 6b46b8975..2f9e04923 100644 --- a/crates/runtime/src/func_env.rs +++ b/crates/runtime/src/func_env.rs @@ -31,15 +31,15 @@ impl FuncEnv { storage: AccountStorage, envelope: &Envelope, context: &Context, - template_addr: &TemplateAddr, - target_addr: &Address, + template_addr: TemplateAddr, + target_addr: Address, ) -> Self { let inner = Inner::new(storage); Self { inner: Rc::new(RefCell::new(inner)), - template_addr: template_addr.clone(), - target_addr: target_addr.clone(), + template_addr: template_addr, + target_addr: target_addr, envelope: envelope.clone(), context: context.clone(), } @@ -51,8 +51,8 @@ impl FuncEnv { storage: AccountStorage, envelope: &Envelope, context: &Context, - template_addr: &TemplateAddr, - target_addr: &Address, + template_addr: TemplateAddr, + target_addr: Address, ) -> Self { let func_env = Self::new(storage, envelope, context, template_addr, target_addr); func_env.borrow_mut().set_memory(memory); diff --git a/crates/runtime/src/runtime/call.rs b/crates/runtime/src/runtime/call.rs index b36b43fe6..860370884 100644 --- a/crates/runtime/src/runtime/call.rs +++ b/crates/runtime/src/runtime/call.rs @@ -5,9 +5,9 @@ use svm_types::{Address, Context, Envelope, Gas, State, TemplateAddr}; #[derive(Debug, Clone, PartialEq)] pub struct Call<'a> { pub func_name: &'a str, - pub calldata: &'a [u8], - pub target_addr: &'a Address, - pub target_template: &'a TemplateAddr, + pub func_input: &'a [u8], + pub target: Address, + pub template: TemplateAddr, pub state: &'a State, pub gas_used: Gas, pub gas_left: Gas, diff --git a/crates/runtime/src/runtime/default.rs b/crates/runtime/src/runtime/default.rs index 792e2ef7d..f283ca63b 100644 --- a/crates/runtime/src/runtime/default.rs +++ b/crates/runtime/src/runtime/default.rs @@ -11,7 +11,7 @@ use svm_program::Program; use svm_storage::account::AccountStorage; use svm_types::{ Address, CallReceipt, Context, DeployReceipt, Envelope, Gas, GasMode, OOGError, ReceiptLog, - RuntimeError, SectionKind, SpawnReceipt, State, Template, TemplateAddr, + RuntimeError, SectionKind, SpawnReceipt, State, Template, TemplateAddr, Transaction, }; use super::{Call, Failure, Function, Outcome}; @@ -116,20 +116,20 @@ where fn call_ctor( &mut self, spawn: &ExtSpawn, - target: &Address, + target: Address, gas_used: Gas, gas_left: Gas, envelope: &Envelope, context: &Context, ) -> SpawnReceipt { - let template_addr = spawn.template_addr(); + let template = spawn.template_addr().clone(); let call = Call { func_name: spawn.ctor_name(), - calldata: spawn.ctor_data(), + func_input: spawn.ctor_data(), state: &State::zeros(), - target_template: template_addr, - target_addr: target, + template, + target: target.clone(), within_spawn: true, gas_used, gas_left, @@ -140,7 +140,7 @@ where let receipt = self.exec_call::<(), ()>(&call); // TODO: move the `into_spawn_receipt` to a `From / TryFrom` - svm_types::into_spawn_receipt(receipt, target) + svm_types::into_spawn_receipt(receipt, &target) } fn exec_call(&mut self, call: &Call) -> CallReceipt { @@ -155,17 +155,16 @@ where Rets: WasmTypeList, F: Fn(&FuncEnv, Outcome>) -> R, { - match self.account_template(call.target_addr) { + match self.account_template(&call.target) { Ok(template) => { - let storage = - self.open_storage(call.target_addr, call.state, template.fixed_layout()); + let storage = self.open_storage(&call.target, call.state, template.fixed_layout()); let mut env = FuncEnv::new( storage, call.envelope, call.context, - call.target_template, - call.target_addr, + call.template.clone(), + call.target.clone(), ); let store = crate::wasm_store::new_store(); @@ -199,8 +198,8 @@ where let func = self.func::(&instance, func_env, call.func_name)?; - let mut out = if call.calldata.len() > 0 { - self.call_with_alloc(&instance, func_env, call.calldata, &func, &[])? + let mut out = if call.func_input.len() > 0 { + self.call_with_alloc(&instance, func_env, call.func_input, &func, &[])? } else { self.call(&instance, func_env, &func, &[])? }; @@ -497,6 +496,35 @@ where Ok(()) } + fn build_call<'a>( + &self, + tx: &'a Transaction, + envelope: &'a Envelope, + context: &'a Context, + func_name: &'a str, + func_input: &'a [u8], + ) -> Call<'a> { + let target = tx.target(); + let template = self.env.resolve_template_addr(target); + + if let Some(template) = template { + Call { + func_name, + func_input, + target: target.clone(), + template, + state: context.state(), + gas_used: Gas::with(0), + gas_left: envelope.gas_limit(), + within_spawn: false, + envelope, + context, + } + } else { + unreachable!("Should have failed earlier when doing `validate_call`"); + } + } + /// Errors #[inline] @@ -705,12 +733,12 @@ where match gas_left { Ok(gas_left) => { let account = ExtAccount::new(spawn.account(), &spawner); - let addr = self.env.compute_account_addr(&spawn); + let target = self.env.compute_account_addr(&spawn); - self.env.store_account(&account, &addr); + self.env.store_account(&account, &target); let gas_used = payload_price.into(); - self.call_ctor(&spawn, &addr, gas_used, gas_left, envelope, context) + self.call_ctor(&spawn, target, gas_used, gas_left, envelope, context) } Err(..) => SpawnReceipt::new_oog(Vec::new()), } @@ -731,25 +759,7 @@ where .parse_call(message) .expect("Should have called `validate_call` first"); - let template = self.env.resolve_template_addr(tx.target()); - - if let Some(template) = template { - let call = Call { - func_name: tx.function(), - calldata: tx.calldata(), - target_addr: tx.target(), - target_template: &template, - state: context.state(), - gas_used: Gas::with(0), - gas_left: envelope.gas_limit(), - within_spawn: false, - envelope, - context, - }; - - self.exec_call::<(), ()>(&call) - } else { - unreachable!("Should have failed earlier when doing `validate_call`"); - } + let call = self.build_call(&tx, envelope, context, tx.func_name(), tx.calldata()); + self.exec_call::<(), ()>(&call) } } diff --git a/crates/types/src/transaction/mod.rs b/crates/types/src/transaction/mod.rs index ef04df4bf..960508f5d 100644 --- a/crates/types/src/transaction/mod.rs +++ b/crates/types/src/transaction/mod.rs @@ -24,10 +24,9 @@ pub struct Transaction { /// Function's name to execute pub func_name: String, - // TODO: - // Transaction's `VerifyData` - // See issue: https://github.com/spacemeshos/svm/issues/248 - // pub verifydata: Vec, + /// Transaction's `VerifyData` + pub verifydata: Vec, + /// Transaction's `CallData` pub calldata: Vec, } @@ -39,16 +38,14 @@ impl Transaction { } #[doc(hidden)] - pub fn function(&self) -> &str { + pub fn func_name(&self) -> &str { &self.func_name } - // TODO: - // See issue: https://github.com/spacemeshos/svm/issues/248 - // #[doc(hidden)] - // pub fn verifydata(&self) -> &[u8] { - // &self.verifydata - // } + #[doc(hidden)] + pub fn verifydata(&self) -> &[u8] { + &self.verifydata + } #[doc(hidden)] pub fn calldata(&self) -> &[u8] { @@ -58,17 +55,15 @@ impl Transaction { impl fmt::Debug for Transaction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // let verifydata = self.verifydata.iter().take(4).collect::>(); + let verifydata = self.verifydata.iter().take(4).collect::>(); let calldata = self.calldata.iter().take(4).collect::>(); f.debug_struct("Transaction") .field("version", &self.version) .field("target", self.target()) - // TODO: - // See issue: https://github.com/spacemeshos/svm/issues/248 - // .field("verifydata", &verifydata) + .field("verifydata", &verifydata) .field("calldata", &calldata) - .field("function", &self.function()) + .field("function", &self.func_name()) .finish() } } From c10fa607d33f800ed3960e83f7ff7dd914b9c3c2 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Tue, 3 Aug 2021 15:28:38 +0300 Subject: [PATCH 02/13] WIP --- crates/runtime/src/runtime/call.rs | 3 +-- crates/runtime/src/runtime/default.rs | 30 +++++++++++++-------------- crates/runtime/src/runtime/mod.rs | 9 ++------ 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/crates/runtime/src/runtime/call.rs b/crates/runtime/src/runtime/call.rs index 860370884..e748b6f4e 100644 --- a/crates/runtime/src/runtime/call.rs +++ b/crates/runtime/src/runtime/call.rs @@ -9,8 +9,7 @@ pub struct Call<'a> { pub target: Address, pub template: TemplateAddr, pub state: &'a State, - pub gas_used: Gas, - pub gas_left: Gas, + pub gas_limit: Gas, pub within_spawn: bool, pub context: &'a Context, pub envelope: &'a Envelope, diff --git a/crates/runtime/src/runtime/default.rs b/crates/runtime/src/runtime/default.rs index f283ca63b..d00d8fbfe 100644 --- a/crates/runtime/src/runtime/default.rs +++ b/crates/runtime/src/runtime/default.rs @@ -117,7 +117,6 @@ where &mut self, spawn: &ExtSpawn, target: Address, - gas_used: Gas, gas_left: Gas, envelope: &Envelope, context: &Context, @@ -131,8 +130,7 @@ where template, target: target.clone(), within_spawn: true, - gas_used, - gas_left, + gas_limit: gas_left, envelope, context, }; @@ -191,7 +189,7 @@ where { self.validate_call(call, template, func_env)?; - let module = self.compile_template(store, func_env, &template, call.gas_left)?; + let module = self.compile_template(store, func_env, &template, call.gas_limit)?; let instance = self.instantiate(func_env, &module, import_object)?; self.set_memory(func_env, &instance); @@ -514,8 +512,7 @@ where target: target.clone(), template, state: context.state(), - gas_used: Gas::with(0), - gas_left: envelope.gas_limit(), + gas_limit: envelope.gas_limit(), within_spawn: false, envelope, context, @@ -736,21 +733,22 @@ where let target = self.env.compute_account_addr(&spawn); self.env.store_account(&account, &target); - let gas_used = payload_price.into(); - - self.call_ctor(&spawn, target, gas_used, gas_left, envelope, context) + self.call_ctor(&spawn, target, gas_left, envelope, context) } Err(..) => SpawnReceipt::new_oog(Vec::new()), } } - fn verify( - &self, - _envelope: &Envelope, - _message: &[u8], - _context: &Context, - ) -> std::result::Result { - todo!("https://github.com/spacemeshos/svm/issues/248") + fn verify(&mut self, envelope: &Envelope, message: &[u8], context: &Context) -> CallReceipt { + let tx = self + .env + .parse_call(message) + .expect("Should have called `validate_call` first"); + + let call = self.build_call(&tx, envelope, context, "svm_verify", tx.verifydata()); + + // TODO: override the `call.gas_limit` with `VERIFY_MAX_GAS` + self.exec_call::<(), ()>(&call) } fn call(&mut self, envelope: &Envelope, message: &[u8], context: &Context) -> CallReceipt { diff --git a/crates/runtime/src/runtime/mod.rs b/crates/runtime/src/runtime/mod.rs index 7b079c93c..9d62c85d7 100644 --- a/crates/runtime/src/runtime/mod.rs +++ b/crates/runtime/src/runtime/mod.rs @@ -21,7 +21,7 @@ pub use rocksdb::create_rocksdb_runtime; pub use config::Config; pub use default::DefaultRuntime; -use svm_types::{CallReceipt, Context, DeployReceipt, Envelope, RuntimeError, SpawnReceipt}; +use svm_types::{CallReceipt, Context, DeployReceipt, Envelope, SpawnReceipt}; use crate::error::ValidateError; @@ -49,12 +49,7 @@ pub trait Runtime { fn spawn(&mut self, envelope: &Envelope, message: &[u8], context: &Context) -> SpawnReceipt; /// Verifies a [`Transaction`](svm_types::Transaction) before execution. - fn verify( - &self, - envelope: &Envelope, - message: &[u8], - context: &Context, - ) -> Result; + fn verify(&mut self, envelope: &Envelope, message: &[u8], context: &Context) -> CallReceipt; /// Executes a [`Transaction`](svm_types::Transaction) and returns its output [`CallReceipt`]. /// From 04c9f5af9702e71c6060254775abf84fcd8fca57 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Tue, 3 Aug 2021 15:55:31 +0300 Subject: [PATCH 03/13] WIP --- crates/runtime-ffi/src/api.rs | 81 +++++++++++++++++++++++++++ crates/runtime-ffi/src/lib.rs | 3 +- crates/runtime/src/runtime/default.rs | 13 +++-- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/crates/runtime-ffi/src/api.rs b/crates/runtime-ffi/src/api.rs index 0587570c2..267ccd87f 100644 --- a/crates/runtime-ffi/src/api.rs +++ b/crates/runtime-ffi/src/api.rs @@ -23,6 +23,7 @@ static MESSAGE_TYPE: Type = Type::Str("Tx Message"); static CONTEXT_TYPE: Type = Type::Str("Tx Context"); static DEPLOY_RECEIPT_TYPE: Type = Type::Str("Deploy Receipt"); static SPAWN_RECEIPT_TYPE: Type = Type::Str("Spawn Receipt"); +static VERIFY_RECEIPT_TYPE: Type = Type::Str("Verify Receipt"); static CALL_RECEIPT_TYPE: Type = Type::Str("Call Receipt"); static SVM_RESOURCE_TYPE: Type = Type::of::(); @@ -472,6 +473,86 @@ pub unsafe extern "C" fn svm_spawn( }) } +/// Calls `verify` on an Account. +/// The inputs `envelope`, `message` and `context` should be the same ones +/// passed later to `svm_call`.(in case the `verify` succeeds). +/// +/// Returns the Receipt of the execution via the `receipt` parameter. +/// +/// # Examples +/// +/// ```rust, no_run +/// use std::ffi::c_void; +/// +/// use svm_runtime_ffi::*; +/// +/// let mut runtime = std::ptr::null_mut(); +/// let mut error = svm_byte_array::default(); +/// +/// let res = unsafe { svm_memory_runtime_create(&mut runtime, &mut error) }; +/// assert!(res.is_ok()); +/// +/// let mut receipt = svm_byte_array::default(); +/// let envelope = svm_byte_array::default(); +/// let message = svm_byte_array::default(); +/// let context = svm_byte_array::default(); +/// +/// let _res = unsafe { +/// svm_verify( +/// &mut receipt, +/// runtime, +/// envelope, +/// message, +/// context, +/// &mut error) +/// }; +/// ``` +/// +#[must_use] +#[no_mangle] +pub unsafe extern "C" fn svm_verify( + receipt: *mut svm_byte_array, + runtime: *mut c_void, + envelope: svm_byte_array, + message: svm_byte_array, + context: svm_byte_array, + error: *mut svm_byte_array, +) -> svm_result_t { + catch_unwind_with_err(&mut *error, svm_result_t::SVM_FAILURE, || { + debug!("`svm_verify` start"); + + let runtime = RuntimeRef::as_native(runtime); + let message = message.as_slice(); + + let envelope = decode_envelope(envelope); + if let Err(e) = envelope { + raw_io_error(e, &mut *error); + return svm_result_t::SVM_FAILURE; + } + + let context = decode_context(context); + if let Err(e) = context { + raw_io_error(e, &mut *error); + return svm_result_t::SVM_FAILURE; + } + + let envelope = envelope.unwrap(); + let context = context.unwrap(); + let rust_receipt = runtime.verify(&envelope, &message, &context); + let receipt_bytes = receipt::encode_call(&rust_receipt); + + // Returns encoded `CallReceipt` as `svm_byte_array`. + // + // # Notes: + // + // Should call later `svm_receipt_destroy` + data_to_svm_byte_array(VERIFY_RECEIPT_TYPE, &mut *receipt, receipt_bytes); + + debug!("`svm_verify` returns `SVM_SUCCESS`"); + svm_result_t::SVM_SUCCESS + }) +} + /// `Call Account` transaction. /// Returns the Receipt of the execution via the `receipt` parameter. /// diff --git a/crates/runtime-ffi/src/lib.rs b/crates/runtime-ffi/src/lib.rs index 3f4ea7f39..3a470b496 100644 --- a/crates/runtime-ffi/src/lib.rs +++ b/crates/runtime-ffi/src/lib.rs @@ -47,9 +47,10 @@ pub use api::{ svm_validate_call, // Transactions Execution - svm_call, svm_deploy, svm_spawn, + svm_verify, + svm_call, // Destroy svm_runtime_destroy, diff --git a/crates/runtime/src/runtime/default.rs b/crates/runtime/src/runtime/default.rs index d00d8fbfe..525bc94ad 100644 --- a/crates/runtime/src/runtime/default.rs +++ b/crates/runtime/src/runtime/default.rs @@ -199,7 +199,7 @@ where let mut out = if call.func_input.len() > 0 { self.call_with_alloc(&instance, func_env, call.func_input, &func, &[])? } else { - self.call(&instance, func_env, &func, &[])? + self.wasmer_call(&instance, func_env, &func, &[])? }; let logs = out.take_logs(); @@ -241,7 +241,7 @@ where let wasm_ptr = out.returns(); self.set_calldata(env, calldata, wasm_ptr); - self.call(instance, env, func, params) + self.wasmer_call(instance, env, func, params) } fn call_alloc(&self, instance: &Instance, env: &FuncEnv, size: usize) -> Result> { @@ -256,7 +256,7 @@ where let func = func.unwrap(); let params: [wasmer::Val; 1] = [(size as i32).into()]; - let out = self.call(instance, env, &func, ¶ms)?; + let out = self.wasmer_call(instance, env, &func, ¶ms)?; let out = out.map(|rets| { let ret = &rets[0]; let offset = ret.i32().unwrap() as u32; @@ -267,7 +267,7 @@ where Ok(out) } - fn call( + fn wasmer_call( &self, instance: &Instance, env: &FuncEnv, @@ -474,6 +474,11 @@ where template: &Template, env: &FuncEnv, ) -> std::result::Result<(), Failure> { + // TODO: validate there is enough gas for running the `Transaction`. + // * verify + // * call + // * other factors + let spawning = call.within_spawn; let ctor = template.is_ctor(call.func_name); From a230f39ffd719c6324e20c43b56f778993063d55 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Wed, 4 Aug 2021 16:37:43 +0300 Subject: [PATCH 04/13] WIP --- crates/codec/src/api/json/call.rs | 21 ++++++++----- crates/codec/src/api/wasm/call.rs | 23 ++++++++------ crates/runtime/tests/vmcalls_tests.rs | 44 +++++++++++++-------------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/crates/codec/src/api/json/call.rs b/crates/codec/src/api/json/call.rs index c1da8603a..b2d403a04 100644 --- a/crates/codec/src/api/json/call.rs +++ b/crates/codec/src/api/json/call.rs @@ -16,10 +16,8 @@ use crate::api::json::{JsonError, JsonSerdeUtils}; /// "version": 0, // number /// "target": "A2FB...", // string /// "func_name": "do_work", // string -/// "verifydata": "", // string -/// "calldata": { -/// ... -/// } +/// "verifydata": {"abi": [], "data": []}, +/// "calldata": {"abi": [], "data": []}, /// } /// /// The `calldata` field can be both encoded and user-friendly form. @@ -219,7 +217,7 @@ mod tests { "version": 0, "target": "10203040506070809000A0B0C0D0E0F0ABCDEFFF", "func_name": "do_something", - "verifydata": verifydata["calldata"] + "verifydata": verifydata["data"] }) .to_string(); @@ -243,12 +241,21 @@ mod tests { ) .unwrap(); + let verifydata = json::encode_calldata( + &json!({ + "abi": ["bool", "i8"], + "data": [true, 3], + }) + .to_string(), + ) + .unwrap(); + let json = json!({ "version": 0, "target": "10203040506070809000A0B0C0D0E0F0ABCDEFFF", "func_name": "do_something", - "verifydata": verifydata["verifydata"], - "calldata": calldata["calldata"], + "verifydata": verifydata["data"], + "calldata": calldata["data"], }) .to_string(); diff --git a/crates/codec/src/api/wasm/call.rs b/crates/codec/src/api/wasm/call.rs index ef0390aa7..e66d3fd91 100644 --- a/crates/codec/src/api/wasm/call.rs +++ b/crates/codec/src/api/wasm/call.rs @@ -38,11 +38,14 @@ mod test { fn wasm_call_valid() { let target = "1122334455667788990011223344556677889900"; - // let verifydata = api::json::encode_calldata(&json!({ - // "abi": ["bool", "i8"], - // "data": [true, 3] - // })) - // .unwrap(); + let verifydata = api::json::encode_calldata( + &json!({ + "abi": ["bool", "i8"], + "data": [true, 3] + }) + .to_string(), + ) + .unwrap(); let calldata = api::json::encode_calldata( &json!({ @@ -57,7 +60,7 @@ mod test { "version": 1, "target": target, "func_name": "do_something", - // "verifydata": verifydata["calldata"], + "verifydata": verifydata["data"], "calldata": calldata["data"] }); @@ -88,10 +91,10 @@ mod test { "version": 1, "target": target, "func_name": "do_something", - // "verifydata": { - // "abi": ["bool", "i8"], - // "data": [true, 3], - // }, + "verifydata": { + "abi": ["bool", "i8"], + "data": [true, 3], + }, "calldata": { "abi": ["i32", "i64"], "data": [10, 20], diff --git a/crates/runtime/tests/vmcalls_tests.rs b/crates/runtime/tests/vmcalls_tests.rs index f7581dc06..f1b5bc5ec 100644 --- a/crates/runtime/tests/vmcalls_tests.rs +++ b/crates/runtime/tests/vmcalls_tests.rs @@ -115,14 +115,14 @@ fn vmcalls_empty_wasm() { #[test] fn vmcalls_get32_set32() { let template_addr = TemplateAddr::repeat(0xAB); - let account_addr = Address::repeat(0xCD); + let target_addr = Address::repeat(0xCD); let layout: FixedLayout = vec![4, 2].into(); let store = wasmer_store(); - let storage = testing::blank_storage(&account_addr, &layout); + let storage = testing::blank_storage(&target_addr, &layout); let envelope = Envelope::default(); let context = Context::default(); - let func_env = FuncEnv::new(storage, &envelope, &context, &template_addr, &account_addr); + let func_env = FuncEnv::new(storage, &envelope, &context, template_addr, target_addr); let import_object = imports! { "svm" => { @@ -150,14 +150,14 @@ fn vmcalls_get32_set32() { #[test] fn vmcalls_get64_set64() { let template_addr = TemplateAddr::repeat(0xAB); - let account_addr = Address::repeat(0xCD); + let target_addr = Address::repeat(0xCD); let layout: FixedLayout = vec![4, 2].into(); let store = wasmer_store(); - let storage = testing::blank_storage(&account_addr, &layout); + let storage = testing::blank_storage(&target_addr, &layout); let envelope = Envelope::default(); let context = Context::default(); - let func_env = FuncEnv::new(storage, &envelope, &context, &template_addr, &account_addr); + let func_env = FuncEnv::new(storage, &envelope, &context, template_addr, target_addr); let import_object = imports! { "svm" => { @@ -185,12 +185,12 @@ fn vmcalls_get64_set64() { #[test] fn vmcalls_load160() { let template_addr = TemplateAddr::repeat(0xAB); - let account_addr = Address::repeat(0xCD); + let target_addr = Address::repeat(0xCD); let layout: FixedLayout = vec![20].into(); let store = wasmer_store(); let memory = wasmer_memory(&store); - let storage = testing::blank_storage(&account_addr, &layout); + let storage = testing::blank_storage(&target_addr, &layout); let envelope = Envelope::default(); let context = Context::default(); let func_env = FuncEnv::new_with_memory( @@ -198,8 +198,8 @@ fn vmcalls_load160() { storage, &envelope, &context, - &template_addr, - &account_addr, + template_addr, + target_addr.clone(), ); let import_object = imports! { @@ -218,7 +218,7 @@ fn vmcalls_load160() { { let storage = &mut func_env.borrow_mut().storage; - storage.write_var(Id(0), account_addr.as_slice().to_vec()); + storage.write_var(Id(0), target_addr.as_slice().to_vec()); } let func: NativeFunc<(u32, u32)> = instance.exports.get_native_function("load").unwrap(); @@ -230,18 +230,18 @@ fn vmcalls_load160() { let view = &memory.view::()[ptr as usize..(ptr as usize + 20)]; let bytes: Vec = view.iter().map(|cell| cell.get()).collect(); - assert_eq!(account_addr, Address::from(&bytes[..])); + assert_eq!(target_addr, Address::from(&bytes[..])); } #[test] fn vmcalls_store160() { let template_addr = TemplateAddr::repeat(0xAB); - let account_addr = Address::repeat(0xCD); + let target_addr = Address::repeat(0xCD); let layout: FixedLayout = vec![20].into(); let store = wasmer_store(); let memory = wasmer_memory(&store); - let storage = testing::blank_storage(&account_addr, &layout); + let storage = testing::blank_storage(&target_addr, &layout); let envelope = Envelope::default(); let context = Context::default(); let func_env = FuncEnv::new_with_memory( @@ -249,8 +249,8 @@ fn vmcalls_store160() { storage, &envelope, &context, - &template_addr, - &account_addr, + template_addr, + target_addr.clone(), ); let import_object = imports! { @@ -267,7 +267,7 @@ fn vmcalls_store160() { include_str!("wasm/load160_store160.wast").into(), ); - for (cell, byte) in memory.view::().iter().zip(account_addr.as_slice()) { + for (cell, byte) in memory.view::().iter().zip(target_addr.as_slice()) { cell.set(*byte); } @@ -277,18 +277,18 @@ fn vmcalls_store160() { func.call(var_id, ptr).expect("function has failed"); - assert_storage!(func_env, 0 => account_addr.as_slice()); + assert_storage!(func_env, 0 => target_addr.as_slice()); } #[test] fn vmcalls_log() { let template_addr = TemplateAddr::repeat(0xAB); - let account_addr = Address::repeat(0xCD); + let target_addr = Address::repeat(0xCD); let layout = FixedLayout::default(); let store = wasmer_store(); let memory = wasmer_memory(&store); - let storage = testing::blank_storage(&account_addr, &layout); + let storage = testing::blank_storage(&target_addr, &layout); let envelope = Envelope::default(); let context = Context::default(); let func_env = FuncEnv::new_with_memory( @@ -296,8 +296,8 @@ fn vmcalls_log() { storage, &envelope, &context, - &template_addr, - &account_addr, + template_addr, + target_addr, ); let import_object = imports! { From f0db8888b9d530c61de68119994a97457c504d2d Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Wed, 4 Aug 2021 17:35:29 +0300 Subject: [PATCH 05/13] Fixing the `svm_codec.wasm` to use `verifydata` --- crates/abi/decoder/src/calldata.rs | 2 - crates/abi/tests/src/lib.rs | 16 ++-- crates/codec/build.sh | 2 +- crates/codec/examples/test.js | 73 +++++++++++-------- crates/codec/src/api/json/call.rs | 14 ++-- .../api/json/{calldata.rs => inputdata.rs} | 14 ++-- crates/codec/src/api/json/mod.rs | 4 +- crates/codec/src/api/json/spawn.rs | 8 +- crates/codec/src/api/wasm/call.rs | 4 +- .../api/wasm/{calldata.rs => inputdata.rs} | 35 +++++---- crates/codec/src/api/wasm/mod.rs | 4 +- crates/codec/src/api/wasm/spawn.rs | 2 +- crates/codec/src/call.rs | 10 +-- crates/codec/src/calldata.rs | 25 ------- crates/codec/src/field.rs | 4 +- crates/codec/src/inputdata.rs | 25 +++++++ crates/codec/src/lib.rs | 24 +++--- crates/codec/src/spawn.rs | 6 +- crates/sdk/src/lib.rs | 2 +- 19 files changed, 142 insertions(+), 132 deletions(-) rename crates/codec/src/api/json/{calldata.rs => inputdata.rs} (96%) rename crates/codec/src/api/wasm/{calldata.rs => inputdata.rs} (68%) delete mode 100644 crates/codec/src/calldata.rs create mode 100644 crates/codec/src/inputdata.rs diff --git a/crates/abi/decoder/src/calldata.rs b/crates/abi/decoder/src/calldata.rs index 0e0385019..432d45651 100644 --- a/crates/abi/decoder/src/calldata.rs +++ b/crates/abi/decoder/src/calldata.rs @@ -8,7 +8,6 @@ use crate::{Cursor, Decoder}; /// Its main usage is by the `svm-sdk` crate for decoding the binary `calldata` into a Rust native values. pub struct CallData { cursor: Cursor, - decoder: Decoder, } @@ -17,7 +16,6 @@ impl CallData { pub fn new(bytes: &[u8]) -> Self { Self { cursor: Cursor::new(bytes), - decoder: Decoder::new(), } } diff --git a/crates/abi/tests/src/lib.rs b/crates/abi/tests/src/lib.rs index f833d7b93..b6232fc8f 100644 --- a/crates/abi/tests/src/lib.rs +++ b/crates/abi/tests/src/lib.rs @@ -8,7 +8,7 @@ #[cfg(test)] mod tests { - use svm_abi_decoder::CallData; + use svm_abi_decoder::InputData; use svm_abi_encoder::Encoder; use svm_sdk_std::{Option, Vec}; @@ -294,7 +294,7 @@ mod tests { let mut buf = Vec::with_capacity(1000); a.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let a_ = calldata.next().unwrap().into(); assert_eq!(a, a_); @@ -307,7 +307,7 @@ mod tests { let mut buf = Vec::with_capacity(1000); a.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let a_ = calldata.next_1(); assert_eq!(a, a_); @@ -323,7 +323,7 @@ mod tests { a.encode(&mut buf); b.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let (a_, b_) = calldata.next_2(); assert_eq!(a, a_); @@ -342,7 +342,7 @@ mod tests { b.encode(&mut buf); c.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let (a_, b_, c_) = calldata.next_3(); assert_eq!(a, a_); @@ -364,7 +364,7 @@ mod tests { c.encode(&mut buf); d.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let (a_, b_, c_, d_): (u32, i16, bool, [u8; 2]) = calldata.next_4(); assert_eq!(a, a_); @@ -389,7 +389,7 @@ mod tests { d.encode(&mut buf); e.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let (a_, b_, c_, d_, e_): (u32, i16, bool, [u8; 2], [u16; 3]) = calldata.next_5(); assert_eq!(a, a_); @@ -417,7 +417,7 @@ mod tests { e.encode(&mut buf); f.encode(&mut buf); - let mut calldata = CallData::new(as_static!(buf)); + let mut calldata = InputData::new(as_static!(buf)); let (a_, b_, c_, d_, e_, f_): (u32, i16, bool, [u8; 2], [u16; 3], Amount) = calldata.next_6(); diff --git a/crates/codec/build.sh b/crates/codec/build.sh index 7f637bf1e..b8aa7c4f3 100755 --- a/crates/codec/build.sh +++ b/crates/codec/build.sh @@ -1,2 +1,2 @@ set -e -cargo +nightly build --release --target wasm32-unknown-unknown \ No newline at end of file +cargo +nightly build --release --target wasm32-unknown-unknown \ No newline at end of file diff --git a/crates/codec/examples/test.js b/crates/codec/examples/test.js index 1858af7fa..73700c47e 100644 --- a/crates/codec/examples/test.js +++ b/crates/codec/examples/test.js @@ -124,9 +124,9 @@ function generateAddress(s) { return repeatString(s, 20); } -function encodeCallData(instance, object) { +function encodeInput(instance, object) { const buf = wasmNewBuffer(instance, object); - const result = instanceCall(instance, "wasm_encode_calldata", buf); + const result = instanceCall(instance, "wasm_encode_inputdata", buf); const encoded = loadWasmBufferDataAsJson(instance, result); @@ -136,9 +136,9 @@ function encodeCallData(instance, object) { return encoded; } -function decodeCallData(instance, encodedData) { +function decodeInput(instance, encodedData) { const buf = wasmNewBuffer(instance, encodedData); - const result = instanceCall(instance, "wasm_decode_calldata", buf); + const result = instanceCall(instance, "wasm_decode_inputdata", buf); const json = loadWasmBufferDataAsJson(instance, result); wasmBufferFree(instance, buf); @@ -163,58 +163,58 @@ function binToString(array) { return result; } -describe("Encode Calldata", function () { - function testCallData(instance, abi, data) { +describe("Encode InputData", function () { + function testInputData(instance, abi, data) { const calldata = { abi: abi, data: data, }; - let encoded = encodeCallData(instance, calldata); - let decoded = decodeCallData(instance, encoded); + let encoded = encodeInput(instance, calldata); + let decoded = decodeInput(instance, encoded); assert.deepStrictEqual(decoded, calldata); } it("i8", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["i8"], [-10]); + testInputData(instance, ["i8"], [-10]); }); }); it("u8", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["u8"], [10]); + testInputData(instance, ["u8"], [10]); }); }); it("i16", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["i16"], [-10]); + testInputData(instance, ["i16"], [-10]); }); }); it("u16", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["u16"], [10]); + testInputData(instance, ["u16"], [10]); }); }); it("i32", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["i32"], [-10]); + testInputData(instance, ["i32"], [-10]); }); }); it("u32", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["u32"], [10]); + testInputData(instance, ["u32"], [10]); }); }); it("amount", function () { return compileWasmCodec().then((instance) => { - testCallData(instance, ["amount"], [10]); + testInputData(instance, ["amount"], [10]); }); }); @@ -226,8 +226,8 @@ describe("Encode Calldata", function () { data: [addr], }; - let encoded = encodeCallData(instance, object); - let decoded = decodeCallData(instance, encoded); + let encoded = encodeInput(instance, object); + let decoded = decodeInput(instance, encoded); assert.deepStrictEqual(decoded, { abi: ["address"], @@ -246,8 +246,8 @@ describe("Encode Calldata", function () { data: [[addr1, addr2]], }; - let encoded = encodeCallData(instance, object); - let decoded = decodeCallData(instance, encoded); + let encoded = encodeInput(instance, object); + let decoded = decodeInput(instance, encoded); assert.deepStrictEqual(decoded, { abi: [["address"]], @@ -312,10 +312,7 @@ describe("Deploy Template", function () { const result = instanceCall(instance, "wasm_encode_deploy", buf); const error = loadWasmBufferError(instance, result); - assert.strictEqual( - error, - 'A non-optional field was missing (`name`).' - ); + assert.strictEqual(error, "A non-optional field was missing (`name`)."); wasmBufferFree(instance, buf); wasmBufferFree(instance, result); @@ -369,7 +366,7 @@ describe("Spawn Account", function () { data: [10, 20], }; - let calldata = encodeCallData(instance, object); + let calldata = encodeInput(instance, object); const bytes = encodeSpawn(instance, template, name, calldata["data"]); const json = decodeSpawn(instance, bytes); @@ -398,7 +395,7 @@ describe("Spawn Account", function () { const error = loadWasmBufferError(instance, result); assert.strictEqual( error, - 'The value of a specific field is invalid (`template`).' + "The value of a specific field is invalid (`template`)." ); wasmBufferFree(instance, buf); @@ -408,11 +405,12 @@ describe("Spawn Account", function () { }); describe("Call Account", function () { - function encodeCall(instance, target, calldata) { + function encodeCall(instance, target, verifydata, calldata) { let tx = { version: 0, target: target, func_name: "do_something", + verifydata: verifydata, calldata: calldata, }; @@ -446,19 +444,32 @@ describe("Call Account", function () { return compileWasmCodec().then((instance) => { const target = generateAddress("1020304050"); - const object = { + let verifydata = encodeInput(instance, { + abi: ["bool", "i8"], + data: [true, 5], + }); + + let calldata = encodeInput(instance, { abi: ["i32", "i64"], data: [10, 20], - }; + }); - let calldata = encodeCallData(instance, object); - const bytes = encodeCall(instance, target, calldata["data"]); + const bytes = encodeCall( + instance, + target, + verifydata["data"], + calldata["data"] + ); const json = decodeCall(instance, bytes); assert.deepStrictEqual(json, { version: 0, target: target, func_name: "do_something", + verifydata: { + abi: ["bool", "i8"], + data: [true, 5], + }, calldata: { abi: ["i32", "i64"], data: [10, 20], @@ -476,7 +487,7 @@ describe("Call Account", function () { const error = loadWasmBufferError(instance, result); assert.strictEqual( error, - 'The value of a specific field is invalid (`target`).' + "The value of a specific field is invalid (`target`)." ); wasmBufferFree(instance, buf); diff --git a/crates/codec/src/api/json/call.rs b/crates/codec/src/api/json/call.rs index b2d403a04..3091e60bd 100644 --- a/crates/codec/src/api/json/call.rs +++ b/crates/codec/src/api/json/call.rs @@ -5,7 +5,7 @@ use std::io::Cursor; use svm_types::Transaction; -use super::calldata::{decode_raw_input, DecodedCallData}; +use super::inputdata::{decode_raw_input, DecodedInputData}; use super::serde_types::*; use crate::api::json::{JsonError, JsonSerdeUtils}; @@ -100,11 +100,11 @@ impl From for DecodedCall { target: AddressWrapper::from(&tx.target), func_name: tx.func_name.clone(), verifydata: EncodedOrDecodedCalldata::Decoded( - DecodedCallData::new(&decode_raw_input(tx.verifydata()).unwrap().to_string()) + DecodedInputData::new(&decode_raw_input(tx.verifydata()).unwrap().to_string()) .unwrap(), ), calldata: EncodedOrDecodedCalldata::Decoded( - DecodedCallData::new(&decode_raw_input(tx.calldata()).unwrap().to_string()) + DecodedInputData::new(&decode_raw_input(tx.calldata()).unwrap().to_string()) .unwrap(), ), } @@ -117,7 +117,7 @@ impl From for DecodedCall { #[serde(untagged)] pub(crate) enum EncodedOrDecodedCalldata { Encoded(HexBlob>), - Decoded(DecodedCallData), + Decoded(DecodedInputData), } impl EncodedOrDecodedCalldata { @@ -204,7 +204,7 @@ mod tests { #[test] fn json_call_missing_calldata() { - let verifydata = json::encode_calldata( + let verifydata = json::encode_inputdata( &json!({ "abi": ["bool", "i8"], "data": [true, 3], @@ -232,7 +232,7 @@ mod tests { #[test] fn json_call_valid() { - let calldata = json::encode_calldata( + let calldata = json::encode_inputdata( &json!({ "abi": ["i32", "i64"], "data": [10, 20], @@ -241,7 +241,7 @@ mod tests { ) .unwrap(); - let verifydata = json::encode_calldata( + let verifydata = json::encode_inputdata( &json!({ "abi": ["bool", "i8"], "data": [true, 3], diff --git a/crates/codec/src/api/json/calldata.rs b/crates/codec/src/api/json/inputdata.rs similarity index 96% rename from crates/codec/src/api/json/calldata.rs rename to crates/codec/src/api/json/inputdata.rs index 7c3d35ba0..074a4545d 100644 --- a/crates/codec/src/api/json/calldata.rs +++ b/crates/codec/src/api/json/inputdata.rs @@ -13,7 +13,7 @@ use super::serde_types::{AddressWrapper, EncodedData, HexBlob}; use super::JsonSerdeUtils; use crate::api::json::JsonError; -/// Given a `Calldata` JSON, encodes it into a binary `Calldata` +/// Given an `Input Data` JSON, encodes it into a binary `Input Data` /// and returns the result wrapped with a JSON. /// /// ```json @@ -21,8 +21,8 @@ use crate::api::json::JsonError; /// "data": "FFC103..." /// } /// ``` -pub fn encode_calldata(json: &str) -> Result { - let decoded = DecodedCallData::new(json)?; +pub fn encode_inputdata(json: &str) -> Result { + let decoded = DecodedInputData::new(json)?; let calldata = HexBlob(decoded.encode().unwrap()); Ok(EncodedData { data: calldata }.to_json()) } @@ -33,7 +33,7 @@ pub fn decode_raw_input(data: &[u8]) -> Result { } /// Given a binary `Calldata` (wrapped within a JSON), decodes it into a JSON -pub fn decode_calldata(json: &str) -> Result { +pub fn decode_inputdata(json: &str) -> Result { let encoded = EncodedData::from_json_str(json)?; let calldata = CallData::new(&encoded.data.0); Ok(calldata_to_json(calldata)) @@ -41,12 +41,12 @@ pub fn decode_calldata(json: &str) -> Result { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] -pub(crate) struct DecodedCallData { +pub(crate) struct DecodedInputData { abi: Vec, data: Vec, } -impl DecodedCallData { +impl DecodedInputData { pub fn new(json: &str) -> Result { let decoded = Self::from_json_str(json)?; @@ -85,7 +85,7 @@ impl DecodedCallData { } } -impl JsonSerdeUtils for DecodedCallData {} +impl JsonSerdeUtils for DecodedInputData {} fn calldata_to_json(mut calldata: CallData) -> Json { let mut abi = vec![]; diff --git a/crates/codec/src/api/json/mod.rs b/crates/codec/src/api/json/mod.rs index 517f5b114..f44626d2b 100644 --- a/crates/codec/src/api/json/mod.rs +++ b/crates/codec/src/api/json/mod.rs @@ -1,7 +1,7 @@ //! JSON API mod call; -mod calldata; +mod inputdata; mod deploy; mod error; mod receipt; @@ -10,7 +10,7 @@ mod spawn; pub(crate) mod serde_types; pub use call::{decode_call, encode_call, encode_call_raw}; -pub use calldata::{decode_calldata, encode_calldata}; +pub use inputdata::{decode_inputdata, encode_inputdata}; pub use deploy::deploy_template; pub use error::JsonError; pub use receipt::decode_receipt; diff --git a/crates/codec/src/api/json/spawn.rs b/crates/codec/src/api/json/spawn.rs index de94b1eaf..f57dcd94a 100644 --- a/crates/codec/src/api/json/spawn.rs +++ b/crates/codec/src/api/json/spawn.rs @@ -6,7 +6,7 @@ use std::io::Cursor; use svm_types::{Account, SpawnAccount}; use super::call::EncodedOrDecodedCalldata; -use super::calldata::DecodedCallData; +use super::inputdata::DecodedInputData; use super::serde_types::{EncodedData, TemplateAddrWrapper}; use super::{JsonError, JsonSerdeUtils}; use crate::spawn; @@ -56,7 +56,7 @@ impl JsonSerdeUtils for DecodedSpawn {} impl From for DecodedSpawn { fn from(spawn: SpawnAccount) -> Self { let template_addr = TemplateAddrWrapper(spawn.template_addr().clone()); - let decoded_calldata = super::calldata::decode_raw_input(&spawn.calldata).unwrap(); + let decoded_calldata = super::inputdata::decode_raw_input(&spawn.calldata).unwrap(); Self { version: spawn.version, @@ -64,7 +64,7 @@ impl From for DecodedSpawn { template_addr, ctor_name: spawn.ctor_name, calldata: EncodedOrDecodedCalldata::Decoded( - DecodedCallData::new(&decoded_calldata.to_string()) + DecodedInputData::new(&decoded_calldata.to_string()) .expect("Invalid JSON immediately after serialization"), ), } @@ -177,7 +177,7 @@ mod tests { #[test] fn json_spawn_valid() { - let calldata = json::encode_calldata( + let calldata = json::encode_inputdata( &json!({ "abi": ["i32", "i64"], "data": [10, 20] diff --git a/crates/codec/src/api/wasm/call.rs b/crates/codec/src/api/wasm/call.rs index e66d3fd91..06d89eab4 100644 --- a/crates/codec/src/api/wasm/call.rs +++ b/crates/codec/src/api/wasm/call.rs @@ -38,7 +38,7 @@ mod test { fn wasm_call_valid() { let target = "1122334455667788990011223344556677889900"; - let verifydata = api::json::encode_calldata( + let verifydata = api::json::encode_inputdata( &json!({ "abi": ["bool", "i8"], "data": [true, 3] @@ -47,7 +47,7 @@ mod test { ) .unwrap(); - let calldata = api::json::encode_calldata( + let calldata = api::json::encode_inputdata( &json!({ "abi": ["i32", "i64"], "data": [10, 20] diff --git a/crates/codec/src/api/wasm/calldata.rs b/crates/codec/src/api/wasm/inputdata.rs similarity index 68% rename from crates/codec/src/api/wasm/calldata.rs rename to crates/codec/src/api/wasm/inputdata.rs index 81f94d389..a45aa10c2 100644 --- a/crates/codec/src/api/wasm/calldata.rs +++ b/crates/codec/src/api/wasm/inputdata.rs @@ -1,22 +1,21 @@ use super::wasm_buf_apply; use crate::{api, api::json::JsonError}; -/// Given an offset to a Wasm buffer holding the data to be encoded -/// to a binary `Calldata`, encodes it and returns an offset to the encoded -/// binary `Calldata` (wrapped within a JSON). -pub fn encode_calldata(offset: usize) -> Result { +/// Given an offset to a Wasm buffer holding the data to be encoded, +/// encodes it and returns an offset to the encoded binary `Input Data` (wrapped within a JSON). +pub fn encode_inputdata(offset: usize) -> Result { wasm_buf_apply(offset, |json: &str| { - let json = api::json::encode_calldata(json)?; + let json = api::json::encode_inputdata(json)?; Ok(api::json::to_bytes(&json)) }) } -/// Given an offset to a Wasm buffer holding a binary `Calldata`, -/// decodes it and returns an offset to be decoded `Calldata` (wrapped within a JSON) -pub fn decode_calldata(offset: usize) -> Result { +/// Given an offset to a Wasm buffer holding a binary `Input Data`, +/// decodes it and returns an offset to be decoded `Input Data` (wrapped within a JSON) +pub fn decode_inputdata(offset: usize) -> Result { wasm_buf_apply(offset, |json: &str| { - let json = api::json::decode_calldata(json)?; + let json = api::json::decode_inputdata(json)?; Ok(api::json::to_bytes(&json)) }) @@ -43,7 +42,7 @@ mod test { } #[test] - fn wasm_encode_calldata_valid() { + fn wasm_encode_inputdata_valid() { let json = r#"{ "abi": ["i32", "address"], "data": [10, "102030405060708090A011121314151617181920"] @@ -51,13 +50,13 @@ mod test { // encode let json_buf = to_wasm_buffer(json.as_bytes()); - let calldata = encode_calldata(json_buf).unwrap(); - let data = wasm_buffer_data(calldata); + let inputdata = encode_inputdata(json_buf).unwrap(); + let data = wasm_buffer_data(inputdata); assert_eq!(data[0], BUF_OK_MARKER); // decode let data_buf = to_wasm_buffer(&data[1..]); - let res_buf = decode_calldata(data_buf).unwrap(); + let res_buf = decode_inputdata(data_buf).unwrap(); assert_eq!( wasm_buf_as_json(res_buf), @@ -68,17 +67,17 @@ mod test { ); free(json_buf); - free(calldata); + free(inputdata); free(data_buf); free(res_buf); } #[test] - fn wasm_encode_calldata_invalid_json() { + fn wasm_encode_inputdata_invalid_json() { let json = "{"; let json_buf = to_wasm_buffer(json.as_bytes()); - let error_buf = encode_calldata(json_buf).unwrap(); + let error_buf = encode_inputdata(json_buf).unwrap(); let error = unsafe { error_as_string(error_buf) }; @@ -89,11 +88,11 @@ mod test { } #[test] - fn wasm_decode_calldata_invalid_json() { + fn wasm_decode_inputdata_invalid_json() { let json = "{"; let json_buf = to_wasm_buffer(json.as_bytes()); - let error_buf = decode_calldata(json_buf).unwrap(); + let error_buf = decode_inputdata(json_buf).unwrap(); let error = unsafe { error_as_string(error_buf) }; diff --git a/crates/codec/src/api/wasm/mod.rs b/crates/codec/src/api/wasm/mod.rs index fd8d002d4..9a1cd8697 100644 --- a/crates/codec/src/api/wasm/mod.rs +++ b/crates/codec/src/api/wasm/mod.rs @@ -1,14 +1,14 @@ //! WASM API mod call; -mod calldata; +mod inputdata; mod deploy; mod error; mod receipt; mod spawn; pub use call::{decode_call, encode_call}; -pub use calldata::{decode_calldata, encode_calldata}; +pub use inputdata::{decode_inputdata, encode_inputdata}; pub use deploy::encode_deploy; pub use error::{error_as_string, into_error_buffer}; pub use receipt::decode_receipt; diff --git a/crates/codec/src/api/wasm/spawn.rs b/crates/codec/src/api/wasm/spawn.rs index 6f7e4dc12..0def7a515 100644 --- a/crates/codec/src/api/wasm/spawn.rs +++ b/crates/codec/src/api/wasm/spawn.rs @@ -36,7 +36,7 @@ mod test { fn wasm_spawn_valid() { let template_addr = "1122334455667788990011223344556677889900"; - let calldata = json::encode_calldata( + let calldata = json::encode_inputdata( &json!({ "abi": ["i32", "i64"], "data": [10, 20] diff --git a/crates/codec/src/call.rs b/crates/codec/src/call.rs index a385de5cd..d4834e19c 100644 --- a/crates/codec/src/call.rs +++ b/crates/codec/src/call.rs @@ -20,7 +20,7 @@ use svm_types::{Address, Transaction}; use std::io::Cursor; -use crate::{calldata, version}; +use crate::{inputdata, version}; use crate::{Field, ParseError, ReadExt, WriteExt}; /// Encodes a binary [`Transaction`] @@ -40,8 +40,8 @@ pub fn decode_call(cursor: &mut Cursor<&[u8]>) -> Result) { fn encode_verifydata(tx: &Transaction, w: &mut Vec) { let verifydata = tx.verifydata(); - calldata::encode_calldata(verifydata, w) + inputdata::encode_inputdata(verifydata, w) } fn encode_calldata(tx: &Transaction, w: &mut Vec) { let calldata = tx.calldata(); - calldata::encode_calldata(calldata, w) + inputdata::encode_inputdata(calldata, w) } /// Decoders diff --git a/crates/codec/src/calldata.rs b/crates/codec/src/calldata.rs deleted file mode 100644 index 17aa9b014..000000000 --- a/crates/codec/src/calldata.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::io::Cursor; - -use crate::{Field, ParseError, ReadExt, WriteExt}; - -pub fn encode_calldata(calldata: &[u8], w: &mut Vec) { - let length = calldata.len(); - - assert!(length <= std::u8::MAX as usize); - - w.write_byte(length as u8); - w.write_bytes(calldata); -} - -pub fn decode_calldata<'a>(cursor: &mut Cursor<&[u8]>) -> Result, ParseError> { - match cursor.read_byte() { - Err(..) => Err(ParseError::NotEnoughBytes(Field::CallDataLength)), - Ok(byte) => { - let length = byte as usize; - - cursor - .read_bytes(length) - .map_err(|_| ParseError::NotEnoughBytes(Field::CallData)) - } - } -} diff --git a/crates/codec/src/field.rs b/crates/codec/src/field.rs index 469c853d8..b320c0d41 100644 --- a/crates/codec/src/field.rs +++ b/crates/codec/src/field.rs @@ -28,8 +28,8 @@ pub enum Field { Address, TemplateAddr, TargetAddr, - CallDataLength, - CallData, + InputDataLength, + InputData, LayoutKind, LayoutCount, LayoutFirstVarId, diff --git a/crates/codec/src/inputdata.rs b/crates/codec/src/inputdata.rs new file mode 100644 index 000000000..466e7b830 --- /dev/null +++ b/crates/codec/src/inputdata.rs @@ -0,0 +1,25 @@ +use std::io::Cursor; + +use crate::{Field, ParseError, ReadExt, WriteExt}; + +pub fn encode_inputdata(data: &[u8], w: &mut Vec) { + let length = data.len(); + + assert!(length <= std::u8::MAX as usize); + + w.write_byte(length as u8); + w.write_bytes(data); +} + +pub fn decode_inputdata<'a>(cursor: &mut Cursor<&[u8]>) -> Result, ParseError> { + match cursor.read_byte() { + Err(..) => Err(ParseError::NotEnoughBytes(Field::InputDataLength)), + Ok(byte) => { + let length = byte as usize; + + cursor + .read_bytes(length) + .map_err(|_| ParseError::NotEnoughBytes(Field::InputData)) + } + } +} diff --git a/crates/codec/src/lib.rs b/crates/codec/src/lib.rs index 3d47e9021..e6a390c13 100644 --- a/crates/codec/src/lib.rs +++ b/crates/codec/src/lib.rs @@ -12,9 +12,9 @@ #![allow(unreachable_code)] #![feature(vec_into_raw_parts)] -mod calldata; mod ext; mod field; +mod inputdata; mod section; mod version; @@ -60,7 +60,8 @@ pub use error::ParseError; /// /// /// WASM Buffer `Data` for Success result: -/// ``` +/// +/// ```text /// +------------------------------------------------+ /// | OK_MAKER = 1 (1 byte) | SVM binary transaction | /// +------------------------------------------------+ @@ -68,7 +69,8 @@ pub use error::ParseError; /// /// /// WASM Buffer `Data` for Error result: -/// ``` +// +/// ```text /// +------------------------------------------------+ /// | ERR_MAKER = 0 (1 byte) | UTF-8 String (error) | /// +------------------------------------------------+ @@ -194,25 +196,25 @@ pub extern "C" fn wasm_buffer_data(offset: i32) -> i32 { data_offset as _ } -/// ## Calldata +/// ## Input Data (i.e `CallData/VerifyData`) /// /// Reads the WASM buffer given at parameter `offset` containing a JSON value. -/// Encodes the `Calldata, and returns a pointer to a new WASM buffer holding the encoded `Calldata`. +/// Encodes the `Input Data`, and returns a pointer to a new WASM buffer holding the encoded `Input Data`. /// If the encoding fails, the returned WASM buffer will contain a String containing the error message. #[no_mangle] #[cfg(target_arch = "wasm32")] -pub extern "C" fn wasm_encode_calldata(offset: i32) -> i32 { - wasm_func_call!(encode_calldata, offset) +pub extern "C" fn wasm_encode_inputdata(offset: i32) -> i32 { + wasm_func_call!(encode_inputdata, offset) } -/// Decodes the encoded `Calldata` given as a WASM buffer (parameter `offset`). +/// Decodes the encoded `Input Data` given as a WASM buffer (parameter `offset`). /// -/// Returns a pointer to a new WASM buffer holding the decoded `Calldata`. +/// Returns a pointer to a new WASM buffer holding the decoded `Input Data`. /// If the decoding fails, the returned WASM buffer will contain a String containing the error message. #[no_mangle] #[cfg(target_arch = "wasm32")] -pub extern "C" fn wasm_decode_calldata(offset: i32) -> i32 { - wasm_func_call!(decode_calldata, offset) +pub extern "C" fn wasm_decode_inputdata(offset: i32) -> i32 { + wasm_func_call!(decode_inputdata, offset) } /// Decodes the encoded `Receipt` given as a WASM buffer (parameter `offset`). diff --git a/crates/codec/src/spawn.rs b/crates/codec/src/spawn.rs index 94a0cd0b8..e21b061f1 100644 --- a/crates/codec/src/spawn.rs +++ b/crates/codec/src/spawn.rs @@ -20,7 +20,7 @@ use std::io::Cursor; use svm_types::{Account, SpawnAccount, TemplateAddr}; -use crate::{calldata, version}; +use crate::{inputdata, version}; use crate::{Field, ParseError, ReadExt, WriteExt}; /// Encodes a binary [`SpawnAccount`] transaction. @@ -82,7 +82,7 @@ fn encode_ctor(spawn: &SpawnAccount, w: &mut Vec) { fn encode_ctor_calldata(spawn: &SpawnAccount, w: &mut Vec) { let calldata = &*spawn.calldata; - calldata::encode_calldata(calldata, w); + inputdata::encode_inputdata(calldata, w); } /// Decoders @@ -115,7 +115,7 @@ fn decode_ctor(cursor: &mut Cursor<&[u8]>) -> Result { } fn decode_ctor_calldata(cursor: &mut Cursor<&[u8]>) -> Result, ParseError> { - calldata::decode_calldata(cursor) + inputdata::decode_inputdata(cursor) } #[cfg(test)] diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 1ee9a2bd2..96b009016 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -338,7 +338,7 @@ compile_error!("Cannot have both `static-alloc` and `dynamic-alloc` features tur compile_error!("Must have either `static-alloc` or `dynamic-alloc` features turned-on"); /// Logging API -pub use svm_abi_decoder::{CallData, DecodeError, ReturnData}; +pub use svm_abi_decoder::{InputData, DecodeError, ReturnData}; pub use svm_sdk_macros::template; pub use svm_sdk_std::{ensure, log}; From 5cd27ba0593bc448ec7f168552e22d116937f091 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Wed, 4 Aug 2021 17:45:36 +0300 Subject: [PATCH 06/13] Code compiles again... --- crates/abi/tests/src/lib.rs | 16 ++++++++-------- crates/codec/src/api/json/inputdata.rs | 4 ++-- crates/sdk/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/abi/tests/src/lib.rs b/crates/abi/tests/src/lib.rs index b6232fc8f..f833d7b93 100644 --- a/crates/abi/tests/src/lib.rs +++ b/crates/abi/tests/src/lib.rs @@ -8,7 +8,7 @@ #[cfg(test)] mod tests { - use svm_abi_decoder::InputData; + use svm_abi_decoder::CallData; use svm_abi_encoder::Encoder; use svm_sdk_std::{Option, Vec}; @@ -294,7 +294,7 @@ mod tests { let mut buf = Vec::with_capacity(1000); a.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let a_ = calldata.next().unwrap().into(); assert_eq!(a, a_); @@ -307,7 +307,7 @@ mod tests { let mut buf = Vec::with_capacity(1000); a.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let a_ = calldata.next_1(); assert_eq!(a, a_); @@ -323,7 +323,7 @@ mod tests { a.encode(&mut buf); b.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let (a_, b_) = calldata.next_2(); assert_eq!(a, a_); @@ -342,7 +342,7 @@ mod tests { b.encode(&mut buf); c.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let (a_, b_, c_) = calldata.next_3(); assert_eq!(a, a_); @@ -364,7 +364,7 @@ mod tests { c.encode(&mut buf); d.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let (a_, b_, c_, d_): (u32, i16, bool, [u8; 2]) = calldata.next_4(); assert_eq!(a, a_); @@ -389,7 +389,7 @@ mod tests { d.encode(&mut buf); e.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let (a_, b_, c_, d_, e_): (u32, i16, bool, [u8; 2], [u16; 3]) = calldata.next_5(); assert_eq!(a, a_); @@ -417,7 +417,7 @@ mod tests { e.encode(&mut buf); f.encode(&mut buf); - let mut calldata = InputData::new(as_static!(buf)); + let mut calldata = CallData::new(as_static!(buf)); let (a_, b_, c_, d_, e_, f_): (u32, i16, bool, [u8; 2], [u16; 3], Amount) = calldata.next_6(); diff --git a/crates/codec/src/api/json/inputdata.rs b/crates/codec/src/api/json/inputdata.rs index 074a4545d..f22653ada 100644 --- a/crates/codec/src/api/json/inputdata.rs +++ b/crates/codec/src/api/json/inputdata.rs @@ -326,8 +326,8 @@ mod tests { ($abi:expr, $data:expr) => {{ let json = json!({"abi": $abi, "data": $data }); - let encoded = encode_calldata(&json.to_string()).unwrap(); - let decoded = decode_calldata(&encoded.to_string()).unwrap(); + let encoded = encode_inputdata(&json.to_string()).unwrap(); + let decoded = decode_inputdata(&encoded.to_string()).unwrap(); assert_eq!(decoded, json); }} diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 96b009016..1ee9a2bd2 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -338,7 +338,7 @@ compile_error!("Cannot have both `static-alloc` and `dynamic-alloc` features tur compile_error!("Must have either `static-alloc` or `dynamic-alloc` features turned-on"); /// Logging API -pub use svm_abi_decoder::{InputData, DecodeError, ReturnData}; +pub use svm_abi_decoder::{CallData, DecodeError, ReturnData}; pub use svm_sdk_macros::template; pub use svm_sdk_std::{ensure, log}; From d532171e5d822065232817e6c0264f45d6ac3307 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Wed, 4 Aug 2021 17:57:22 +0300 Subject: [PATCH 07/13] cargo fmt --- crates/codec/src/api/json/mod.rs | 4 ++-- crates/codec/src/api/wasm/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/codec/src/api/json/mod.rs b/crates/codec/src/api/json/mod.rs index f44626d2b..52874b725 100644 --- a/crates/codec/src/api/json/mod.rs +++ b/crates/codec/src/api/json/mod.rs @@ -1,18 +1,18 @@ //! JSON API mod call; -mod inputdata; mod deploy; mod error; +mod inputdata; mod receipt; mod spawn; pub(crate) mod serde_types; pub use call::{decode_call, encode_call, encode_call_raw}; -pub use inputdata::{decode_inputdata, encode_inputdata}; pub use deploy::deploy_template; pub use error::JsonError; +pub use inputdata::{decode_inputdata, encode_inputdata}; pub use receipt::decode_receipt; pub use spawn::{decode_spawn, encode_spawn}; diff --git a/crates/codec/src/api/wasm/mod.rs b/crates/codec/src/api/wasm/mod.rs index 9a1cd8697..505750ff7 100644 --- a/crates/codec/src/api/wasm/mod.rs +++ b/crates/codec/src/api/wasm/mod.rs @@ -1,16 +1,16 @@ //! WASM API mod call; -mod inputdata; mod deploy; mod error; +mod inputdata; mod receipt; mod spawn; pub use call::{decode_call, encode_call}; -pub use inputdata::{decode_inputdata, encode_inputdata}; pub use deploy::encode_deploy; pub use error::{error_as_string, into_error_buffer}; +pub use inputdata::{decode_inputdata, encode_inputdata}; pub use receipt::decode_receipt; pub use spawn::{decode_spawn, encode_spawn}; From d342f5e075429b2ffe83f396dbb8126f30be57f5 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Fri, 6 Aug 2021 15:35:17 +0300 Subject: [PATCH 08/13] `svm-program`: Validating `svm_verify` --- crates/codec/src/api/json/call.rs | 7 +- crates/program/src/error.rs | 16 +++- crates/program/src/lib.rs | 8 +- crates/program/src/program.rs | 130 +++++++++++++++++++++++------- 4 files changed, 119 insertions(+), 42 deletions(-) diff --git a/crates/codec/src/api/json/call.rs b/crates/codec/src/api/json/call.rs index 3091e60bd..22ea128f2 100644 --- a/crates/codec/src/api/json/call.rs +++ b/crates/codec/src/api/json/call.rs @@ -59,11 +59,8 @@ pub fn encode_call_raw(json: &str) -> Result, JsonError> { /// ``` pub fn decode_call(json: &str) -> Result { let encoded_call = EncodedData::from_json_str(json)?; - let tx = { - let mut cursor = Cursor::new(&encoded_call.data.0[..]); - - crate::call::decode_call(&mut cursor).unwrap() - }; + let mut cursor = Cursor::new(&encoded_call.data.0[..]); + let tx = crate::call::decode_call(&mut cursor).unwrap(); Ok(DecodedCall::from(tx).to_json()) } diff --git a/crates/program/src/error.rs b/crates/program/src/error.rs index 51aebf795..8545beb50 100644 --- a/crates/program/src/error.rs +++ b/crates/program/src/error.rs @@ -7,19 +7,27 @@ use std::fmt; pub enum ProgramError { /// Invalid wasm InvalidWasm, + /// No valid `svm_alloc` function found. - FunctionNotFound { - /// The name of the WebAssembly function that wasn't found. - func_name: String, - }, + FunctionNotFound(String), + /// Floats not allowed FloatsNotAllowed, + /// Too many function imports TooManyFunctionImports, + /// Function index is too large FunctionIndexTooLarge, + /// Wasm has no `code` section MissingCodeSection, + + /// Invalid Export Kind + InvalidExportKind, + + /// Invalid Export Function Signature + InvalidExportFunctionSignature, } impl fmt::Display for ProgramError { diff --git a/crates/program/src/lib.rs b/crates/program/src/lib.rs index 245523550..5a955fe12 100644 --- a/crates/program/src/lib.rs +++ b/crates/program/src/lib.rs @@ -2,10 +2,10 @@ //! //! The main entity in this crate is [`Program`]. -#![deny(missing_docs)] -#![deny(unused)] -#![deny(dead_code)] -#![deny(unreachable_code)] +#![allow(missing_docs)] +#![allow(unused)] +#![allow(dead_code)] +#![allow(unreachable_code)] use parity_wasm::elements::Instruction; diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index b215807e0..b22a2b15d 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -1,5 +1,6 @@ use indexmap::IndexMap; -use parity_wasm::elements::{CodeSection, Module}; + +use parity_wasm::elements::{self as pwasm, ValueType}; use crate::{ validate_no_floats, Exports, FuncIndex, Function, Imports, Instruction, ProgramError, @@ -124,13 +125,13 @@ impl Program { } } -fn read_module(wasm: &[u8]) -> Result { +fn read_module(wasm: &[u8]) -> Result { let module = parity_wasm::deserialize_buffer(wasm); module.map_err(|_| ProgramError::InvalidWasm) } -fn read_code(module: &Module) -> Result { +fn read_code(module: &pwasm::Module) -> Result { match module.code_section() { Some(code) => Ok(code.clone()), None => Err(ProgramError::MissingCodeSection), @@ -162,53 +163,124 @@ fn count_functions_in_program(program: &Program) -> u64 { Counter::default().visit(program).unwrap() } -/// Checks whether `wasm_module` exports a well-defined `svm_alloc` function. -/// `svm_alloc` is required by SVM for all WASM code and must have a `I32 -> -/// I32` type signature. -fn module_validate_exports(wasm_module: &Module) -> Result<(), ProgramError> { - use parity_wasm::elements::{ExportSection, FunctionSection, Type, TypeSection, ValueType}; +/// Checks whether `wasm_module` exports a well-defined `svm_alloc` and `svm_verify` functions. +/// Both are required by SVM to exist in each `Template`. + +/// * `svm_alloc` must have a `I32 -> I32` type signature. +/// - The input param is for the amount of bytes to allocate. +/// - The output is the `offset` pointing to the allocated memory first cell. +/// +/// * `svm_verify` must have a `() -> I32` type signature. +/// - The input is `()` since it is passed using the `Verify Data` mechanism. +/// - The output is the `offset` pointing to the `returndata` first cell. +/// +fn module_validate_exports(wasm_module: &pwasm::Module) -> Result<(), ProgramError> { + use pwasm::{ExportSection, FunctionSection, TypeSection}; - let empty_export_section = ExportSection::with_entries(vec![]); let empty_function_sig_section = FunctionSection::with_entries(vec![]); let empty_type_section = TypeSection::with_types(vec![]); + let empty_export_section = ExportSection::with_entries(vec![]); let module_functions = wasm_module .function_section() .unwrap_or(&empty_function_sig_section) .entries(); + let module_types = wasm_module .type_section() .unwrap_or(&empty_type_section) .types(); + let module_exports = wasm_module .export_section() .unwrap_or(&empty_export_section) .entries(); + let mut seen_alloc = false; + let mut seen_verify = false; + for entry in module_exports.iter() { - if entry.field() != "svm_alloc" { - continue; + match entry.field() { + "svm_alloc" => { + seen_alloc = true; + validate_export_alloc(entry, module_functions, module_types)?; + } + "svm_verify" => { + svm_verify_validate(entry, &module_functions, &module_types)?; + } + _ => (), } + } - let type_signature = { - let function = if let parity_wasm::elements::Internal::Function(i) = entry.internal() { - module_functions[*i as usize] - } else { - // We don't care about anything but functions right now. - continue; - }; - &module_types[function.type_ref() as usize] - }; - - #[allow(irrefutable_let_patterns)] - if let Type::Function(f) = type_signature { - if f.params() == &[ValueType::I32] && f.results() == &[ValueType::I32] { - return Ok(()); - } + if !seen_alloc { + return Err(ProgramError::FunctionNotFound("svm_alloc".to_string())); + } + + if !seen_verify { + return Err(ProgramError::FunctionNotFound("svm_verify".to_string())); + } + + Ok(()) +} + +fn validate_export_alloc( + entry: &pwasm::ExportEntry, + module_funcs: &[pwasm::Func], + module_types: &[pwasm::Type], +) -> Result<(), ProgramError> { + use pwasm::ValueType; + + validate_func_signature( + entry, + module_funcs, + module_types, + &[ValueType::I32], + &[ValueType::I32], + ) +} + +fn svm_verify_validate( + entry: &pwasm::ExportEntry, + module_funcs: &[pwasm::Func], + module_types: &[pwasm::Type], +) -> Result<(), ProgramError> { + use pwasm::ValueType; + + validate_func_signature(entry, module_funcs, module_types, &[], &[ValueType::I32]) +} + +fn validate_func_signature( + entry: &pwasm::ExportEntry, + module_funcs: &[pwasm::Func], + module_types: &[pwasm::Type], + expected_params: &[pwasm::ValueType], + expected_rets: &[pwasm::ValueType], +) -> Result<(), ProgramError> { + let sig = export_func_signature(entry, &module_funcs, &module_types)?; + + #[allow(irrefutable_let_patterns)] + if let pwasm::Type::Function(f) = sig { + if f.params() == expected_params && f.results() == expected_rets { + Ok(()) + } else { + Err(ProgramError::InvalidExportFunctionSignature) } + } else { + unreachable!() } +} - Err(ProgramError::FunctionNotFound { - func_name: "svm_alloc".to_string(), - }) +fn export_func_signature<'p>( + entry: &'p pwasm::ExportEntry, + module_functions: &'p [pwasm::Func], + module_types: &'p [pwasm::Type], +) -> Result<&'p pwasm::Type, ProgramError> { + if let pwasm::Internal::Function(i) = entry.internal() { + let func = &module_functions[*i as usize]; + let sig = &module_types[func.type_ref() as usize]; + + Ok(sig) + } else { + Err(ProgramError::InvalidExportKind) + } } From 1d080b3c193ea3bbc5b3024522038e6e4dfeb62a Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Fri, 6 Aug 2021 15:48:17 +0300 Subject: [PATCH 09/13] svm-program: a bit of refactoring to program.rs --- crates/program/src/program.rs | 45 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index b22a2b15d..31955c2f1 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -1,6 +1,6 @@ use indexmap::IndexMap; -use parity_wasm::elements::{self as pwasm, ValueType}; +use parity_wasm::elements::{self as pwasm, FunctionSection, ValueType}; use crate::{ validate_no_floats, Exports, FuncIndex, Function, Imports, Instruction, ProgramError, @@ -174,27 +174,16 @@ fn count_functions_in_program(program: &Program) -> u64 { /// - The input is `()` since it is passed using the `Verify Data` mechanism. /// - The output is the `offset` pointing to the `returndata` first cell. /// -fn module_validate_exports(wasm_module: &pwasm::Module) -> Result<(), ProgramError> { +fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { use pwasm::{ExportSection, FunctionSection, TypeSection}; - let empty_function_sig_section = FunctionSection::with_entries(vec![]); + let empty_function_section = FunctionSection::with_entries(vec![]); let empty_type_section = TypeSection::with_types(vec![]); let empty_export_section = ExportSection::with_entries(vec![]); - let module_functions = wasm_module - .function_section() - .unwrap_or(&empty_function_sig_section) - .entries(); - - let module_types = wasm_module - .type_section() - .unwrap_or(&empty_type_section) - .types(); - - let module_exports = wasm_module - .export_section() - .unwrap_or(&empty_export_section) - .entries(); + let module_functions = module_functions(module, &empty_function_section); + let module_types = module_types(module, &empty_type_section); + let module_exports = module_exports(module, &empty_export_section); let mut seen_alloc = false; let mut seen_verify = false; @@ -206,6 +195,7 @@ fn module_validate_exports(wasm_module: &pwasm::Module) -> Result<(), ProgramErr validate_export_alloc(entry, module_functions, module_types)?; } "svm_verify" => { + seen_verify = true; svm_verify_validate(entry, &module_functions, &module_types)?; } _ => (), @@ -284,3 +274,24 @@ fn export_func_signature<'p>( Err(ProgramError::InvalidExportKind) } } + +fn module_functions<'p>( + module: &'p pwasm::Module, + default: &'p pwasm::FunctionSection, +) -> &'p [pwasm::Func] { + module.function_section().unwrap_or(default).entries() +} + +fn module_types<'p>( + module: &'p pwasm::Module, + default: &'p pwasm::TypeSection, +) -> &'p [pwasm::Type] { + module.type_section().unwrap_or(default).types() +} + +fn module_exports<'p>( + module: &'p pwasm::Module, + default: &'p pwasm::ExportSection, +) -> &'p [pwasm::ExportEntry] { + module.export_section().unwrap_or(default).entries() +} From b745cab20735f3812a9d9d3f5f9fc6189464ea38 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Fri, 6 Aug 2021 16:27:25 +0300 Subject: [PATCH 10/13] svm-runtime: adding tests for `validate_deploy` (testing `svm_verify` and `svm_alloc`) --- crates/program/src/error.rs | 2 +- crates/program/src/program.rs | 36 ++++++--- crates/runtime/src/error.rs | 2 + crates/runtime/tests/runtime_tests.rs | 78 ++++++++++++++++++- .../runtime/tests/wasm/missing_svm_alloc.wast | 4 + .../tests/wasm/missing_svm_verify.wast | 4 + .../tests/wasm/svm_alloc_invalid_sig.wast | 11 +++ .../tests/wasm/svm_verify_invalid_sig.wast | 11 +++ 8 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 crates/runtime/tests/wasm/missing_svm_alloc.wast create mode 100644 crates/runtime/tests/wasm/missing_svm_verify.wast create mode 100644 crates/runtime/tests/wasm/svm_alloc_invalid_sig.wast create mode 100644 crates/runtime/tests/wasm/svm_verify_invalid_sig.wast diff --git a/crates/program/src/error.rs b/crates/program/src/error.rs index 8545beb50..70a4bbcd7 100644 --- a/crates/program/src/error.rs +++ b/crates/program/src/error.rs @@ -27,7 +27,7 @@ pub enum ProgramError { InvalidExportKind, /// Invalid Export Function Signature - InvalidExportFunctionSignature, + InvalidExportFunctionSignature(String), } impl fmt::Display for ProgramError { diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index 31955c2f1..7a5caa688 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -34,7 +34,7 @@ pub struct Program { } impl Program { - /// Reads a Wasm program and constructs a `Program` struct + /// Reads a Wasm program and constructs a [`Program`] struct pub fn new(wasm_module: &[u8], validate_exports: bool) -> Result { let module = read_module(wasm_module)?; @@ -188,15 +188,15 @@ fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { let mut seen_alloc = false; let mut seen_verify = false; - for entry in module_exports.iter() { - match entry.field() { + for export in module_exports.iter() { + match export.field() { "svm_alloc" => { seen_alloc = true; - validate_export_alloc(entry, module_functions, module_types)?; + validate_export_alloc(export, module_functions, module_types)?; } "svm_verify" => { seen_verify = true; - svm_verify_validate(entry, &module_functions, &module_types)?; + svm_verify_validate(export, &module_functions, &module_types)?; } _ => (), } @@ -214,14 +214,15 @@ fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { } fn validate_export_alloc( - entry: &pwasm::ExportEntry, + export: &pwasm::ExportEntry, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], ) -> Result<(), ProgramError> { use pwasm::ValueType; validate_func_signature( - entry, + "svm_alloc", + export, module_funcs, module_types, &[ValueType::I32], @@ -230,30 +231,40 @@ fn validate_export_alloc( } fn svm_verify_validate( - entry: &pwasm::ExportEntry, + export: &pwasm::ExportEntry, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], ) -> Result<(), ProgramError> { use pwasm::ValueType; - validate_func_signature(entry, module_funcs, module_types, &[], &[ValueType::I32]) + validate_func_signature( + "svm_verify", + export, + module_funcs, + module_types, + &[], + &[ValueType::I32], + ) } fn validate_func_signature( - entry: &pwasm::ExportEntry, + func_name: &str, + export: &pwasm::ExportEntry, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], expected_params: &[pwasm::ValueType], expected_rets: &[pwasm::ValueType], ) -> Result<(), ProgramError> { - let sig = export_func_signature(entry, &module_funcs, &module_types)?; + let sig = export_func_signature(func_name, export, &module_funcs, &module_types)?; #[allow(irrefutable_let_patterns)] if let pwasm::Type::Function(f) = sig { if f.params() == expected_params && f.results() == expected_rets { Ok(()) } else { - Err(ProgramError::InvalidExportFunctionSignature) + Err(ProgramError::InvalidExportFunctionSignature( + func_name.to_string(), + )) } } else { unreachable!() @@ -261,6 +272,7 @@ fn validate_func_signature( } fn export_func_signature<'p>( + func_name: &str, entry: &'p pwasm::ExportEntry, module_functions: &'p [pwasm::Func], module_types: &'p [pwasm::Type], diff --git a/crates/runtime/src/error.rs b/crates/runtime/src/error.rs index 7fb0817de..c05cb4ed9 100644 --- a/crates/runtime/src/error.rs +++ b/crates/runtime/src/error.rs @@ -10,10 +10,12 @@ pub enum ValidateError { /// An unexpected condition was found when decoding from the SVM ABI. #[error("{0}")] Parse(#[from] ParseError), + /// The given smWasm is invalid or it uses specific features which are not /// allowed by SVM. #[error("{0}")] Program(#[from] ProgramError), + /// The given smWasm code is valid, but it doesn't pass the requirements to /// run in fixed-gas mode. #[error("{0}")] diff --git a/crates/runtime/tests/runtime_tests.rs b/crates/runtime/tests/runtime_tests.rs index c1b1c57f4..ce77eed7f 100644 --- a/crates/runtime/tests/runtime_tests.rs +++ b/crates/runtime/tests/runtime_tests.rs @@ -24,7 +24,83 @@ fn memory_runtime_validate_deploy_not_enough_bytes() { } #[test] -fn memory_runtime_validate_deploy_invalid_wasm() { +fn memory_runtime_validate_deploy_missing_svm_verify_export() { + let runtime = testing::create_memory_runtime(); + + let message = testing::build_deploy( + 0, + "My Template", + FixedLayout::default(), + &[], + include_str!("wasm/missing_svm_verify.wast").into(), + ); + + let error = ProgramError::FunctionNotFound("svm_verify".to_string()); + let expected = Err(ValidateError::Program(error)); + + let actual = runtime.validate_deploy(&message); + assert_eq!(expected, actual); +} + +#[test] +fn memory_runtime_validate_deploy_missing_svm_alloc_export() { + let runtime = testing::create_memory_runtime(); + + let message = testing::build_deploy( + 0, + "My Template", + FixedLayout::default(), + &[], + include_str!("wasm/missing_svm_alloc.wast").into(), + ); + + let error = ProgramError::FunctionNotFound("svm_alloc".to_string()); + let expected = Err(ValidateError::Program(error)); + + let actual = runtime.validate_deploy(&message); + assert_eq!(expected, actual); +} + +#[test] +fn memory_runtime_validate_deploy_svm_alloc_export_invalid_signature() { + let runtime = testing::create_memory_runtime(); + + let message = testing::build_deploy( + 0, + "My Template", + FixedLayout::default(), + &[], + include_str!("wasm/svm_alloc_invalid_sig.wast").into(), + ); + + let error = ProgramError::InvalidExportFunctionSignature("svm_alloc".to_string()); + let expected = Err(ValidateError::Program(error)); + + let actual = runtime.validate_deploy(&message); + assert_eq!(expected, actual); +} + +#[test] +fn memory_runtime_validate_deploy_svm_verify_export_invalid_signature() { + let runtime = testing::create_memory_runtime(); + + let message = testing::build_deploy( + 0, + "My Template", + FixedLayout::default(), + &[], + include_str!("wasm/svm_verify_invalid_sig.wast").into(), + ); + + let error = ProgramError::InvalidExportFunctionSignature("svm_verify".to_string()); + let expected = Err(ValidateError::Program(error)); + + let actual = runtime.validate_deploy(&message); + assert_eq!(expected, actual); +} + +#[test] +fn memory_runtime_validate_deploy_floats_not_allowed() { let runtime = testing::create_memory_runtime(); // An invalid Wasm (has floats) diff --git a/crates/runtime/tests/wasm/missing_svm_alloc.wast b/crates/runtime/tests/wasm/missing_svm_alloc.wast new file mode 100644 index 000000000..151695482 --- /dev/null +++ b/crates/runtime/tests/wasm/missing_svm_alloc.wast @@ -0,0 +1,4 @@ +(module + (export "svm_verify" (func $svm_verify)) + (func $svm_verify (result i32) + (i32.const 0))) \ No newline at end of file diff --git a/crates/runtime/tests/wasm/missing_svm_verify.wast b/crates/runtime/tests/wasm/missing_svm_verify.wast new file mode 100644 index 000000000..961ded034 --- /dev/null +++ b/crates/runtime/tests/wasm/missing_svm_verify.wast @@ -0,0 +1,4 @@ +(module + (export "svm_alloc" (func $svm_alloc)) + (func $svm_alloc (param i32) (result i32) + (i32.const 0))) \ No newline at end of file diff --git a/crates/runtime/tests/wasm/svm_alloc_invalid_sig.wast b/crates/runtime/tests/wasm/svm_alloc_invalid_sig.wast new file mode 100644 index 000000000..1ca0dddc7 --- /dev/null +++ b/crates/runtime/tests/wasm/svm_alloc_invalid_sig.wast @@ -0,0 +1,11 @@ +(module + (export "svm_alloc" (func $svm_alloc)) + (export "svm_verify" (func $svm_verify)) + + ;; Valid `svm_verify` signature + (func $svm_verify (result i32) + (i32.const 0)) + + ;; Invalid `svm_alloc` signature + (func $svm_alloc (result i32) + (i32.const 0))) \ No newline at end of file diff --git a/crates/runtime/tests/wasm/svm_verify_invalid_sig.wast b/crates/runtime/tests/wasm/svm_verify_invalid_sig.wast new file mode 100644 index 000000000..845de8859 --- /dev/null +++ b/crates/runtime/tests/wasm/svm_verify_invalid_sig.wast @@ -0,0 +1,11 @@ +(module + (export "svm_alloc" (func $svm_alloc)) + (export "svm_verify" (func $svm_verify)) + + ;; Invalid `svm_verify` signature + (func $svm_verify (param i32) (result i32) + (i32.const 0)) + + ;; Valid `svm_alloc` signature + (func $svm_alloc (param i32) (result i32) + (i32.const 0))) \ No newline at end of file From 954ec5959f133cf83a13a9cb883c190a1bf2138d Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Fri, 6 Aug 2021 17:00:24 +0300 Subject: [PATCH 11/13] SVM SDK emit a stub implementation for the `svm_verify` --- crates/program/src/program.rs | 10 +++--- crates/runtime/tests/runtime_tests.rs | 18 +++++++++++ .../runtime/tests/wasm/runtime_calldata.wasm | Bin 9407 -> 7286 bytes crates/sdk/macros/Cargo.toml | 2 +- crates/sdk/macros/src/template.rs | 30 ++++++++++++++---- crates/sdk/types/Cargo.toml | 2 +- 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index 7a5caa688..e2a65d66e 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -253,15 +253,17 @@ fn validate_func_signature( module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], expected_params: &[pwasm::ValueType], - expected_rets: &[pwasm::ValueType], + expected_results: &[pwasm::ValueType], ) -> Result<(), ProgramError> { - let sig = export_func_signature(func_name, export, &module_funcs, &module_types)?; + let func_sig = export_func_signature(func_name, export, &module_funcs, &module_types)?; #[allow(irrefutable_let_patterns)] - if let pwasm::Type::Function(f) = sig { - if f.params() == expected_params && f.results() == expected_rets { + if let pwasm::Type::Function(f) = func_sig { + if f.params() == expected_params && f.results() == expected_results { Ok(()) } else { + dbg!(f); + Err(ProgramError::InvalidExportFunctionSignature( func_name.to_string(), )) diff --git a/crates/runtime/tests/runtime_tests.rs b/crates/runtime/tests/runtime_tests.rs index ce77eed7f..58ab2162d 100644 --- a/crates/runtime/tests/runtime_tests.rs +++ b/crates/runtime/tests/runtime_tests.rs @@ -119,6 +119,24 @@ fn memory_runtime_validate_deploy_floats_not_allowed() { assert_eq!(expected, actual); } +// #[test] +// fn memory_runtime_validate_deploy_ok() { +// let runtime = testing::create_memory_runtime(); + +// let message = testing::build_deploy( +// 0, +// "My Template", +// FixedLayout::default(), +// &[], +// include_bytes!("wasm/runtime_calldata.wasm")[..].into(), +// ); + +// let result = runtime.validate_deploy(&message); + +// dbg!(result.unwrap_err()); +// // assert!(result.is_ok()); +// } + #[test] fn memory_runtime_validate_spawn_missing_template_addr() { let runtime = testing::create_memory_runtime(); diff --git a/crates/runtime/tests/wasm/runtime_calldata.wasm b/crates/runtime/tests/wasm/runtime_calldata.wasm index d832a946fadf5a86225daa0f2695de9c8c80b0c6..fa46483edaa18885131a566464d84f7b32c6ef5b 100755 GIT binary patch delta 1016 zcma)4O=uHA6rMM`X_M|Qna%DtO`6b6T9ndCTa{W2g`GpIUV4#=f`_69A+3lpdTb&h zBA)C!iK4l9D_ChkL_wZ+CYgl8>Szck0KMS248>HU2yz=P zN;qN>j1Qs*o+Hx_!ebPy29)|-ZPvQ zBu+>-aLPPEe>BXkbX^0zM$?P=A`H+liZ>Gi*Q^OJSGTMzU@}?io&oJ&T?@$q-cFW= zn_U{O!6H{Zb<&Y59eF@=CW_jwSlri0thlIxfmcO9!n78pU#7Z=Uqv45CEJA*X6&)Q zn?|Fib2fs5+x8)Fv6LDC4=_EOxYn8qQepW<<6aJa|k@+B+#d<2fl zcvV70m}DTOL5Y#S%57#k2GMqL%{d7s+HNm#9dmmq&bTBA-g0vkmnrt(TQ?6G{1Ham z%lBm?w7C|vm_eUz(xrZ*hrI9t54I9VVorm#*7CLx#fqRN+@t;2K6)1rg&(!QhY75 zhs4~-?4M?S wG(!YHo7TdJ?=DElh!eo8-YWz!nVZDLTw$~c(USi6KpVN!^gPH*yq>@L2NOEan*aa+ delta 3227 zcmbtVNsJst7R`vNqL-?6S8vAdR*UR%Ghjj68M!AtpiWF;un>d52(T<_A~Pc0)m^S? zva&pQkjNgE1Dk|NvtQTQ%VR03LF|;RzN(2Gys<@kd~7@zP^= zbffRF2$jWWE&*_>+~Zk+;lt~S%-BBv91K9|IkES@f?j=`Te8G>ZwS`uO7Z&q_*n7t z+*&DpnOn{Ad()(}H{H6T)8A>Pca3!Wt54IHMyG~W504G6j*Smi|IWScDu0t($BV1! zRU;_(C zdS7lmGQHn^h3_#U7o-gt9t5|!qp=I3JR5d!5Uj0AOw3&1Qe~#hN|govbo&0RHR=AD zh1x~>ymg|;5@vbB$~eD}74N|r`*2ny0XsSb%e>%_p4oJ;xYZ$tG45bdaJxqJo!n6NpW&1SnMRiEI#?wnYs@6CR-aN)%6$Eeuq|btJ>A&FR+e*^=n%`6qY33yv_5ZE3PBN#%cn zfp+D->|L+~xe^(Ml+~*?qyjM$xx~`uoe_2Lj)~9M5$uJV3zJRd6 z2`tV0PMxfG$Yvcko9zIZVj1JO5#&48x@BO~4;)P=K2j7l^uSI0 zrrNu?-tNR2eK=R5U}ki9v{0xPf0bdeJ*^JHjWZAdpdF8x)xevXb>sXEAkbnwo~40Eb@Dx$I@c z5u0sH#NBm76e}=Pj2v50LW6px8-JR#Ett@_9?`fPwRrA~wnhV#*s8DC0kw4EINlXw z+)|F9OVrPyDd@` z`VVp|{qfR?A4~dV?yTA}}U^zBXRB8ppFm1(~x}`@isSn-$aTk%&uUUt|m=s|x zP(n=Xkm?%orhiY(bS7doOf<(Js)JELycxI0>gPz=f>Wz|l9x(VdkS(vOi#Y$7@BFQ4%HMb2)wy|b$*TqQhF$+&ZsyJo8piX5{9fmDDZag2qhW7 zXextIG>6SfsA)RVG=f6!${oQBP>{(`3?Ca#h>_tFpS?`j+jF^2B|Dios#+#7jKB;G z%AOj_+j}{YTsAxs8R#bie{{hNd-%$Vn diff --git a/crates/sdk/macros/Cargo.toml b/crates/sdk/macros/Cargo.toml index f030c8e34..c0e5077e5 100644 --- a/crates/sdk/macros/Cargo.toml +++ b/crates/sdk/macros/Cargo.toml @@ -31,7 +31,7 @@ lazy_static = "1.4.0" trybuild = { version = "1.0", features = ["diff"] } [features] -refault = ["mock", "dynamic-alloc"] +default = ["mock", "dynamic-alloc"] meta = [] ffi = ["svm-sdk-host/ffi", "svm-sdk-storage/ffi"] mock = ["svm-sdk-host/mock", "svm-sdk-storage/mock"] diff --git a/crates/sdk/macros/src/template.rs b/crates/sdk/macros/src/template.rs index 8dae7ce20..7fcc166e4 100644 --- a/crates/sdk/macros/src/template.rs +++ b/crates/sdk/macros/src/template.rs @@ -57,14 +57,13 @@ pub fn expand(_args: TokenStream, input: TokenStream) -> Result<(TokenStream, Te let structs = expand_structs(&template)?; let functions = expand_functions(&template)?; - let alloc_func = alloc_func_ast(); + let verify_export = export_verify_ast(); + let alloc_export = export_alloc_ast(); let ast = quote! { - // #(#imports)* + #verify_export - // #(#aliases)* - - #alloc_func + #alloc_export #structs @@ -266,15 +265,32 @@ fn expand_functions(template: &Template) -> Result { Ok(ast) } -fn alloc_func_ast() -> TokenStream { +fn export_alloc_ast() -> TokenStream { quote! { - extern crate svm_sdk; #[no_mangle] pub extern "C" fn svm_alloc(size: u32) -> u32 { + extern crate svm_sdk; + let ptr = svm_sdk::alloc(size as usize); ptr.offset() as u32 } } } + +fn export_verify_ast() -> TokenStream { + quote! { + #[no_mangle] + pub extern "C" fn svm_verify() -> u32 { + extern crate svm_sdk; + + // TODO: + // This is a temporary stub + // + // The Template Author will have to come up with + // his own implementation for `svm_verify` + 0 + } + } +} diff --git a/crates/sdk/types/Cargo.toml b/crates/sdk/types/Cargo.toml index 4e4e1e6c8..ee585256d 100644 --- a/crates/sdk/types/Cargo.toml +++ b/crates/sdk/types/Cargo.toml @@ -15,6 +15,6 @@ svm-sdk-std = { path = "../std", default-features = false } [features] default = [] -debug = ["svm-sdk-std/debug"] +debug = ["svm-sdk-std/debug"] static-alloc = ["svm-sdk-std/static-alloc"] dynamic-alloc = ["svm-sdk-std/dynamic-alloc"] \ No newline at end of file From 3d07983292d9819a69deea992e9c2ba42cb719cd Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Fri, 6 Aug 2021 19:28:56 +0300 Subject: [PATCH 12/13] svm-program: fix for resovling func type signature by function index --- crates/program/src/program.rs | 38 ++++++++++++++---- crates/runtime/tests/runtime_tests.rs | 32 +++++++-------- crates/runtime/tests/wasm/calldata/Cargo.lock | 4 +- .../runtime/tests/wasm/runtime_calldata.wasm | Bin 7286 -> 7305 bytes crates/sdk/macros/src/template.rs | 7 +--- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index e2a65d66e..b154d035a 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -184,6 +184,7 @@ fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { let module_functions = module_functions(module, &empty_function_section); let module_types = module_types(module, &empty_type_section); let module_exports = module_exports(module, &empty_export_section); + let import_count = module_functions_import_count(module); let mut seen_alloc = false; let mut seen_verify = false; @@ -192,11 +193,11 @@ fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { match export.field() { "svm_alloc" => { seen_alloc = true; - validate_export_alloc(export, module_functions, module_types)?; + validate_export_alloc(export, import_count, module_functions, module_types)?; } "svm_verify" => { seen_verify = true; - svm_verify_validate(export, &module_functions, &module_types)?; + svm_verify_validate(export, import_count, &module_functions, &module_types)?; } _ => (), } @@ -215,6 +216,7 @@ fn module_validate_exports(module: &pwasm::Module) -> Result<(), ProgramError> { fn validate_export_alloc( export: &pwasm::ExportEntry, + import_count: usize, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], ) -> Result<(), ProgramError> { @@ -223,6 +225,7 @@ fn validate_export_alloc( validate_func_signature( "svm_alloc", export, + import_count, module_funcs, module_types, &[ValueType::I32], @@ -232,6 +235,7 @@ fn validate_export_alloc( fn svm_verify_validate( export: &pwasm::ExportEntry, + import_count: usize, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], ) -> Result<(), ProgramError> { @@ -240,6 +244,7 @@ fn svm_verify_validate( validate_func_signature( "svm_verify", export, + import_count, module_funcs, module_types, &[], @@ -250,20 +255,25 @@ fn svm_verify_validate( fn validate_func_signature( func_name: &str, export: &pwasm::ExportEntry, + import_count: usize, module_funcs: &[pwasm::Func], module_types: &[pwasm::Type], expected_params: &[pwasm::ValueType], expected_results: &[pwasm::ValueType], ) -> Result<(), ProgramError> { - let func_sig = export_func_signature(func_name, export, &module_funcs, &module_types)?; + let func_sig = export_func_signature( + func_name, + export, + import_count, + &module_funcs, + &module_types, + )?; #[allow(irrefutable_let_patterns)] if let pwasm::Type::Function(f) = func_sig { if f.params() == expected_params && f.results() == expected_results { Ok(()) } else { - dbg!(f); - Err(ProgramError::InvalidExportFunctionSignature( func_name.to_string(), )) @@ -276,12 +286,18 @@ fn validate_func_signature( fn export_func_signature<'p>( func_name: &str, entry: &'p pwasm::ExportEntry, + import_count: usize, module_functions: &'p [pwasm::Func], module_types: &'p [pwasm::Type], ) -> Result<&'p pwasm::Type, ProgramError> { - if let pwasm::Internal::Function(i) = entry.internal() { - let func = &module_functions[*i as usize]; - let sig = &module_types[func.type_ref() as usize]; + if let pwasm::Internal::Function(global) = entry.internal() { + let global = *global as usize; + debug_assert!(global >= import_count); + + let local = global - import_count; + let func = &module_functions[local]; + let type_ref = func.type_ref() as usize; + let sig = &module_types[type_ref]; Ok(sig) } else { @@ -309,3 +325,9 @@ fn module_exports<'p>( ) -> &'p [pwasm::ExportEntry] { module.export_section().unwrap_or(default).entries() } + +fn module_functions_import_count(module: &pwasm::Module) -> usize { + use pwasm::ImportCountType; + + module.import_count(ImportCountType::Function) +} diff --git a/crates/runtime/tests/runtime_tests.rs b/crates/runtime/tests/runtime_tests.rs index 58ab2162d..3074cd7c3 100644 --- a/crates/runtime/tests/runtime_tests.rs +++ b/crates/runtime/tests/runtime_tests.rs @@ -119,23 +119,21 @@ fn memory_runtime_validate_deploy_floats_not_allowed() { assert_eq!(expected, actual); } -// #[test] -// fn memory_runtime_validate_deploy_ok() { -// let runtime = testing::create_memory_runtime(); - -// let message = testing::build_deploy( -// 0, -// "My Template", -// FixedLayout::default(), -// &[], -// include_bytes!("wasm/runtime_calldata.wasm")[..].into(), -// ); - -// let result = runtime.validate_deploy(&message); - -// dbg!(result.unwrap_err()); -// // assert!(result.is_ok()); -// } +#[test] +fn memory_runtime_validate_deploy_ok() { + let runtime = testing::create_memory_runtime(); + + let message = testing::build_deploy( + 0, + "My Template", + FixedLayout::default(), + &[], + include_bytes!("wasm/runtime_calldata.wasm")[..].into(), + ); + + let result = runtime.validate_deploy(&message); + assert!(result.is_ok()); +} #[test] fn memory_runtime_validate_spawn_missing_template_addr() { diff --git a/crates/runtime/tests/wasm/calldata/Cargo.lock b/crates/runtime/tests/wasm/calldata/Cargo.lock index 1eb95d227..baa06ff7b 100644 --- a/crates/runtime/tests/wasm/calldata/Cargo.lock +++ b/crates/runtime/tests/wasm/calldata/Cargo.lock @@ -147,7 +147,7 @@ version = "0.0.0" [[package]] name = "svm-runtime-examples-calldata" -version = "0.1.0" +version = "0.0.0" dependencies = [ "svm-sdk", ] @@ -187,7 +187,7 @@ dependencies = [ [[package]] name = "svm-sdk-macros" -version = "0.1.0" +version = "0.0.0" dependencies = [ "proc-macro2", "quote", diff --git a/crates/runtime/tests/wasm/runtime_calldata.wasm b/crates/runtime/tests/wasm/runtime_calldata.wasm index fa46483edaa18885131a566464d84f7b32c6ef5b..028774fca40048c870538510f5bc1d9142e3e6de 100755 GIT binary patch delta 809 zcmY+C&u<^&)kaVfB+Gs<2sVFhw#YC$YducR;*kFMOSxO6(h&_1n z;KgVr@$AimCLXwI)Ob-Z*2aIpXwswc(yPw$qr&C8GyB>3?##S*lzDXF$y?7%1fITI zS#Jb<^>V$@>~bczI`xfCxmm4rnJ?fbMaOAuGQV8is%67e#@6f8jAl;=SFg&hG`HD)s#bOk>_EZQyvu*+aq8{Gi(qc-JJ8j82PC-7iVg=SGTaLFVpnne-cZ5 zGkmQhgz&O)9>Tb1q#=SYjV$S*F$**3H&2tMNuzkvJW0A|E}V;z@q1RYc^X!Q)E3aB zu9%zVvJ7k{;38wHrOaWK;#6QHlll8~`HxdQnuM%JW0f8E_8UO$Q delta 798 zcmZ9K%WD%+6vpql8I#F8nt3EKk5-2YRY7Uo)M!OAE^5V1K`c@#HLqfZq(jmqP!+Nk zOHj^6aN|nRrCF;*cWx}D3&EZJ7ev90p2;+tar1HR{O)(|neX0*7k=a)zvaoqlbyN6 zk{E7O8*Xchv*>2Gu~w|t-7*VHwT)W4R;<_VRar#ZY`d-MTCq}TF)>7!io`{2KzTOZMdp3i&>ya_!SC?;AdNOh9t*xAY+l6pbR>^51^tT z+$C)Yd!&UU`=mYTCOYBmVO7U+q%*8`@s+3_R*#~isv-H+fvj5WEW2aFg31vhCHySk zr`@hFk4xbUK3Cp=hBwqaD1&X)0b2Z==+f|^f5UStM8o%DZ5r`=tdNic(6$`n3SQHu zlKQmpa^zDiZl7{2K{N1ycJ6;u&NqF~5KLUw&qEyh`Ya^yojy1ZLw`bOH(LdS{CLRSj>itj47r}!N&2xxCIJcGP4t#OX@Q5lh Result { fn export_alloc_ast() -> TokenStream { quote! { + // using the `Allocator` of `svm_sdk` + extern crate svm_sdk; #[no_mangle] pub extern "C" fn svm_alloc(size: u32) -> u32 { - extern crate svm_sdk; - let ptr = svm_sdk::alloc(size as usize); - ptr.offset() as u32 } } @@ -283,8 +282,6 @@ fn export_verify_ast() -> TokenStream { quote! { #[no_mangle] pub extern "C" fn svm_verify() -> u32 { - extern crate svm_sdk; - // TODO: // This is a temporary stub // From 25942371f0a46fe7048194743c0cb23ac2df5d31 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Mon, 16 Aug 2021 13:08:01 +0300 Subject: [PATCH 13/13] Changes for PR comments. --- crates/program/src/lib.rs | 8 ++++---- crates/program/src/program.rs | 11 ++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/crates/program/src/lib.rs b/crates/program/src/lib.rs index 5a955fe12..245523550 100644 --- a/crates/program/src/lib.rs +++ b/crates/program/src/lib.rs @@ -2,10 +2,10 @@ //! //! The main entity in this crate is [`Program`]. -#![allow(missing_docs)] -#![allow(unused)] -#![allow(dead_code)] -#![allow(unreachable_code)] +#![deny(missing_docs)] +#![deny(unused)] +#![deny(dead_code)] +#![deny(unreachable_code)] use parity_wasm::elements::Instruction; diff --git a/crates/program/src/program.rs b/crates/program/src/program.rs index b154d035a..5171e8348 100644 --- a/crates/program/src/program.rs +++ b/crates/program/src/program.rs @@ -1,6 +1,6 @@ use indexmap::IndexMap; -use parity_wasm::elements::{self as pwasm, FunctionSection, ValueType}; +use parity_wasm::elements as pwasm; use crate::{ validate_no_floats, Exports, FuncIndex, Function, Imports, Instruction, ProgramError, @@ -261,13 +261,7 @@ fn validate_func_signature( expected_params: &[pwasm::ValueType], expected_results: &[pwasm::ValueType], ) -> Result<(), ProgramError> { - let func_sig = export_func_signature( - func_name, - export, - import_count, - &module_funcs, - &module_types, - )?; + let func_sig = export_func_signature(export, import_count, &module_funcs, &module_types)?; #[allow(irrefutable_let_patterns)] if let pwasm::Type::Function(f) = func_sig { @@ -284,7 +278,6 @@ fn validate_func_signature( } fn export_func_signature<'p>( - func_name: &str, entry: &'p pwasm::ExportEntry, import_count: usize, module_functions: &'p [pwasm::Func],