Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error handling #248

Merged
merged 39 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6cb5bb0
Move envs to odra-core
kubaplas Sep 18, 2023
a855b74
CasperVM
kubaplas Sep 26, 2023
eaed399
Wip
kubaplas Sep 28, 2023
00a859a
Wip
kubaplas Sep 28, 2023
f00e4fc
odra2, wasm backend, counter
zie1ony Sep 28, 2023
ccd7e84
deployer
zie1ony Sep 28, 2023
0bfabfc
Running tests on casperVM
kubaplas Sep 29, 2023
df10f8b
Odra VM Machine (Odra VeryMilusia Machine)
kubaplas Sep 29, 2023
58b638e
OdraVm - continue
kubaplas Sep 29, 2023
74152f0
Running tests without features
kubaplas Oct 2, 2023
dbfc9e5
Squashed commit of the following:
kubaplas Oct 2, 2023
bca6a31
Fix justfile
kubaplas Oct 2, 2023
12f926a
EntryPointsCaller
kubaplas Oct 2, 2023
06f217e
allow for dead code
zie1ony Oct 2, 2023
6e08c32
Everything is now Bytes.
kubaplas Oct 3, 2023
fc6e117
Constructors
zie1ony Oct 23, 2023
9ceba08
Resurect counter_pack and add print_gas_report for host env.
zie1ony Oct 23, 2023
bed4c50
Cross Calls
kubaplas Oct 24, 2023
8eae676
Remove generic consts
zie1ony Oct 24, 2023
86b58fd
Balances in OdraVm
kubaplas Oct 26, 2023
c351c55
Balances on Casper.
kubaplas Oct 26, 2023
0cbd6d2
Move directories around
kubaplas Oct 27, 2023
4acaeb1
get_block_time
kubaplas Oct 27, 2023
8429541
Removed balance_of from contract_env
kubaplas Oct 27, 2023
1e2781e
Remove generic consts
zie1ony Oct 24, 2023
9d3d0ba
merge
zie1ony Oct 27, 2023
c67a872
get_event
kubaplas Oct 31, 2023
4f038be
Skip proxy getter in casper tests if not needed.
zie1ony Nov 6, 2023
1b08371
Merge branch 'feature/envs-in-odra-core' of github.com:odradev/odra i…
kubaplas Nov 6, 2023
6150711
Events
kubaplas Nov 7, 2023
c48e684
Merge remote-tracking branch 'origin/release/0.8.0' into feature/envs…
kubaplas Nov 8, 2023
20d61b8
Wrap event in another layer of Bytes in OdraVm
kubaplas Nov 8, 2023
3bf87af
get_event in Ref
kubaplas Nov 8, 2023
7dc7480
WIP
kubaplas Nov 10, 2023
c04b0bd
Events using new ces interface
kubaplas Nov 10, 2023
8de7fec
Change return type of HostContext::call_contract
kpob Nov 14, 2023
923c0db
Improve error handling
kpob Nov 15, 2023
b1820b5
Merge branch 'release/0.8.0' into feature/errors
kpob Nov 15, 2023
41f2ac6
Apply peer's suggestions
kpob Nov 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ repository = "https://github.com/odradev/odra"
casper-contract = { version = "3.0.0", default-features = false }
casper-types = "3.0.0"
casper-execution-engine = "5.0.0"
casper-event-standard = "0.4.0"
casper-event-standard = "0.4.1"
1 change: 0 additions & 1 deletion examples2/bin/build_contract.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![no_std]
#![no_main]

#![allow(unused_imports)]
use examples2;
4 changes: 2 additions & 2 deletions examples2/src/counter_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ mod __counter_pack_test_parts {
"index_b" => index_b
}
)
)
).unwrap()
}

pub fn increment(&self, index_a: u8, index_b: u8) {
Expand All @@ -218,7 +218,7 @@ mod __counter_pack_test_parts {
"index_b" => index_b
}
)
)
).unwrap()
}
}

