use odra_core::{prelude::*, GasReport};
use std::cell::RefCell;
use std::env;
use std::path::PathBuf;
use casper_engine_test_support::{
DeployItemBuilder, ExecuteRequestBuilder, ARG_AMOUNT, DEFAULT_ACCOUNT_INITIAL_BALANCE,
DEFAULT_CHAINSPEC_REGISTRY, DEFAULT_GENESIS_CONFIG_HASH, DEFAULT_PAYMENT
};
use std::rc::Rc;
use crate::CasperVm;
use odra_core::casper_types::account::AccountHash;
use odra_core::casper_types::bytesrepr::{Bytes, ToBytes};
use odra_core::casper_types::{runtime_args, BlockTime, Key, Motes, SecretKey};
use odra_core::casper_types::{PublicKey, RuntimeArgs, U512};
use odra_core::consts;
use odra_core::consts::*;
use odra_core::entry_point_callback::EntryPointsCaller;
use odra_core::prelude::*;
use odra_core::EventError;
use odra_core::{
host::{HostContext, HostEnv},
CallDef, ContractEnv, VmError
};
pub struct CasperHost {
pub vm: Rc<RefCell<CasperVm>>
}
impl HostContext for CasperHost {
fn set_caller(&self, caller: Address) {
self.vm.borrow_mut().set_caller(caller)
}
fn set_gas(&self, gas: u64) {
}
fn caller(&self) -> Address {
self.vm.borrow().get_caller()
}
fn get_account(&self, index: usize) -> Address {
self.vm.borrow().get_account(index)
}
fn get_validator(&self, index: usize) -> PublicKey {
self.vm.borrow().get_validator(index)
}
fn remove_validator(&self, index: usize) {
let validator = self.get_validator(index);
let mut backend = self.vm.borrow_mut();
backend.remove_validator(validator);
}
fn balance_of(&self, address: &Address) -> U512 {
self.vm.borrow().balance_of(address)
}
fn advance_block_time(&self, time_diff: u64) {
self.vm.borrow_mut().advance_block_time(time_diff)
}
fn advance_with_auctions(&self, time_diff: u64) {
self.vm.borrow_mut().advance_with_auctions(time_diff)
}
fn auction_delay(&self) -> u64 {
let mut backend = self.vm.borrow_mut();
backend.auction_delay()
}
fn unbonding_delay(&self) -> u64 {
let mut backend = self.vm.borrow_mut();
backend.unbonding_delay()
}
fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512 {
let mut backend = self.vm.borrow_mut();
backend.delegated_amount(delegator, validator)
}
fn block_time(&self) -> u64 {
self.vm.borrow().block_time()
}
fn get_event(&self, contract_address: &Address, index: u32) -> Result<Bytes, EventError> {
if !contract_address.is_contract() {
return Err(EventError::TriedToQueryEventForNonContract);
}
self.vm.borrow().get_event(contract_address, index)
}
fn get_native_event(
&self,
contract_address: &Address,
index: u32
) -> Result<Bytes, EventError> {
if !contract_address.is_contract() {
return Err(EventError::TriedToQueryEventForNonContract);
}
self.vm.borrow().get_native_event(contract_address, index)
}
fn get_events_count(&self, address: &Address) -> Result<u32, EventError> {
self.vm.borrow().get_events_count(address)
}
fn get_native_events_count(&self, contract_address: &Address) -> Result<u32, EventError> {
self.vm.borrow().get_native_events_count(contract_address)
}
fn call_contract(
&self,
address: &Address,
call_def: CallDef,
use_proxy: bool
) -> OdraResult<Bytes> {
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();
Err(error.unwrap_or(OdraError::VmError(VmError::Panic)))
}
}
}
fn new_contract(
&self,
name: &str,
init_args: RuntimeArgs,
entry_points_caller: EntryPointsCaller
) -> OdraResult<Address> {
let mut opt_result: Option<Address> = None;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
opt_result = Some(self.vm.borrow_mut().new_contract(
name,
init_args,
entry_points_caller
));
}));
match opt_result {
Some(result) => Ok(result),
None => {
let error = self.vm.borrow().error();
Err(error.unwrap_or(OdraError::VmError(VmError::Panic)))
}
}
}
fn upgrade_contract(
&self,
name: &str,
contract_to_upgrade: Address,
upgrade_args: RuntimeArgs,
entry_points_caller: EntryPointsCaller
) -> OdraResult<Address> {
let mut opt_result: Option<Address> = None;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
opt_result = Some(self.vm.borrow_mut().upgrade_contract(
name,
contract_to_upgrade,
upgrade_args,
entry_points_caller
));
}));
match opt_result {
Some(result) => Ok(result),
None => {
let error = self.vm.borrow().error();
Err(error.unwrap_or(OdraError::VmError(VmError::Panic)))
}
}
}
fn register_contract(
&self,
address: Address,
contract_name: String,
entry_points_caller: EntryPointsCaller
) {
panic!("register_contract is not supported in CasperHost");
}
fn contract_env(&self) -> ContractEnv {
unreachable!()
}
fn gas_report(&self) -> GasReport {
self.vm.borrow().gas_report().clone()
}
fn last_call_gas_cost(&self) -> u64 {
self.vm.borrow().last_call_gas_cost()
}
fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
self.vm.borrow().sign_message(message, address)
}
fn public_key(&self, address: &Address) -> PublicKey {
self.vm.borrow().public_key(address)
}
fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
self.vm.borrow_mut().transfer(to, amount)
}
}
impl CasperHost {
pub fn new(vm: Rc<RefCell<CasperVm>>) -> Rc<Self> {
Rc::new(Self { vm })
}
}