Skip to content

Commit

Permalink
Fix error handling OdraVm
Browse files Browse the repository at this point in the history
  • Loading branch information
kpob committed Dec 21, 2023
1 parent 39426fe commit 061ca38
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 103 deletions.
8 changes: 4 additions & 4 deletions core/src/entry_point_callback.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use crate::call_def::CallDef;
use crate::Bytes;
use crate::{Bytes, OdraError};
use crate::{ContractEnv, HostEnv};

#[derive(Clone)]
pub struct EntryPointsCaller {
pub f: fn(contract_env: ContractEnv, call_def: CallDef) -> Bytes,
pub f: fn(contract_env: ContractEnv, call_def: CallDef) -> Result<Bytes, OdraError>,
host_env: HostEnv
}

impl EntryPointsCaller {
pub fn new(
host_env: HostEnv,
f: fn(contract_env: ContractEnv, call_def: CallDef) -> Bytes
f: fn(contract_env: ContractEnv, call_def: CallDef) -> Result<Bytes, OdraError>
) -> Self {
EntryPointsCaller { f, host_env }
}

pub fn call(&self, call_def: CallDef) -> Bytes {
pub fn call(&self, call_def: CallDef) -> Result<Bytes, OdraError> {
(self.f)(self.host_env.contract_env(), call_def)
}
}
24 changes: 15 additions & 9 deletions modules/src/erc1155_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ mod tests {
use crate::erc1155_token::{Erc1155TokenDeployer, Erc1155TokenHostRef};
use crate::wrapped_native::WrappedNativeTokenDeployer;
use odra::prelude::*;
use odra::{Address, Bytes, HostEnv, U256};
use odra::{Address, Bytes, HostEnv, OdraError, VmError, U256};

struct TokenEnv {
env: HostEnv,
Expand Down Expand Up @@ -895,15 +895,19 @@ mod tests {
// When we transfer tokens to an invalid receiver
// Then it errors out
env.env.set_caller(env.alice);
let _err = env.token.try_safe_transfer_from(
let err = env.token.try_safe_transfer_from(
env.alice,
*receiver.address(),
U256::one(),
100.into(),
None
);
// TODO: Reenable this assertion after https://github.com/odradev/odra/issues/298 is fixed
// assert_eq!(err, Err(OdraError::VmError(NoSuchMethod("on_erc1155_received".to_string()))));
assert_eq!(
err,
Err(OdraError::VmError(VmError::NoSuchMethod(
"on_erc1155_received".to_string()
)))
);
}

#[test]
Expand Down Expand Up @@ -998,8 +1002,6 @@ mod tests {

#[test]
fn safe_batch_transfer_to_invalid_receiver() {
// OdraError::VmError(NoSuchMethod("on_erc1155_batch_received".to_string())),
// || {
// Given a deployed contract
let mut env = setup();
// And an invalid receiver
Expand All @@ -1011,7 +1013,7 @@ mod tests {
// When we transfer tokens to an invalid receiver
// Then it errors out
env.env.set_caller(env.alice);
let _err = env
let err = env
.token
.try_safe_batch_transfer_from(
env.alice,
Expand All @@ -1021,7 +1023,11 @@ mod tests {
None
)
.unwrap_err();
// TODO: Reenable this assertion after https://github.com/odradev/odra/issues/298 is fixed
// assert_eq!(err, OdraError::VmError(NoSuchMethod("on_erc1155_batch_received".to_string())));
assert_eq!(
err,
OdraError::VmError(VmError::NoSuchMethod(
"on_erc1155_batch_received".to_string()
))
);
}
}
1 change: 0 additions & 1 deletion modules/src/erc721_receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use odra::prelude::*;
use odra::{Address, Bytes, Module, U256};

/// The ERC721 receiver implementation.
// TODO: remove {} when #295 is merged
#[odra::module]
pub struct Erc721Receiver;

Expand Down
22 changes: 12 additions & 10 deletions modules/src/erc721_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ mod tests {
use crate::erc721_receiver::Erc721ReceiverDeployer;
use crate::erc721_token::errors::Error::TokenAlreadyExists;
use odra::prelude::*;
use odra::{Address, HostEnv, OdraAddress, U256};
use odra::{Address, HostEnv, OdraAddress, OdraError, VmError, U256};

const NAME: &str = "PlascoinNFT";
const SYMBOL: &str = "PLSNFT";
Expand Down Expand Up @@ -487,7 +487,7 @@ mod tests {
// When deploy a contract with the initial supply
let mut erc721_env = setup();
// And another contract which does not support nfts
let _erc20 = Erc20Deployer::init(
let erc20 = Erc20Deployer::init(
&erc721_env.env,
"PLS".to_string(),
"PLASCOIN".to_string(),
Expand All @@ -502,14 +502,16 @@ mod tests {
erc721_env.env.set_caller(erc721_env.alice);

// TODO: Enable this after fixing mockvm
// assert_eq!(
// OdraError::VmError(NoSuchMethod("on_erc721_received".to_string())),
// erc721_env.token.try_safe_transfer_from(
// erc721_env.alice,
// erc20.address,
// U256::from(1)
// ).unwrap_err()
// );
assert_eq!(
Err(OdraError::VmError(VmError::NoSuchMethod(
"on_erc721_received".to_string()
))),
erc721_env.token.try_safe_transfer_from(
erc721_env.alice,
*erc20.address(),
U256::from(1)
)
);
}

#[test]
Expand Down
34 changes: 20 additions & 14 deletions odra-macros/src/ast/deployer_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,23 @@ mod deployer_impl {
match call_def.method() {
"init" => {
let result = execute_init(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"total_supply" => {
let result = execute_total_supply(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"pay_to_mint" => {
let result = execute_pay_to_mint(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"approve" => {
let result = execute_approve(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
_ => panic!("Unknown method")
name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name)),
))
}
});

Expand Down Expand Up @@ -143,13 +145,15 @@ mod deployer_impl {
match call_def.method() {
"total_supply" => {
let result = execute_total_supply(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"pay_to_mint" => {
let result = execute_pay_to_mint(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
_ => panic!("Unknown method")
name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name)),
))
}
});

Expand Down Expand Up @@ -182,25 +186,27 @@ mod deployer_impl {
match call_def.method() {
"total_supply" => {
let result = execute_total_supply(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"get_owner" => {
let result = execute_get_owner(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"set_owner" => {
let result = execute_set_owner(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"name" => {
let result = execute_name(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"symbol" => {
let result = execute_symbol(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
_ => panic!("Unknown method")
name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name)),
))
}
});

Expand Down
6 changes: 4 additions & 2 deletions odra-macros/src/ast/deployer_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,16 @@ impl<'a> FunctionCallBranch {
let result_ident = utils::ident::result();
let function_ident = func.execute_name();
let contract_env_ident = utils::ident::contract_env();
parse_quote!(let #result_ident = #function_ident(#contract_env_ident);)
parse_quote!(let #result_ident = #function_ident(#contract_env_ident);)
}
}

struct DefaultBranch;

impl ToTokens for DefaultBranch {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(quote::quote!(_ => panic!("Unknown method")))
tokens.extend(quote::quote!(name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name))
))))
}
}
20 changes: 12 additions & 8 deletions odra-macros/src/ast/test_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,21 +194,23 @@ mod test {
match call_def.method() {
"init" => {
let result = execute_init(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"total_supply" => {
let result = execute_total_supply(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"pay_to_mint" => {
let result = execute_pay_to_mint(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"approve" => {
let result = execute_approve(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
_ => panic!("Unknown method")
name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name))
))
}
});

Expand Down Expand Up @@ -336,13 +338,15 @@ mod test {
match call_def.method() {
"total_supply" => {
let result = execute_total_supply(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
"pay_to_mint" => {
let result = execute_pay_to_mint(contract_env);
odra::ToBytes::to_bytes(&result).map(Into::into).unwrap()
odra::ToBytes::to_bytes(&result).map(Into::into).map_err(|err| odra::OdraError::ExecutionError(err.into()))
}
_ => panic!("Unknown method")
name => Err(odra::OdraError::VmError(
odra::VmError::NoSuchMethod(odra::prelude::String::from(name)),
))
}
});

Expand Down
4 changes: 3 additions & 1 deletion odra-macros/src/utils/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub fn u512_zero() -> syn::Expr {
}

pub fn parse_bytes(data_ident: &syn::Ident) -> syn::Expr {
parse_quote!(odra::ToBytes::to_bytes(&#data_ident).map(Into::into).unwrap())
let ty = super::ty::to_bytes();
let ty_err = super::ty::odra_error();
parse_quote!(#ty::to_bytes(&#data_ident).map(Into::into).map_err(|err| #ty_err::ExecutionError(err.into())))
}

pub fn module_component_instnace(ty: &syn::Type, env_ident: &syn::Ident, idx: u8) -> syn::Expr {
Expand Down
37 changes: 9 additions & 28 deletions odra-vm/src/vm/contract_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub type EntrypointArgs = Vec<String>;
#[derive(Clone)]
pub struct ContractContainer {
name: String,

entry_points_caller: EntryPointsCaller
}

Expand All @@ -27,36 +28,16 @@ impl ContractContainer {
}

pub fn call(&self, call_def: CallDef) -> Result<Bytes, OdraError> {
Ok(self.entry_points_caller.call(call_def))
// TODO: Restore validate_args
// if self.constructors.get(&entrypoint).is_some() {
// return Err(OdraError::VmError(VmError::InvalidContext));
// }
//
// match self.entrypoints.get(&entrypoint) {
// Some((ep_args, call)) => {
// self.validate_args(ep_args, args)?;
// Ok(call(self.name.clone(), args))
// }
// None => Err(OdraError::VmError(VmError::NoSuchMethod(entrypoint)))
// }
// }
//
// pub fn call_constructor(
// &self,
// entrypoint: String,
// args: &RuntimeArgs
// ) -> Result<Vec<u8>, OdraError> {
// match self.constructors.get(&entrypoint) {
// Some((ep_args, call)) => {
// self.validate_args(ep_args, args)?;
// Ok(call(self.name.clone(), args))
// }
// None => Err(OdraError::VmError(VmError::NoSuchMethod(entrypoint)))
// }
// TODO: Restore validate_args - to do so, we need to know names of all args.
// The current structure of ContractContainer doesn't allow that - we do not store the required args names.
// It makes impossible to mimic the behavior of the CasperVm

// let registered_args = vec![];
// self.validate_args(&registered_args, call_def.args())?;
self.entry_points_caller.call(call_def)
}

fn _validate_args(&self, args: &[String], input_args: &RuntimeArgs) -> Result<(), OdraError> {
fn validate_args(&self, args: &[String], input_args: &RuntimeArgs) -> Result<(), OdraError> {
// TODO: What's the purpose of this code? Is it needed?
let named_args = input_args
.named_args()
Expand Down
29 changes: 4 additions & 25 deletions odra-vm/src/vm/contract_register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,9 @@ impl ContractRegister {
}

pub fn call(&self, addr: &Address, call_def: CallDef) -> Result<Bytes, OdraError> {
// todo: make it better
self.contracts.get(addr).unwrap().call(call_def)
if let Some(contract) = self.contracts.get(addr) {
return contract.call(call_def);
}
Err(OdraError::VmError(VmError::InvalidContractAddress))
}

// pub fn call_constructor(
// &self,
// addr: &Address,
// entrypoint: String,
// args: &RuntimeArgs
// ) -> Result<Vec<u8>, OdraError> {
// self.internal_call(addr, |container| {
// container.call_constructor(entrypoint, args)
// })
// }
//
// fn internal_call<F: FnOnce(&ContractContainer) -> Result<Vec<u8>, OdraError>>(
// &self,
// addr: &Address,
// call_fn: F
// ) -> Result<Vec<u8>, OdraError> {
// let contract = self.contracts.get(addr);
// match contract {
// Some(container) => call_fn(container),
// None => Err(OdraError::VmError(VmError::InvalidContractAddress))
// }
// }
}
1 change: 0 additions & 1 deletion odra-vm/src/vm/odra_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ impl OdraVm {
self.revert(err);
}
}

let result = self
.contract_register
.read()
Expand Down

0 comments on commit 061ca38

Please sign in to comment.