Skip to content

Commit

Permalink
Merge branch 'release/1.4.0' into feature/extend_prelude
Browse files Browse the repository at this point in the history
  • Loading branch information
zie1ony committed Oct 17, 2024
2 parents 00ed058 + 0f5b5dc commit 64fe724
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 355 deletions.
27 changes: 22 additions & 5 deletions core/src/contract_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ use casper_types::U512;
/// The container validates a contract call definition before calling the entry point.
#[derive(Clone)]
pub struct ContractContainer {
entry_points_caller: EntryPointsCaller
entry_points_caller: EntryPointsCaller,
ctx: ExecutionContext
}

impl ContractContainer {
/// Creates a new instance of `ContractContainer`.
pub fn new(entry_points_caller: EntryPointsCaller) -> Self {
Self {
entry_points_caller
entry_points_caller,
ctx: ExecutionContext::Installation
}
}

pub(crate) fn post_install(&mut self) {
self.ctx = ExecutionContext::Runtime;
}

/// Calls the entry point with the given call definition.
pub fn call(&self, call_def: CallDef) -> OdraResult<Bytes> {
// find the entry point
Expand All @@ -34,13 +40,22 @@ impl ContractContainer {
if !ep.is_payable && call_def.amount() > U512::zero() {
return Err(OdraError::ExecutionError(ExecutionError::NonPayable));
}
if ep.name == "init" && self.ctx == ExecutionContext::Runtime {
return Err(OdraError::VmError(VmError::InvalidContext));
}
self.entry_points_caller.call(call_def)
}
}

#[derive(PartialEq, Eq, Clone, Copy)]
enum ExecutionContext {
Installation,
Runtime
}

#[cfg(test)]
mod tests {
use super::ContractContainer;
use super::{ContractContainer, ExecutionContext};
use crate::contract_context::MockContractContext;
use crate::entry_point_callback::{Argument, EntryPoint, EntryPointsCaller};
use crate::host::{HostEnv, MockHostContext};
Expand Down Expand Up @@ -85,7 +100,8 @@ mod tests {
)))
});
Self {
entry_points_caller
entry_points_caller,
ctx: ExecutionContext::Installation
}
}

Expand Down Expand Up @@ -113,7 +129,8 @@ mod tests {
});

Self {
entry_points_caller
entry_points_caller,
ctx: ExecutionContext::Installation
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions core/src/contract_register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,11 @@ impl ContractRegister {
}
Err(OdraError::VmError(VmError::InvalidContractAddress))
}