Expand Down
121 changes: 89 additions & 32 deletions examples2/src/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ pub struct Approval {
pub value: U256
}

#[repr(u16)]
pub enum Erc20Error {
InsufficientBalance = 1,
InsufficientAllowance = 2
}

impl From<Erc20Error> for OdraError {
fn from(error: Erc20Error) -> Self {
OdraError::user(error as u16)
}
}

pub struct Erc20 {
env: Rc<ContractEnv>,
total_supply: Variable<U256>,
Expand Down Expand Up @@ -47,7 +59,7 @@ impl Erc20 {
let from_balance = balances.get_or_default(caller);
let to_balance = balances.get_or_default(to);
if from_balance < value {
self.env().revert(1);
self.env().revert(Erc20Error::InsufficientBalance)
}
balances.set(caller, from_balance.saturating_sub(value));
balances.set(to, to_balance.saturating_add(value));
Expand All @@ -69,9 +81,6 @@ impl Erc20 {

pub fn pay_to_mint(&mut self) {
let attached_value = self.env().attached_value();
if attached_value.is_zero() {
self.env.revert(666);
}
let caller = self.env().caller();
let caller_balance = self.balance_of(caller);
self.balances
Expand All @@ -88,7 +97,7 @@ impl Erc20 {
let caller = self.env().caller();
let caller_balance = self.balance_of(caller);
if amount > caller_balance {
self.env().revert(1);
self.env().revert(Erc20Error::InsufficientBalance)
}

self.balances.set(caller, caller_balance - amount);
Expand Down Expand Up @@ -334,29 +343,31 @@ mod __erc20_wasm_parts {
}
}

// #[cfg(not(target_arch = "wasm32"))]
pub struct Erc20ContractRef {
pub address: Address,
pub env: Rc<ContractEnv>
}

impl Erc20ContractRef {
pub fn total_supply(&self) -> U256 {
self.env.call_contract(
self.address,
CallDef::new(String::from("total_supply"), RuntimeArgs::new())
)
}
}

#[cfg(not(target_arch = "wasm32"))]
mod __erc20_test_parts {
use crate::erc20::Erc20;
use core::panic;
use core::panic::AssertUnwindSafe;
use odra2::casper_event_standard::EventInstance;
use odra2::event::EventError;
use odra2::prelude::*;
use odra2::types::casper_types::EntryPoints;
use odra2::types::{runtime_args, Address, Bytes, RuntimeArgs, ToBytes, U256, U512, FromBytes};
use odra2::types::{runtime_args, Address, Bytes, RuntimeArgs, ToBytes, U256, U512, FromBytes, OdraError};
use odra2::{CallDef, ContractEnv, EntryPointsCaller, HostEnv};
use odra2::casper_event_standard::EventInstance;
use odra2::event::EventError;

pub struct Erc20ContractRef {
pub address: Address,
pub env: Rc<ContractEnv>
}

impl Erc20ContractRef {
pub fn total_supply(&self) -> U256 {
self.env.call_contract(
self.address,
CallDef::new(String::from("total_supply"), RuntimeArgs::new())
)
}
}

pub struct Erc20HostRef {
pub address: Address,
Expand All @@ -373,14 +384,18 @@ mod __erc20_test_parts {
}
}

pub fn total_supply(&self) -> U256 {
pub fn try_total_supply(&self) -> Result<U256, OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(String::from("total_supply"), RuntimeArgs::new())
)
}

pub fn balance_of(&self, owner: Address) -> U256 {
pub fn total_supply(&self) -> U256 {
self.try_total_supply().unwrap()
}

pub fn try_balance_of(&self, owner: Address) -> Result<U256, OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(
Expand All @@ -391,8 +406,12 @@ mod __erc20_test_parts {
)
)
}

pub fn balance_of(&self, owner: Address) -> U256 {
self.try_balance_of(owner).unwrap()
}

pub fn transfer(&self, to: Address, value: U256) {
pub fn try_transfer(&self, to: Address, value: U256) -> Result<(), OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(
Expand All @@ -405,7 +424,11 @@ mod __erc20_test_parts {
)
}

pub fn cross_total(&self, other: Address) -> U256 {
pub fn transfer(&self, to: Address, value: U256) {
self.try_transfer(to, value).unwrap();
}

pub fn try_cross_total(&self, other: Address) -> Result<U256, OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(
Expand All @@ -417,7 +440,11 @@ mod __erc20_test_parts {
)
}

pub fn pay_to_mint(&self) {
pub fn cross_total(&self, other: Address) -> U256 {
self.try_cross_total(other).unwrap()
}

pub fn try_pay_to_mint(&self) -> Result<(), OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(
Expand All @@ -430,14 +457,22 @@ mod __erc20_test_parts {
)
}

pub fn get_current_block_time(&self) -> u64 {
pub fn pay_to_mint(&self) {
self.try_pay_to_mint().unwrap()
}

pub fn try_get_current_block_time(&self) -> Result<u64, OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(String::from("get_current_block_time"), runtime_args! {})
)
}

pub fn burn_and_get_paid(&self, amount: U256) {
pub fn get_current_block_time(&self) -> u64 {
self.try_get_current_block_time().unwrap()
}

pub fn try_burn_and_get_paid(&self, amount: U256) -> Result<(), OdraError> {
self.env.call_contract(
&self.address,
CallDef::new(
Expand All @@ -449,6 +484,10 @@ mod __erc20_test_parts {
)
}

pub fn burn_and_get_paid(&self, amount: U256) {
self.try_burn_and_get_paid(amount).unwrap()
}

pub fn get_event<T: FromBytes + EventInstance>(&self, index: i32) -> Result<T, EventError> {
self.env.get_event(&self.address, index)
}
Expand Down Expand Up @@ -521,13 +560,18 @@ mod __erc20_test_parts {
}
}

// #[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm32"))]
use crate::erc20::tests::casper_event_standard::casper_types::system::mint::Error::InsufficientFunds;
#[cfg(not(target_arch = "wasm32"))]
pub use __erc20_test_parts::*;
use odra2::types::RuntimeArgs;
use odra2::types::{ExecutionError, OdraError, RuntimeArgs};

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
pub use super::*;
use odra2::types::ExecutionError;
use odra2::types::OdraError;
use odra2::types::ToBytes;
use odra2::types::U512;

Expand Down Expand Up @@ -591,6 +635,19 @@ mod tests {
assert_eq!(event.to, Some(bob));
assert_eq!(event.amount, 10.into());

// Test errors
// Following line panics
// erc20.transfer(alice, 1_000_000.into());
// But this one doesn't
let result = erc20.try_transfer(alice, 1_000_000.into());
assert_eq!(
result,
Err(Erc20Error::InsufficientBalance.into())
);
// With return value
let result = erc20.try_balance_of(alice);
assert_eq!(result, Ok(100.into()));

env.print_gas_report()
}
}
21 changes: 16 additions & 5 deletions odra-casper/test-vm/src/casper_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use odra_types::casper_types::bytesrepr::{Bytes, ToBytes};
use odra_types::casper_types::{
runtime_args, BlockTime, ContractPackageHash, Key, Motes, SecretKey
};
use odra_types::{Address, PublicKey, U512};
use odra_types::{Address, PublicKey, U512, OdraError, VmError};
use odra_types::{EventData, RuntimeArgs};

pub struct CasperHost {
Expand Down Expand Up @@ -50,10 +50,21 @@ impl HostContext for CasperHost {
self.vm.borrow().get_event(contract_address, index)
}

fn call_contract(&self, address: &Address, call_def: CallDef, use_proxy: bool) -> Bytes {
self.vm
.borrow_mut()
.call_contract(address, call_def, use_proxy)
fn call_contract(&self, address: &Address, call_def: CallDef, use_proxy: bool) -> Result<Bytes, OdraError> {
let mut opt_result: Option<Bytes> = None;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
opt_result = Some(self.vm
.borrow_mut()
.call_contract(address, call_def, use_proxy));
}));

match opt_result {
Some(result) => Ok(result),
None => {
let error = self.vm.borrow().error.clone();
Err(error.unwrap_or(OdraError::VmError(VmError::Panic)))
},
}
}

fn new_contract(
Expand Down
51 changes: 43 additions & 8 deletions odra-casper/test-vm/src/vm/casper_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use casper_engine_test_support::{
use casper_event_standard::try_full_name_from_bytes;
use std::rc::Rc;

use casper_execution_engine::core::engine_state::{GenesisAccount, RunGenesisRequest};
use casper_execution_engine::core::engine_state::{GenesisAccount, RunGenesisRequest, self};
use odra_casper_shared::consts;
use odra_casper_shared::consts::*;
use odra_core::entry_point_callback::EntryPointsCaller;
Expand All @@ -24,9 +24,9 @@ use odra_types::casper_types::account::{Account, AccountHash};
use odra_types::casper_types::bytesrepr::{Bytes, ToBytes};
use odra_types::casper_types::{
runtime_args, BlockTime, Contract, ContractHash, ContractPackageHash, Key, Motes, SecretKey,
StoredValue, URef
StoredValue, URef, ApiError
};
use odra_types::{Address, PublicKey, U512};
use odra_types::{Address, PublicKey, U512, VmError, ExecutionError};
use odra_types::{CLTyped, FromBytes, OdraError, RuntimeArgs};

pub struct CasperVm {
Expand Down Expand Up @@ -262,11 +262,9 @@ impl CasperVm {

self.attached_value = U512::zero();
if let Some(error) = self.context.get_error() {
// TODO: handle error
// let odra_error = parse_error(error);
panic!("Error: {}", error);
// self.error = Some(odra_error.clone());
// self.panic_with_error(odra_error, call_def.entry_point, hash);
let odra_error = parse_error(error);
self.error = Some(odra_error.clone());
self.panic_with_error(odra_error, &call_def.entry_point, hash);
} else {
self.get_active_account_result()
}
Expand Down Expand Up @@ -423,4 +421,41 @@ impl CasperVm {
println!("{}: {}", name, cost);
}
}

fn panic_with_error(
&self,
error: OdraError,
entrypoint: &str,
contract_package_hash: ContractPackageHash
) -> ! {
panic!("Revert: {:?} - {:?}::{}", error, contract_package_hash, entrypoint)
}
}

fn parse_error(err: engine_state::Error) -> OdraError {
if let engine_state::Error::Exec(exec_err) = err {
match exec_err {
engine_state::ExecError::Revert(ApiError::MissingArgument) => {
OdraError::VmError(VmError::MissingArg)
},
engine_state::ExecError::Revert(ApiError::Mint(0)) => {
OdraError::VmError(VmError::BalanceExceeded)
},
engine_state::ExecError::Revert(ApiError::User(code)) => {
if code == ExecutionError::NonPayable.code() {
OdraError::ExecutionError(ExecutionError::NonPayable)
} else if code == ExecutionError::ReentrantCall.code() {
OdraError::ExecutionError(ExecutionError::ReentrantCall)
} else {
OdraError::ExecutionError(ExecutionError::User(code))
}
},
engine_state::ExecError::InvalidContext => OdraError::VmError(VmError::InvalidContext),
engine_state::ExecError::NoSuchMethod(name) => OdraError::VmError(VmError::NoSuchMethod(name)),
engine_state::ExecError::MissingArgument { name } => OdraError::VmError(VmError::MissingArg),
_ => OdraError::VmError(VmError::Other(format!("Casper ExecError: {}", exec_err)))
}
} else {
OdraError::VmError(VmError::Other(format!("Casper EngineStateError: {}", err)))
}
}
Loading