/// Post install hook.
pub fn post_install(&mut self, addr: &Address) {
if let Some(contract) = self.contracts.get_mut(addr) {
contract.post_install();
}
}
}
111 changes: 94 additions & 17 deletions core/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ pub trait EntryPointsCallerProvider {
pub trait Deployer<R: OdraContract>: Sized {
/// Deploys a contract with given init args.
///
/// If the init args are provided, the contract is deployed and initialized
/// by calling the constructor. If the init args are not provided, the contract
/// is deployed without initialization.
/// If the `init_args` is not [NoArgs], the contract is deployed and initialized
/// by calling the constructor. Otherwise no constructor is called.
///
/// The default [OdraConfig] is used for deployment.
///
/// Returns a host reference to the deployed contract.
fn deploy(env: &HostEnv, init_args: R::InitArgs) -> R::HostRef;
Expand All @@ -79,6 +80,20 @@ pub trait Deployer<R: OdraContract>: Sized {
///
/// Similar to `deploy`, but returns a result instead of panicking.
fn try_deploy(env: &HostEnv, init_args: R::InitArgs) -> OdraResult<R::HostRef>;

/// Deploys a contract with given init args and configuration.
///
/// Returns a host reference to the deployed contract.
fn deploy_with_cfg<T: OdraConfig>(env: &HostEnv, init_args: R::InitArgs, cfg: T) -> R::HostRef;

/// Tries to deploy a contract with given init args and configuration.
///
/// Similar to `deploy_with_cfg`, but returns a result instead of panicking.
fn try_deploy_with_cfg<T: OdraConfig>(
env: &HostEnv,
init_args: R::InitArgs,
cfg: T
) -> OdraResult<R::HostRef>;
}

/// A type which can be used as initialization arguments for a contract.
Expand All @@ -99,6 +114,44 @@ impl From<NoArgs> for RuntimeArgs {
}
}

/// A configuration for a contract.
///
/// The configuration every contract written in Odra expects.
/// Read more: [https://odra.dev/docs/backends/casper/#wasm-arguments]
pub trait OdraConfig {
/// Returns the package hash of the contract.
///
/// Used to set the `odra_cfg_package_hash_key_name` key at the contract initialization.
fn package_hash(&self) -> String;
/// Returns true if the contract should be deployed as upgradable.
///
/// If true, the `odra_cfg_is_upgradable` key is set to `true` at the contract initialization.
fn is_upgradable(&self) -> bool;
/// If true and the key `odra_cfg_package_hash_key_name` already exists, it should be overwritten.
fn allow_key_override(&self) -> bool;
}

#[cfg(not(target_arch = "wasm32"))]
/// Default configuration for a contract.
struct DefaultOdraConfig {
name: String
}

#[cfg(not(target_arch = "wasm32"))]
impl OdraConfig for DefaultOdraConfig {
fn package_hash(&self) -> String {
self.name.clone()
}

fn is_upgradable(&self) -> bool {
false
}

fn allow_key_override(&self) -> bool {
true
}
}

#[cfg(not(target_arch = "wasm32"))]
impl<R: OdraContract> Deployer<R> for R {
fn deploy(
Expand All @@ -119,10 +172,47 @@ impl<R: OdraContract> Deployer<R> for R {
env: &HostEnv,
init_args: <R as OdraContract>::InitArgs
) -> OdraResult<<R as OdraContract>::HostRef> {
Self::try_deploy_with_cfg(
env,
init_args,
DefaultOdraConfig {
name: R::HostRef::ident()
}
)
}

fn deploy_with_cfg<T: OdraConfig>(
env: &HostEnv,
init_args: <R as OdraContract>::InitArgs,
cfg: T
) -> <R as OdraContract>::HostRef {
let contract_ident = R::HostRef::ident();
match Self::try_deploy_with_cfg(env, init_args, cfg) {
Ok(contract) => contract,
Err(OdraError::ExecutionError(ExecutionError::MissingArg)) => {
core::panic!("Invalid init args for contract {}.", contract_ident)
}
Err(e) => core::panic!("Contract init failed {:?}", e)
}
}

fn try_deploy_with_cfg<T: OdraConfig>(
env: &HostEnv,
init_args: <R as OdraContract>::InitArgs,
cfg: T
) -> OdraResult<<R as OdraContract>::HostRef> {
let contract_ident = R::HostRef::ident();
let caller = R::HostRef::entry_points_caller(env);
let address = env.new_contract(&contract_ident, init_args.into(), caller)?;

let mut init_args = init_args.into();
init_args.insert(consts::IS_UPGRADABLE_ARG, cfg.is_upgradable())?;
init_args.insert(consts::ALLOW_KEY_OVERRIDE_ARG, cfg.allow_key_override())?;
init_args.insert(
consts::PACKAGE_HASH_KEY_NAME_ARG,
format!("{}_package_hash", cfg.package_hash())
)?;

let address = env.new_contract(&contract_ident, init_args, caller)?;
Ok(R::HostRef::new(address, env.clone()))
}
}
Expand Down Expand Up @@ -268,19 +358,6 @@ impl HostEnv {
entry_points_caller: EntryPointsCaller
) -> OdraResult<Address> {
let backend = self.backend.borrow();

let mut init_args = init_args;
init_args.insert(consts::IS_UPGRADABLE_ARG, false).unwrap();
init_args
.insert(consts::ALLOW_KEY_OVERRIDE_ARG, true)
.unwrap();
init_args
.insert(
consts::PACKAGE_HASH_KEY_NAME_ARG,
format!("{}_package_hash", name)
)
.unwrap();

let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;

self.deployed_contracts.borrow_mut().push(deployed_contract);
Expand Down
Loading

0 comments on commit 64fe724

Please sign in to comment.