mod args;
mod externals;
mod mint_internal;
mod proof_of_stake_internal;
mod scoped_instrumenter;
mod standard_payment_internal;
use std::{
cmp,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
convert::TryFrom,
iter::IntoIterator,
};
use itertools::Itertools;
use parity_wasm::elements::Module;
use wasmi::{ImportsBuilder, MemoryRef, ModuleInstance, ModuleRef, Trap, TrapKind};
use ::mint::Mint;
use engine_shared::{account::Account, gas::Gas, stored_value::StoredValue};
use engine_storage::{global_state::StateReader, protocol_data::ProtocolData};
use proof_of_stake::ProofOfStake;
use standard_payment::StandardPayment;
use types::{
account::{AccountHash, ActionType, Weight},
bytesrepr::{self, FromBytes, ToBytes},
contracts::{
self, Contract, ContractPackage, EntryPoint, EntryPointAccess, EntryPoints, Group,
},
runtime_args, system_contract_errors,
system_contract_errors::mint,
AccessRights, ApiError, CLType, CLTyped, CLValue, ContractHash, ContractPackageHash,
ContractVersionKey, ContractWasm, EntryPointType, Key, ProtocolVersion, RuntimeArgs,
SystemContractType, TransferResult, TransferredTo, URef, U128, U256, U512,
};
use crate::{
engine_state::{system_contract_cache::SystemContractCache, EngineConfig},
execution::Error,
resolvers::{create_module_resolver, memory_resolver::MemoryResolver},
runtime_context::{self, RuntimeContext},
Address,
};
use contracts::{ContractVersion, ContractVersions, DisabledVersions, Groups, NamedKeys};
use scoped_instrumenter::ScopedInstrumenter;
pub struct Runtime<'a, R> {
system_contract_cache: SystemContractCache,
config: EngineConfig,
memory: MemoryRef,
module: Module,
host_buffer: Option<CLValue>,
context: RuntimeContext<'a, R>,
}
pub fn rename_export_to_call(module: &mut Module, name: String) {
let main_export = module
.export_section_mut()
.unwrap()
.entries_mut()
.iter_mut()
.find(|e| e.field() == name)
.unwrap()
.field_mut();
main_export.clear();
main_export.push_str("call");
}
pub fn instance_and_memory(
parity_module: Module,
protocol_version: ProtocolVersion,
) -> Result<(ModuleRef, MemoryRef), Error> {
let module = wasmi::Module::from_parity_wasm_module(parity_module)?;
let resolver = create_module_resolver(protocol_version)?;
let mut imports = ImportsBuilder::new();
imports.push_resolver("env", &resolver);
let not_started_module = ModuleInstance::new(&module, &imports)?;
if not_started_module.has_start() {
return Err(Error::UnsupportedWasmStart);
}
let instance = not_started_module.not_started_instance().clone();
let memory = resolver.memory_ref()?;
Ok((instance, memory))
}
pub fn key_to_tuple(key: Key) -> Option<([u8; 32], AccessRights)> {
match key {
Key::URef(uref) => Some((uref.addr(), uref.access_rights())),
Key::Account(_) => None,
Key::Hash(_) => None,
}
}
pub fn extract_access_rights_from_urefs<I: IntoIterator<Item = URef>>(
input: I,
) -> HashMap<Address, HashSet<AccessRights>> {
input
.into_iter()
.map(|uref: URef| (uref.addr(), uref.access_rights()))
.group_by(|(key, _)| *key)
.into_iter()
.map(|(key, group)| {
(
key,
group.map(|(_, x)| x).collect::<HashSet<AccessRights>>(),
)
})
.collect()
}
pub fn extract_access_rights_from_keys<I: IntoIterator<Item = Key>>(
input: I,
) -> HashMap<Address, HashSet<AccessRights>> {
input
.into_iter()
.map(key_to_tuple)
.flatten()
.group_by(|(key, _)| *key)
.into_iter()
.map(|(key, group)| {
(
key,
group.map(|(_, x)| x).collect::<HashSet<AccessRights>>(),
)
})
.collect()
}
#[allow(clippy::cognitive_complexity)]
fn extract_urefs(cl_value: &CLValue) -> Result<Vec<URef>, Error> {
match cl_value.cl_type() {
CLType::Bool
| CLType::I32
| CLType::I64
| CLType::U8
| CLType::U32
| CLType::U64
| CLType::U128
| CLType::U256
| CLType::U512
| CLType::Unit
| CLType::String
| CLType::Any => Ok(vec![]),
CLType::Option(ty) => match **ty {
CLType::URef => {
let opt: Option<URef> = cl_value.to_owned().into_t()?;
Ok(opt.into_iter().collect())
}
CLType::Key => {
let opt: Option<Key> = cl_value.to_owned().into_t()?;
Ok(opt.into_iter().flat_map(Key::into_uref).collect())
}
_ => Ok(vec![]),
},
CLType::List(ty) => match **ty {
CLType::URef => Ok(cl_value.to_owned().into_t()?),
CLType::Key => {
let keys: Vec<Key> = cl_value.to_owned().into_t()?;
Ok(keys.into_iter().filter_map(Key::into_uref).collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 1) => match **ty {
CLType::URef => {
let arr: [URef; 1] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 1] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 2) => match **ty {
CLType::URef => {
let arr: [URef; 2] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 2] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 3) => match **ty {
CLType::URef => {
let arr: [URef; 3] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 3] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 4) => match **ty {
CLType::URef => {
let arr: [URef; 4] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 4] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 5) => match **ty {
CLType::URef => {
let arr: [URef; 5] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 5] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 6) => match **ty {
CLType::URef => {
let arr: [URef; 6] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 6] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 7) => match **ty {
CLType::URef => {
let arr: [URef; 7] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 7] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 8) => match **ty {
CLType::URef => {
let arr: [URef; 8] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 8] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 9) => match **ty {
CLType::URef => {
let arr: [URef; 9] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 9] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 10) => match **ty {
CLType::URef => {
let arr: [URef; 10] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 10] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 11) => match **ty {
CLType::URef => {
let arr: [URef; 11] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 11] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 12) => match **ty {
CLType::URef => {
let arr: [URef; 12] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 12] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 13) => match **ty {
CLType::URef => {
let arr: [URef; 13] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 13] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 14) => match **ty {
CLType::URef => {
let arr: [URef; 14] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 14] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 15) => match **ty {
CLType::URef => {
let arr: [URef; 15] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 15] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 16) => match **ty {
CLType::URef => {
let arr: [URef; 16] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 16] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 17) => match **ty {
CLType::URef => {
let arr: [URef; 17] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 17] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 18) => match **ty {
CLType::URef => {
let arr: [URef; 18] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 18] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 19) => match **ty {
CLType::URef => {
let arr: [URef; 19] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 19] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 20) => match **ty {
CLType::URef => {
let arr: [URef; 20] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 20] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 21) => match **ty {
CLType::URef => {
let arr: [URef; 21] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 21] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 22) => match **ty {
CLType::URef => {
let arr: [URef; 22] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 22] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 23) => match **ty {
CLType::URef => {
let arr: [URef; 23] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 23] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 24) => match **ty {
CLType::URef => {
let arr: [URef; 24] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 24] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 25) => match **ty {
CLType::URef => {
let arr: [URef; 25] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 25] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 26) => match **ty {
CLType::URef => {
let arr: [URef; 26] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 26] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 27) => match **ty {
CLType::URef => {
let arr: [URef; 27] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 27] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 28) => match **ty {
CLType::URef => {
let arr: [URef; 28] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 28] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 29) => match **ty {
CLType::URef => {
let arr: [URef; 29] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 29] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 30) => match **ty {
CLType::URef => {
let arr: [URef; 30] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 30] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 31) => match **ty {
CLType::URef => {
let arr: [URef; 31] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 31] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 32) => match **ty {
CLType::URef => {
let arr: [URef; 32] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 32] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 64) => match **ty {
CLType::URef => {
let arr: [URef; 64] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 64] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 128) => match **ty {
CLType::URef => {
let arr: [URef; 128] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 128] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 256) => match **ty {
CLType::URef => {
let arr: [URef; 256] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 256] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(ty, 512) => match **ty {
CLType::URef => {
let arr: [URef; 512] = cl_value.to_owned().into_t()?;
Ok(arr.to_vec())
}
CLType::Key => {
let arr: [Key; 512] = cl_value.to_owned().into_t()?;
Ok(arr.iter().filter_map(Key::as_uref).cloned().collect())
}
_ => Ok(vec![]),
},
CLType::FixedList(_ty, _) => Ok(vec![]),
CLType::Result { ok, err } => match (&**ok, &**err) {
(CLType::URef, CLType::Bool) => {
let res: Result<URef, bool> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::I32) => {
let res: Result<URef, i32> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::I64) => {
let res: Result<URef, i64> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U8) => {
let res: Result<URef, u8> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U32) => {
let res: Result<URef, u32> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U64) => {
let res: Result<URef, u64> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U128) => {
let res: Result<URef, U128> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U256) => {
let res: Result<URef, U256> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::U512) => {
let res: Result<URef, U512> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::Unit) => {
let res: Result<URef, ()> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::String) => {
let res: Result<URef, String> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(_) => Ok(vec![]),
}
}
(CLType::URef, CLType::Key) => {
let res: Result<URef, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::URef, CLType::URef) => {
let res: Result<URef, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(uref) => Ok(vec![uref]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::Key, CLType::Bool) => {
let res: Result<Key, bool> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::I32) => {
let res: Result<Key, i32> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::I64) => {
let res: Result<Key, i64> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U8) => {
let res: Result<Key, u8> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U32) => {
let res: Result<Key, u32> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U64) => {
let res: Result<Key, u64> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U128) => {
let res: Result<Key, U128> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U256) => {
let res: Result<Key, U256> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::U512) => {
let res: Result<Key, U512> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::Unit) => {
let res: Result<Key, ()> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::String) => {
let res: Result<Key, String> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(_) => Ok(vec![]),
}
}
(CLType::Key, CLType::URef) => {
let res: Result<Key, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::Key, CLType::Key) => {
let res: Result<Key, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(key) => Ok(key.into_uref().into_iter().collect()),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::Bool, CLType::URef) => {
let res: Result<bool, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::I32, CLType::URef) => {
let res: Result<i32, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::I64, CLType::URef) => {
let res: Result<i64, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U8, CLType::URef) => {
let res: Result<u8, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U32, CLType::URef) => {
let res: Result<u32, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U64, CLType::URef) => {
let res: Result<u64, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U128, CLType::URef) => {
let res: Result<U128, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U256, CLType::URef) => {
let res: Result<U256, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::U512, CLType::URef) => {
let res: Result<U512, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::Unit, CLType::URef) => {
let res: Result<(), URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::String, CLType::URef) => {
let res: Result<String, URef> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(uref) => Ok(vec![uref]),
}
}
(CLType::Bool, CLType::Key) => {
let res: Result<bool, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::I32, CLType::Key) => {
let res: Result<i32, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::I64, CLType::Key) => {
let res: Result<i64, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U8, CLType::Key) => {
let res: Result<u8, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U32, CLType::Key) => {
let res: Result<u32, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U64, CLType::Key) => {
let res: Result<u64, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U128, CLType::Key) => {
let res: Result<U128, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U256, CLType::Key) => {
let res: Result<U256, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::U512, CLType::Key) => {
let res: Result<U512, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::Unit, CLType::Key) => {
let res: Result<(), Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(CLType::String, CLType::Key) => {
let res: Result<String, Key> = cl_value.to_owned().into_t()?;
match res {
Ok(_) => Ok(vec![]),
Err(key) => Ok(key.into_uref().into_iter().collect()),
}
}
(_, _) => Ok(vec![]),
},
CLType::Map { key, value } => match (&**key, &**value) {
(CLType::URef, CLType::Bool) => {
let map: BTreeMap<URef, bool> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::I32) => {
let map: BTreeMap<URef, i32> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::I64) => {
let map: BTreeMap<URef, i64> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U8) => {
let map: BTreeMap<URef, u8> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U32) => {
let map: BTreeMap<URef, u32> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U64) => {
let map: BTreeMap<URef, u64> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U128) => {
let map: BTreeMap<URef, U128> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U256) => {
let map: BTreeMap<URef, U256> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::U512) => {
let map: BTreeMap<URef, U512> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::Unit) => {
let map: BTreeMap<URef, ()> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::String) => {
let map: BTreeMap<URef, String> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().collect())
}
(CLType::URef, CLType::Key) => {
let map: BTreeMap<URef, Key> = cl_value.to_owned().into_t()?;
Ok(map
.keys()
.cloned()
.chain(map.values().cloned().filter_map(Key::into_uref))
.collect())
}
(CLType::URef, CLType::URef) => {
let map: BTreeMap<URef, URef> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().chain(map.values().cloned()).collect())
}
(CLType::Key, CLType::Bool) => {
let map: BTreeMap<Key, bool> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::I32) => {
let map: BTreeMap<Key, i32> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::I64) => {
let map: BTreeMap<Key, i64> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U8) => {
let map: BTreeMap<Key, u8> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U32) => {
let map: BTreeMap<Key, u32> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U64) => {
let map: BTreeMap<Key, u64> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U128) => {
let map: BTreeMap<Key, U128> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U256) => {
let map: BTreeMap<Key, U256> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::U512) => {
let map: BTreeMap<Key, U512> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::Unit) => {
let map: BTreeMap<Key, ()> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::String) => {
let map: BTreeMap<Key, String> = cl_value.to_owned().into_t()?;
Ok(map.keys().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Key, CLType::URef) => {
let map: BTreeMap<Key, URef> = cl_value.to_owned().into_t()?;
Ok(map
.keys()
.cloned()
.filter_map(Key::into_uref)
.chain(map.values().cloned())
.collect())
}
(CLType::Key, CLType::Key) => {
let map: BTreeMap<Key, Key> = cl_value.to_owned().into_t()?;
Ok(map
.keys()
.cloned()
.filter_map(Key::into_uref)
.chain(map.values().cloned().filter_map(Key::into_uref))
.collect())
}
(CLType::Bool, CLType::URef) => {
let map: BTreeMap<bool, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::I32, CLType::URef) => {
let map: BTreeMap<i32, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::I64, CLType::URef) => {
let map: BTreeMap<i64, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U8, CLType::URef) => {
let map: BTreeMap<u8, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U32, CLType::URef) => {
let map: BTreeMap<u32, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U64, CLType::URef) => {
let map: BTreeMap<u64, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U128, CLType::URef) => {
let map: BTreeMap<U128, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U256, CLType::URef) => {
let map: BTreeMap<U256, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::U512, CLType::URef) => {
let map: BTreeMap<U512, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::Unit, CLType::URef) => {
let map: BTreeMap<(), URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::String, CLType::URef) => {
let map: BTreeMap<String, URef> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().collect())
}
(CLType::Bool, CLType::Key) => {
let map: BTreeMap<bool, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::I32, CLType::Key) => {
let map: BTreeMap<i32, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::I64, CLType::Key) => {
let map: BTreeMap<i64, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U8, CLType::Key) => {
let map: BTreeMap<u8, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U32, CLType::Key) => {
let map: BTreeMap<u32, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U64, CLType::Key) => {
let map: BTreeMap<u64, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U128, CLType::Key) => {
let map: BTreeMap<U128, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U256, CLType::Key) => {
let map: BTreeMap<U256, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::U512, CLType::Key) => {
let map: BTreeMap<U512, Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::Unit, CLType::Key) => {
let map: BTreeMap<(), Key> = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(CLType::String, CLType::Key) => {
let map: NamedKeys = cl_value.to_owned().into_t()?;
Ok(map.values().cloned().filter_map(Key::into_uref).collect())
}
(_, _) => Ok(vec![]),
},
CLType::Tuple1([ty]) => match **ty {
CLType::URef => {
let val: (URef,) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
CLType::Key => {
let val: (Key,) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
_ => Ok(vec![]),
},
CLType::Tuple2([ty1, ty2]) => match (&**ty1, &**ty2) {
(CLType::URef, CLType::Bool) => {
let val: (URef, bool) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::I32) => {
let val: (URef, i32) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::I64) => {
let val: (URef, i64) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U8) => {
let val: (URef, u8) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U32) => {
let val: (URef, u32) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U64) => {
let val: (URef, u64) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U128) => {
let val: (URef, U128) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U256) => {
let val: (URef, U256) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::U512) => {
let val: (URef, U512) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::Unit) => {
let val: (URef, ()) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::String) => {
let val: (URef, String) = cl_value.to_owned().into_t()?;
Ok(vec![val.0])
}
(CLType::URef, CLType::Key) => {
let val: (URef, Key) = cl_value.to_owned().into_t()?;
let mut res = vec![val.0];
res.extend(val.1.into_uref().into_iter());
Ok(res)
}
(CLType::URef, CLType::URef) => {
let val: (URef, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.0, val.1])
}
(CLType::Key, CLType::Bool) => {
let val: (Key, bool) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::I32) => {
let val: (Key, i32) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::I64) => {
let val: (Key, i64) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U8) => {
let val: (Key, u8) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U32) => {
let val: (Key, u32) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U64) => {
let val: (Key, u64) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U128) => {
let val: (Key, U128) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U256) => {
let val: (Key, U256) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::U512) => {
let val: (Key, U512) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::Unit) => {
let val: (Key, ()) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::String) => {
let val: (Key, String) = cl_value.to_owned().into_t()?;
Ok(val.0.into_uref().into_iter().collect())
}
(CLType::Key, CLType::URef) => {
let val: (Key, URef) = cl_value.to_owned().into_t()?;
let mut res: Vec<URef> = val.0.into_uref().into_iter().collect();
res.push(val.1);
Ok(res)
}
(CLType::Key, CLType::Key) => {
let val: (Key, Key) = cl_value.to_owned().into_t()?;
Ok(val
.0
.into_uref()
.into_iter()
.chain(val.1.into_uref().into_iter())
.collect())
}
(CLType::Bool, CLType::URef) => {
let val: (bool, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::I32, CLType::URef) => {
let val: (i32, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::I64, CLType::URef) => {
let val: (i64, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U8, CLType::URef) => {
let val: (u8, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U32, CLType::URef) => {
let val: (u32, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U64, CLType::URef) => {
let val: (u64, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U128, CLType::URef) => {
let val: (U128, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U256, CLType::URef) => {
let val: (U256, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::U512, CLType::URef) => {
let val: (U512, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::Unit, CLType::URef) => {
let val: ((), URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::String, CLType::URef) => {
let val: (String, URef) = cl_value.to_owned().into_t()?;
Ok(vec![val.1])
}
(CLType::Bool, CLType::Key) => {
let val: (bool, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::I32, CLType::Key) => {
let val: (i32, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::I64, CLType::Key) => {
let val: (i64, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U8, CLType::Key) => {
let val: (u8, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U32, CLType::Key) => {
let val: (u32, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U64, CLType::Key) => {
let val: (u64, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U128, CLType::Key) => {
let val: (U128, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U256, CLType::Key) => {
let val: (U256, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::U512, CLType::Key) => {
let val: (U512, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::Unit, CLType::Key) => {
let val: ((), Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(CLType::String, CLType::Key) => {
let val: (String, Key) = cl_value.to_owned().into_t()?;
Ok(val.1.into_uref().into_iter().collect())
}
(_, _) => Ok(vec![]),
},
CLType::Tuple3(_) => Ok(vec![]),
CLType::Key => {
let key: Key = cl_value.to_owned().into_t()?; Ok(key.into_uref().into_iter().collect())
}
CLType::URef => {
let uref: URef = cl_value.to_owned().into_t()?; Ok(vec![uref])
}
}
}
impl<'a, R> Runtime<'a, R>
where
R: StateReader<Key, StoredValue>,
R::Error: Into<Error>,
{
pub fn new(
config: EngineConfig,
system_contract_cache: SystemContractCache,
memory: MemoryRef,
module: Module,
context: RuntimeContext<'a, R>,
) -> Self {
Runtime {
config,
system_contract_cache,
memory,
module,
host_buffer: None,
context,
}
}
pub fn memory(&self) -> &MemoryRef {
&self.memory
}
pub fn module(&self) -> &Module {
&self.module
}
pub fn context(&self) -> &RuntimeContext<'a, R> {
&self.context
}
pub fn protocol_data(&self) -> ProtocolData {
self.context.protocol_data()
}
fn charge_gas(&mut self, amount: Gas) -> bool {
let prev = self.context.gas_counter();
match prev.checked_add(amount) {
None => false,
Some(val) if val > self.context.gas_limit() => false,
Some(val) => {
self.context.set_gas_counter(val);
true
}
}
}
fn gas(&mut self, amount: Gas) -> Result<(), Trap> {
if self.charge_gas(amount) {
Ok(())
} else {
Err(Error::GasLimit.into())
}
}
fn bytes_from_mem(&self, ptr: u32, size: usize) -> Result<Vec<u8>, Error> {
self.memory.get(ptr, size).map_err(Into::into)
}
fn t_from_mem<T: FromBytes>(&self, ptr: u32, size: u32) -> Result<T, Error> {
let bytes = self.bytes_from_mem(ptr, size as usize)?;
bytesrepr::deserialize(bytes).map_err(Into::into)
}
fn key_from_mem(&mut self, key_ptr: u32, key_size: u32) -> Result<Key, Error> {
let bytes = self.bytes_from_mem(key_ptr, key_size as usize)?;
bytesrepr::deserialize(bytes).map_err(Into::into)
}
fn cl_value_from_mem(
&mut self,
cl_value_ptr: u32,
cl_value_size: u32,
) -> Result<CLValue, Error> {
let bytes = self.bytes_from_mem(cl_value_ptr, cl_value_size as usize)?;
bytesrepr::deserialize(bytes).map_err(Into::into)
}
fn string_from_mem(&self, ptr: u32, size: u32) -> Result<String, Trap> {
let bytes = self.bytes_from_mem(ptr, size as usize)?;
bytesrepr::deserialize(bytes).map_err(|e| Error::BytesRepr(e).into())
}
fn get_module_from_entry_points(
&mut self,
entry_points: &EntryPoints,
) -> Result<Vec<u8>, Error> {
let export_section = self
.module
.export_section()
.ok_or_else(|| Error::FunctionNotFound(String::from("Missing Export Section")))?;
let entry_point_names: Vec<&str> = entry_points.keys().map(|s| s.as_str()).collect();
let maybe_missing_name: Option<String> = entry_point_names
.iter()
.find(|name| {
export_section
.entries()
.iter()
.find(|export_entry| export_entry.field() == **name)
.is_none()
})
.map(|s| String::from(*s));
if let Some(missing_name) = maybe_missing_name {
Err(Error::FunctionNotFound(missing_name))
} else {
let mut module = self.module.clone();
pwasm_utils::optimize(&mut module, entry_point_names).unwrap();
parity_wasm::serialize(module).map_err(Error::ParityWasm)
}
}
fn is_valid_uref(&mut self, uref_ptr: u32, uref_size: u32) -> Result<bool, Trap> {
let bytes = self.bytes_from_mem(uref_ptr, uref_size as usize)?;
let uref: URef = bytesrepr::deserialize(bytes).map_err(Error::BytesRepr)?;
Ok(self.context.validate_uref(&uref).is_ok())
}
fn load_key(
&mut self,
name_ptr: u32,
name_size: u32,
output_ptr: u32,
output_size: usize,
bytes_written_ptr: u32,
) -> Result<Result<(), ApiError>, Trap> {
let name = self.string_from_mem(name_ptr, name_size)?;
let key = match self.context.named_keys_get(&name) {
Some(key) => key,
None => return Ok(Err(ApiError::MissingKey)),
};
let key_bytes = match key.to_bytes() {
Ok(bytes) => bytes,
Err(error) => return Ok(Err(error.into())),
};
if output_size < key_bytes.len() {
return Ok(Err(ApiError::BufferTooSmall));
}
if let Err(error) = self.memory.set(output_ptr, &key_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
let bytes_size = key_bytes.len() as u32;
let size_bytes = bytes_size.to_le_bytes(); if let Err(error) = self.memory.set(bytes_written_ptr, &size_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
Ok(Ok(()))
}
fn has_key(&mut self, name_ptr: u32, name_size: u32) -> Result<i32, Trap> {
let name = self.string_from_mem(name_ptr, name_size)?;
if self.context.named_keys_contains_key(&name) {
Ok(0)
} else {
Ok(1)
}
}
fn put_key(
&mut self,
name_ptr: u32,
name_size: u32,
key_ptr: u32,
key_size: u32,
) -> Result<(), Trap> {
let name = self.string_from_mem(name_ptr, name_size)?;
let key = self.key_from_mem(key_ptr, key_size)?;
self.context.put_key(name, key).map_err(Into::into)
}
fn remove_key(&mut self, name_ptr: u32, name_size: u32) -> Result<(), Trap> {
let name = self.string_from_mem(name_ptr, name_size)?;
self.context.remove_key(&name)?;
Ok(())
}
fn get_main_purse(&mut self, dest_ptr: u32) -> Result<(), Trap> {
let purse = self.context.get_main_purse()?;
let purse_bytes = purse.into_bytes().map_err(Error::BytesRepr)?;
self.memory
.set(dest_ptr, &purse_bytes)
.map_err(|e| Error::Interpreter(e.into()).into())
}
fn get_caller(&mut self, output_size: u32) -> Result<Result<(), ApiError>, Trap> {
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let value = CLValue::from_t(self.context.get_caller()).map_err(Error::CLValue)?;
let value_size = value.inner_bytes().len();
if let Err(error) = self.write_host_buffer(value) {
return Ok(Err(error));
}
let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size, &output_size_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
Ok(Ok(()))
}
fn get_phase(&mut self, dest_ptr: u32) -> Result<(), Trap> {
let phase = self.context.phase();
let bytes = phase.into_bytes().map_err(Error::BytesRepr)?;
self.memory
.set(dest_ptr, &bytes)
.map_err(|e| Error::Interpreter(e.into()).into())
}
fn get_blocktime(&self, dest_ptr: u32) -> Result<(), Trap> {
let blocktime = self
.context
.get_blocktime()
.into_bytes()
.map_err(Error::BytesRepr)?;
self.memory
.set(dest_ptr, &blocktime)
.map_err(|e| Error::Interpreter(e.into()).into())
}
fn ret(
&mut self,
value_ptr: u32,
value_size: usize,
scoped_instrumenter: &mut ScopedInstrumenter,
) -> Trap {
const UREF_COUNT: &str = "uref_count";
self.host_buffer = None;
let mem_get = self
.memory
.get(value_ptr, value_size)
.map_err(|e| Error::Interpreter(e.into()));
match mem_get {
Ok(buf) => {
self.host_buffer = bytesrepr::deserialize(buf).ok();
let urefs = match &self.host_buffer {
Some(buf) => extract_urefs(buf),
None => Ok(vec![]),
};
match urefs {
Ok(urefs) => {
scoped_instrumenter.add_property(UREF_COUNT, urefs.len());
Error::Ret(urefs).into()
}
Err(e) => {
scoped_instrumenter.add_property(UREF_COUNT, 0);
e.into()
}
}
}
Err(e) => {
scoped_instrumenter.add_property(UREF_COUNT, 0);
e.into()
}
}
}
pub fn is_mint(&self, key: Key) -> bool {
key.into_seed() == self.protocol_data().mint()
}
pub fn is_proof_of_stake(&self, key: Key) -> bool {
key.into_seed() == self.protocol_data().proof_of_stake()
}
fn get_named_argument<T: FromBytes + CLTyped>(
args: &RuntimeArgs,
name: &str,
) -> Result<T, Error> {
let arg: CLValue = args
.get(name)
.cloned()
.ok_or_else(|| Error::Revert(ApiError::MissingArgument))?;
arg.into_t()
.map_err(|_| Error::Revert(ApiError::InvalidArgument))
}
fn reverter<T: Into<ApiError>>(error: T) -> Error {
let api_error: ApiError = error.into();
Error::Revert(api_error)
}
pub fn call_host_mint(
&mut self,
protocol_version: ProtocolVersion,
entry_point_name: &str,
named_keys: &mut NamedKeys,
runtime_args: &RuntimeArgs,
extra_keys: &[Key],
) -> Result<CLValue, Error> {
const METHOD_MINT: &str = "mint";
const METHOD_CREATE: &str = "create";
const METHOD_BALANCE: &str = "balance";
const METHOD_TRANSFER: &str = "transfer";
let state = self.context.state();
let access_rights = {
let mut keys: Vec<Key> = named_keys.values().cloned().collect();
keys.extend(extra_keys);
keys.push(self.get_mint_contract().into());
keys.push(self.get_pos_contract().into());
extract_access_rights_from_keys(keys)
};
let authorization_keys = self.context.authorization_keys().to_owned();
let account = self.context.account();
let base_key = self.protocol_data().mint().into();
let blocktime = self.context.get_blocktime();
let deploy_hash = self.context.get_deploy_hash();
let gas_limit = self.context.gas_limit();
let gas_counter = self.context.gas_counter();
let hash_address_generator = self.context.hash_address_generator();
let uref_address_generator = self.context.uref_address_generator();
let correlation_id = self.context.correlation_id();
let phase = self.context.phase();
let protocol_data = self.context.protocol_data();
let mut mint_context = RuntimeContext::new(
state,
EntryPointType::Contract,
named_keys,
access_rights,
runtime_args.to_owned(),
authorization_keys,
account,
base_key,
blocktime,
deploy_hash,
gas_limit,
gas_counter,
hash_address_generator,
uref_address_generator,
protocol_version,
correlation_id,
phase,
protocol_data,
);
let ret: CLValue = match entry_point_name {
METHOD_MINT => {
let amount: U512 = Self::get_named_argument(&runtime_args, "amount")?;
let result: Result<URef, mint::Error> = mint_context.mint(amount);
CLValue::from_t(result)?
}
METHOD_CREATE => {
let uref = mint_context.mint(U512::zero()).map_err(Self::reverter)?;
CLValue::from_t(uref).map_err(Self::reverter)?
}
METHOD_BALANCE => {
let uref: URef = Self::get_named_argument(&runtime_args, "purse")?;
let maybe_balance: Option<U512> =
mint_context.balance(uref).map_err(Self::reverter)?;
CLValue::from_t(maybe_balance).map_err(Self::reverter)?
}
METHOD_TRANSFER => {
let source: URef = Self::get_named_argument(&runtime_args, "source")?;
let target: URef = Self::get_named_argument(&runtime_args, "target")?;
let amount: U512 = Self::get_named_argument(&runtime_args, "amount")?;
let result: Result<(), mint::Error> = mint_context.transfer(source, target, amount);
CLValue::from_t(result).map_err(Self::reverter)?
}
_ => CLValue::from_t(()).map_err(Self::reverter)?,
};
let urefs = extract_urefs(&ret)?;
let access_rights = extract_access_rights_from_urefs(urefs);
self.context.access_rights_extend(access_rights);
Ok(ret)
}
pub fn call_host_proof_of_stake(
&mut self,
protocol_version: ProtocolVersion,
entry_point_name: &str,
named_keys: &mut NamedKeys,
runtime_args: &RuntimeArgs,
extra_keys: &[Key],
) -> Result<CLValue, Error> {
const METHOD_BOND: &str = "bond";
const METHOD_UNBOND: &str = "unbond";
const METHOD_GET_PAYMENT_PURSE: &str = "get_payment_purse";
const METHOD_SET_REFUND_PURSE: &str = "set_refund_purse";
const METHOD_GET_REFUND_PURSE: &str = "get_refund_purse";
const METHOD_FINALIZE_PAYMENT: &str = "finalize_payment";
const ARG_AMOUNT: &str = "amount";
const ARG_PURSE: &str = "purse";
let state = self.context.state();
let access_rights = {
let mut keys: Vec<Key> = named_keys.values().cloned().collect();
keys.extend(extra_keys);
keys.push(self.get_mint_contract().into());
keys.push(self.get_pos_contract().into());
extract_access_rights_from_keys(keys)
};
let authorization_keys = self.context.authorization_keys().to_owned();
let account = self.context.account();
let base_key = self.protocol_data().proof_of_stake().into();
let blocktime = self.context.get_blocktime();
let deploy_hash = self.context.get_deploy_hash();
let gas_limit = self.context.gas_limit();
let gas_counter = self.context.gas_counter();
let fn_store_id = self.context.hash_address_generator();
let address_generator = self.context.uref_address_generator();
let correlation_id = self.context.correlation_id();
let phase = self.context.phase();
let protocol_data = self.context.protocol_data();
let runtime_context = RuntimeContext::new(
state,
EntryPointType::Contract,
named_keys,
access_rights,
runtime_args.to_owned(),
authorization_keys,
account,
base_key,
blocktime,
deploy_hash,
gas_limit,
gas_counter,
fn_store_id,
address_generator,
protocol_version,
correlation_id,
phase,
protocol_data,
);
let mut runtime = Runtime::new(
self.config,
SystemContractCache::clone(&self.system_contract_cache),
self.memory.clone(),
self.module.clone(),
runtime_context,
);
let ret: CLValue = match entry_point_name {
METHOD_BOND => {
if !self.config.enable_bonding() {
let err = Error::Revert(ApiError::Unhandled);
return Err(err);
}
let validator: AccountHash = runtime.context.get_caller();
let amount: U512 = Self::get_named_argument(&runtime_args, ARG_AMOUNT)?;
let source_uref: URef = Self::get_named_argument(&runtime_args, ARG_PURSE)?;
runtime
.bond(validator, amount, source_uref)
.map_err(Self::reverter)?;
CLValue::from_t(()).map_err(Self::reverter)?
}
METHOD_UNBOND => {
if !self.config.enable_bonding() {
let err = Error::Revert(ApiError::Unhandled);
return Err(err);
}
let validator: AccountHash = runtime.context.get_caller();
let maybe_amount: Option<U512> = Self::get_named_argument(&runtime_args, "amount")?;
runtime
.unbond(validator, maybe_amount)
.map_err(Self::reverter)?;
CLValue::from_t(()).map_err(Self::reverter)?
}
METHOD_GET_PAYMENT_PURSE => {
let rights_controlled_purse =
runtime.get_payment_purse().map_err(Self::reverter)?;
CLValue::from_t(rights_controlled_purse).map_err(Self::reverter)?
}
METHOD_SET_REFUND_PURSE => {
let purse: URef = Self::get_named_argument(&runtime_args, "purse")?;
runtime.set_refund_purse(purse).map_err(Self::reverter)?;
CLValue::from_t(()).map_err(Self::reverter)?
}
METHOD_GET_REFUND_PURSE => {
let maybe_purse = runtime.get_refund_purse().map_err(Self::reverter)?;
CLValue::from_t(maybe_purse).map_err(Self::reverter)?
}
METHOD_FINALIZE_PAYMENT => {
let amount_spent: U512 = Self::get_named_argument(&runtime_args, "amount")?;
let account: AccountHash = Self::get_named_argument(&runtime_args, "account")?;
runtime
.finalize_payment(amount_spent, account)
.map_err(Self::reverter)?;
CLValue::from_t(()).map_err(Self::reverter)?
}
_ => CLValue::from_t(()).map_err(Self::reverter)?,
};
let urefs = extract_urefs(&ret)?;
let access_rights = extract_access_rights_from_urefs(urefs);
self.context.access_rights_extend(access_rights);
Ok(ret)
}
pub fn call_host_standard_payment(&mut self) -> Result<(), Error> {
let amount: U512 = Self::get_named_argument(&self.context.args(), "amount")?;
self.pay(amount).map_err(Self::reverter)
}
pub fn call_contract(
&mut self,
contract_hash: ContractHash,
entry_point_name: &str,
args: RuntimeArgs,
) -> Result<CLValue, Error> {
let key = contract_hash.into();
let contract = match self.context.read_gs(&key)? {
Some(StoredValue::Contract(contract)) => contract,
Some(_) => {
return Err(Error::FunctionNotFound(format!(
"Value at {:?} is not a contract",
key
)));
}
None => return Err(Error::KeyNotFound(key)),
};
let entry_point = contract
.entry_point(entry_point_name)
.cloned()
.ok_or_else(|| Error::NoSuchMethod(entry_point_name.to_owned()))?;
let context_key = self.get_context_key_for_contract_call(contract_hash, &entry_point)?;
self.execute_contract(
key,
context_key,
contract,
args,
entry_point,
self.context.protocol_version(),
)
}
pub fn call_versioned_contract(
&mut self,
contract_package_hash: ContractPackageHash,
contract_version: Option<ContractVersion>,
entry_point_name: String,
args: RuntimeArgs,
) -> Result<CLValue, Error> {
let key = contract_package_hash.into();
let contract_package = match self.context.read_gs(&key)? {
Some(StoredValue::ContractPackage(contract_package)) => contract_package,
Some(_) => {
return Err(Error::FunctionNotFound(format!(
"Value at {:?} is not a versioned contract",
contract_package_hash
)));
}
None => return Err(Error::KeyNotFound(key)),
};
let contract_version_key = match contract_version {
Some(version) => {
ContractVersionKey::new(self.context.protocol_version().value().major, version)
}
None => match contract_package.current_contract_version() {
Some(v) => v,
None => return Err(Error::NoActiveContractVersions(contract_package_hash)),
},
};
let contract_hash = contract_package
.lookup_contract_hash(contract_version_key)
.cloned()
.ok_or_else(|| Error::InvalidContractVersion(contract_version_key))?;
let contract = match self.context.read_gs(&contract_hash.into())? {
Some(StoredValue::Contract(contract)) => contract,
Some(_) => {
return Err(Error::FunctionNotFound(format!(
"Value at {:?} is not a contract",
contract_package_hash
)));
}
None => return Err(Error::KeyNotFound(key)),
};
let entry_point = contract
.entry_point(&entry_point_name)
.cloned()
.ok_or_else(|| Error::NoSuchMethod(entry_point_name.to_owned()))?;
self.validate_entry_point_access(&contract_package, entry_point.access())?;
for (expected, found) in entry_point
.args()
.iter()
.map(|a| a.cl_type())
.cloned()
.zip(args.to_values().into_iter().map(|v| v.cl_type()).cloned())
{
if expected != found {
return Err(Error::type_mismatch(expected, found));
}
}
let context_key = self.get_context_key_for_contract_call(contract_hash, &entry_point)?;
self.execute_contract(
context_key,
context_key,
contract,
args,
entry_point,
self.context.protocol_version(),
)
}
fn get_context_key_for_contract_call(
&self,
contract_hash: ContractHash,
entry_point: &EntryPoint,
) -> Result<Key, Error> {
match entry_point.entry_point_type() {
EntryPointType::Session
if self.context.entry_point_type() == EntryPointType::Contract =>
{
Err(Error::InvalidContext)
}
EntryPointType::Session => {
assert_eq!(self.context.entry_point_type(), EntryPointType::Session);
Ok(self.context.base_key())
}
EntryPointType::Contract => Ok(contract_hash.into()),
}
}
pub(crate) fn access_rights_extend(
&mut self,
access_rights: HashMap<Address, HashSet<AccessRights>>,
) {
self.context.access_rights_extend(access_rights)
}
fn execute_contract(
&mut self,
key: Key,
base_key: Key,
contract: Contract,
args: RuntimeArgs,
entry_point: EntryPoint,
protocol_version: ProtocolVersion,
) -> Result<CLValue, Error> {
if !contract.is_compatible_protocol_version(protocol_version) {
return Err(Error::IncompatibleProtocolMajorVersion {
actual: contract.protocol_version().value().major,
expected: protocol_version.value().major,
});
}
let mut named_keys = match entry_point.entry_point_type() {
EntryPointType::Session => self.context.account().named_keys().clone(),
EntryPointType::Contract => contract.named_keys().clone(),
};
let extra_keys = {
let mut extra_keys = vec![];
for arg in args.to_values() {
extra_keys.extend(
extract_urefs(arg)?
.into_iter()
.map(<Key as From<URef>>::from),
);
}
for key in &extra_keys {
self.context.validate_key(key)?;
}
if !self.config.use_system_contracts() {
if self.is_mint(key) {
return self.call_host_mint(
self.context.protocol_version(),
entry_point.name(),
&mut named_keys,
&args,
&extra_keys,
);
} else if self.is_proof_of_stake(key) {
return self.call_host_proof_of_stake(
self.context.protocol_version(),
entry_point.name(),
&mut named_keys,
&args,
&extra_keys,
);
}
}
extra_keys
};
let module = {
let maybe_module = self.system_contract_cache.get(key.into_seed());
let wasm_key = contract.contract_wasm_key();
let contract_wasm: ContractWasm = match self.context.read_gs(&wasm_key)? {
Some(StoredValue::ContractWasm(contract_wasm)) => contract_wasm,
Some(_) => {
return Err(Error::FunctionNotFound(format!(
"Value at {:?} is not contract wasm",
key
)));
}
None => return Err(Error::KeyNotFound(key)),
};
match maybe_module {
Some(module) => module,
None => parity_wasm::deserialize_buffer(contract_wasm.bytes())?,
}
};
let entry_point_name = entry_point.name();
let (instance, memory) = instance_and_memory(module.clone(), protocol_version)?;
let access_rights = {
let mut keys: Vec<Key> = named_keys.values().cloned().collect();
keys.extend(extra_keys);
keys.push(self.get_mint_contract().into());
keys.push(self.get_pos_contract().into());
extract_access_rights_from_keys(keys)
};
let system_contract_cache = SystemContractCache::clone(&self.system_contract_cache);
let config = self.config;
let host_buffer = None;
let context = RuntimeContext::new(
self.context.state(),
entry_point.entry_point_type(),
&mut named_keys,
access_rights,
args,
self.context.authorization_keys().clone(),
&self.context.account(),
base_key,
self.context.get_blocktime(),
self.context.get_deploy_hash(),
self.context.gas_limit(),
self.context.gas_counter(),
self.context.hash_address_generator(),
self.context.uref_address_generator(),
protocol_version,
self.context.correlation_id(),
self.context.phase(),
self.context.protocol_data(),
);
let mut runtime = Runtime {
system_contract_cache,
config,
memory,
module,
host_buffer,
context,
};
let result = instance.invoke_export(entry_point_name, &[], &mut runtime);
self.context.set_gas_counter(runtime.context.gas_counter());
let error = match result {
Err(error) => error,
Ok(_) => {
if self.context.entry_point_type() == EntryPointType::Session
&& runtime.context.entry_point_type() == EntryPointType::Session
{
*self.context.named_keys_mut() = runtime.context.named_keys().clone();
}
return Ok(runtime.take_host_buffer().unwrap_or(CLValue::from_t(())?));
}
};
if let Some(host_error) = error.as_host_error() {
let downcasted_error = host_error.downcast_ref::<Error>().unwrap();
match downcasted_error {
Error::Ret(ref ret_urefs) => {
let ret_urefs_map: HashMap<Address, HashSet<AccessRights>> =
extract_access_rights_from_urefs(ret_urefs.clone());
self.context.access_rights_extend(ret_urefs_map);
if self.context.entry_point_type() == EntryPointType::Session
&& runtime.context.entry_point_type() == EntryPointType::Session
{
*self.context.named_keys_mut() = runtime.context.named_keys().clone();
}
return runtime.take_host_buffer().ok_or(Error::ExpectedReturnValue);
}
error => return Err(error.clone()),
}
}
Err(Error::Interpreter(error.into()))
}
fn call_contract_host_buffer(
&mut self,
contract_hash: ContractHash,
entry_point_name: &str,
args_bytes: Vec<u8>,
result_size_ptr: u32,
scoped_instrumenter: &mut ScopedInstrumenter,
) -> Result<Result<(), ApiError>, Error> {
if let Err(err) = self.check_host_buffer() {
return Ok(Err(err));
}
let args: RuntimeArgs = bytesrepr::deserialize(args_bytes)?;
scoped_instrumenter.pause();
let result = self.call_contract(contract_hash, entry_point_name, args)?;
scoped_instrumenter.unpause();
self.manage_call_contract_host_buffer(result_size_ptr, result)
}
fn call_versioned_contract_host_buffer(
&mut self,
contract_package_hash: ContractPackageHash,
contract_version: Option<ContractVersion>,
entry_point_name: String,
args_bytes: Vec<u8>,
result_size_ptr: u32,
scoped_instrumenter: &mut ScopedInstrumenter,
) -> Result<Result<(), ApiError>, Error> {
if let Err(err) = self.check_host_buffer() {
return Ok(Err(err));
}
let args: RuntimeArgs = bytesrepr::deserialize(args_bytes)?;
scoped_instrumenter.pause();
let result = self.call_versioned_contract(
contract_package_hash,
contract_version,
entry_point_name,
args,
)?;
scoped_instrumenter.unpause();
self.manage_call_contract_host_buffer(result_size_ptr, result)
}
fn check_host_buffer(&mut self) -> Result<(), ApiError> {
if !self.can_write_to_host_buffer() {
Err(ApiError::HostBufferFull)
} else {
Ok(())
}
}
fn manage_call_contract_host_buffer(
&mut self,
result_size_ptr: u32,
result: CLValue,
) -> Result<Result<(), ApiError>, Error> {
let result_size = result.inner_bytes().len() as u32;
if result_size != 0 {
if let Err(error) = self.write_host_buffer(result) {
return Ok(Err(error));
}
}
let result_size_bytes = result_size.to_le_bytes(); if let Err(error) = self.memory.set(result_size_ptr, &result_size_bytes) {
return Err(Error::Interpreter(error.into()));
}
Ok(Ok(()))
}
fn load_named_keys(
&mut self,
total_keys_ptr: u32,
result_size_ptr: u32,
scoped_instrumenter: &mut ScopedInstrumenter,
) -> Result<Result<(), ApiError>, Trap> {
scoped_instrumenter.add_property(
"names_total_length",
self.context
.named_keys()
.keys()
.map(|name| name.len())
.sum::<usize>(),
);
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let total_keys = self.context.named_keys().len() as u32;
let total_keys_bytes = total_keys.to_le_bytes();
if let Err(error) = self.memory.set(total_keys_ptr, &total_keys_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
if total_keys == 0 {
return Ok(Ok(()));
}
let named_keys =
CLValue::from_t(self.context.named_keys().clone()).map_err(Error::CLValue)?;
let length = named_keys.inner_bytes().len() as u32;
if let Err(error) = self.write_host_buffer(named_keys) {
return Ok(Err(error));
}
let length_bytes = length.to_le_bytes();
if let Err(error) = self.memory.set(result_size_ptr, &length_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
Ok(Ok(()))
}
fn create_contract_value(&mut self) -> Result<(StoredValue, URef), Error> {
let access_key = self.context.new_unit_uref()?;
let contract_package = ContractPackage::new(
access_key,
ContractVersions::default(),
DisabledVersions::default(),
Groups::default(),
);
let value = StoredValue::ContractPackage(contract_package);
Ok((value, access_key))
}
fn create_contract_package_at_hash(&mut self) -> Result<([u8; 32], [u8; 32]), Error> {
let addr = self.context.new_hash_address()?;
let key = Key::Hash(addr);
let (stored_value, access_key) = self.create_contract_value()?;
self.context.state().borrow_mut().write(key, stored_value);
Ok((addr, access_key.addr()))
}
fn create_contract_user_group(
&mut self,
contract_package_hash: ContractPackageHash,
label: String,
num_new_urefs: u32,
mut existing_urefs: BTreeSet<URef>,
output_size_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
let contract_package_key = contract_package_hash.into();
let mut contract_package: ContractPackage = self
.context
.get_validated_contract_package(contract_package_hash)?;
let groups = contract_package.groups_mut();
let new_group = Group::new(label);
if groups.get(&new_group).is_some() {
return Ok(Err(contracts::Error::GroupAlreadyExists.into()));
}
if groups.len() >= (contracts::MAX_GROUPS as usize) {
return Ok(Err(contracts::Error::MaxGroupsExceeded.into()));
}
let total_urefs: usize = groups.values().map(|urefs| urefs.len()).sum::<usize>()
+ (num_new_urefs as usize)
+ existing_urefs.len();
if total_urefs > contracts::MAX_TOTAL_UREFS {
let err = contracts::Error::MaxTotalURefsExceeded;
return Ok(Err(ApiError::ContractHeader(err as u8)));
}
let mut new_urefs = Vec::with_capacity(num_new_urefs as usize);
for _ in 0..num_new_urefs {
let u = self.context.new_unit_uref()?;
new_urefs.push(u);
}
for u in new_urefs.iter().cloned() {
existing_urefs.insert(u);
}
groups.insert(new_group, existing_urefs);
if let Err(err) = self.check_host_buffer() {
return Ok(Err(err));
}
let new_urefs_value = CLValue::from_t(new_urefs)?;
let value_size = new_urefs_value.inner_bytes().len();
if let Err(err) = self.write_host_buffer(new_urefs_value) {
return Ok(Err(err));
}
let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size_ptr, &output_size_bytes) {
return Err(Error::Interpreter(error.into()));
}
self.context.state().borrow_mut().write(
contract_package_key,
StoredValue::ContractPackage(contract_package),
);
Ok(Ok(()))
}
#[allow(clippy::too_many_arguments)]
fn add_contract_version(
&mut self,
contract_package_hash: ContractPackageHash,
entry_points: EntryPoints,
mut named_keys: NamedKeys,
output_ptr: u32,
output_size: usize,
bytes_written_ptr: u32,
version_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
let contract_package_key = contract_package_hash.into();
self.context.validate_key(&contract_package_key)?;
let mut contract_package: ContractPackage = self
.context
.get_validated_contract_package(contract_package_hash)?;
let contract_wasm_hash = self.context.new_hash_address()?;
let contract_wasm_key = Key::Hash(contract_wasm_hash);
let contract_wasm = {
let module_bytes = self.get_module_from_entry_points(&entry_points)?;
ContractWasm::new(module_bytes)
};
let contract_hash = self.context.new_hash_address()?;
let contract_key = Key::Hash(contract_hash);
let protocol_version = self.context.protocol_version();
let major = protocol_version.value().major;
if let Some(previous_contract_hash) = contract_package.current_contract_hash() {
let previous_contract: Contract =
self.context.read_gs_typed(&previous_contract_hash.into())?;
let mut previous_named_keys = previous_contract.take_named_keys();
named_keys.append(&mut previous_named_keys);
}
let contract = Contract::new(
contract_package_hash,
contract_wasm_hash,
named_keys,
entry_points,
protocol_version,
);
let insert_contract_result = contract_package.insert_contract_version(major, contract_hash);
self.context
.state()
.borrow_mut()
.write(contract_wasm_key, StoredValue::ContractWasm(contract_wasm));
self.context
.state()
.borrow_mut()
.write(contract_key, StoredValue::Contract(contract));
self.context.state().borrow_mut().write(
contract_package_key,
StoredValue::ContractPackage(contract_package),
);
{
let key_bytes = match contract_hash.to_bytes() {
Ok(bytes) => bytes,
Err(error) => return Ok(Err(error.into())),
};
if output_size < key_bytes.len() {
return Ok(Err(ApiError::BufferTooSmall));
}
if let Err(error) = self.memory.set(output_ptr, &key_bytes) {
return Err(Error::Interpreter(error.into()));
}
let bytes_size = key_bytes.len() as u32;
let size_bytes = bytes_size.to_le_bytes(); if let Err(error) = self.memory.set(bytes_written_ptr, &size_bytes) {
return Err(Error::Interpreter(error.into()));
}
let version_value: u32 = insert_contract_result.contract_version();
let version_bytes = version_value.to_le_bytes();
if let Err(error) = self.memory.set(version_ptr, &version_bytes) {
return Err(Error::Interpreter(error.into()));
}
}
Ok(Ok(()))
}
fn disable_contract_version(
&mut self,
contract_package_hash: ContractPackageHash,
contract_hash: ContractHash,
) -> Result<Result<(), ApiError>, Error> {
let contract_package_key = contract_package_hash.into();
self.context.validate_key(&contract_package_key)?;
let mut contract_package: ContractPackage = self
.context
.get_validated_contract_package(contract_package_hash)?;
if let Err(err) = contract_package.disable_contract_version(contract_hash) {
return Ok(Err(err.into()));
}
self.context.state().borrow_mut().write(
contract_package_key,
StoredValue::ContractPackage(contract_package),
);
Ok(Ok(()))
}
fn function_address(&mut self, hash_bytes: [u8; 32], dest_ptr: u32) -> Result<(), Trap> {
self.memory
.set(dest_ptr, &hash_bytes)
.map_err(|e| Error::Interpreter(e.into()).into())
}
fn new_uref(&mut self, uref_ptr: u32, value_ptr: u32, value_size: u32) -> Result<(), Trap> {
let cl_value = self.cl_value_from_mem(value_ptr, value_size)?; let uref = self.context.new_uref(StoredValue::CLValue(cl_value))?;
self.memory
.set(uref_ptr, &uref.into_bytes().map_err(Error::BytesRepr)?)
.map_err(|e| Error::Interpreter(e.into()).into())
}
fn write(
&mut self,
key_ptr: u32,
key_size: u32,
value_ptr: u32,
value_size: u32,
) -> Result<(), Trap> {
let key = self.key_from_mem(key_ptr, key_size)?;
let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
self.context
.write_gs(key, StoredValue::CLValue(cl_value))
.map_err(Into::into)
}
fn write_local(
&mut self,
key_ptr: u32,
key_size: u32,
value_ptr: u32,
value_size: u32,
) -> Result<(), Trap> {
let key_bytes = self.bytes_from_mem(key_ptr, key_size as usize)?;
let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
self.context
.write_ls(&key_bytes, cl_value)
.map_err(Into::into)
}
fn add(
&mut self,
key_ptr: u32,
key_size: u32,
value_ptr: u32,
value_size: u32,
) -> Result<(), Trap> {
let key = self.key_from_mem(key_ptr, key_size)?;
let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
self.context
.add_gs(key, StoredValue::CLValue(cl_value))
.map_err(Into::into)
}
fn read(
&mut self,
key_ptr: u32,
key_size: u32,
output_size_ptr: u32,
) -> Result<Result<(), ApiError>, Trap> {
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let key = self.key_from_mem(key_ptr, key_size)?;
let cl_value = match self.context.read_gs(&key)? {
Some(stored_value) => CLValue::try_from(stored_value).map_err(Error::TypeMismatch)?,
None => return Ok(Err(ApiError::ValueNotFound)),
};
let value_size = cl_value.inner_bytes().len() as u32;
if let Err(error) = self.write_host_buffer(cl_value) {
return Ok(Err(error));
}
let value_bytes = value_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size_ptr, &value_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
Ok(Ok(()))
}
fn read_local(
&mut self,
key_ptr: u32,
key_size: u32,
output_size_ptr: u32,
) -> Result<Result<(), ApiError>, Trap> {
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let key_bytes = self.bytes_from_mem(key_ptr, key_size as usize)?;
let cl_value = match self.context.read_ls(&key_bytes)? {
Some(cl_value) => cl_value,
None => return Ok(Err(ApiError::ValueNotFound)),
};
let value_size = cl_value.inner_bytes().len() as u32;
if let Err(error) = self.write_host_buffer(cl_value) {
return Ok(Err(error));
}
let value_bytes = value_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size_ptr, &value_bytes) {
return Err(Error::Interpreter(error.into()).into());
}
Ok(Ok(()))
}
fn revert(&mut self, status: u32) -> Trap {
Error::Revert(status.into()).into()
}
fn add_associated_key(
&mut self,
account_hash_ptr: u32,
account_hash_size: usize,
weight_value: u8,
) -> Result<i32, Trap> {
let account_hash = {
let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
let source: AccountHash =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
let weight = Weight::new(weight_value);
match self.context.add_associated_key(account_hash, weight) {
Ok(_) => Ok(0),
Err(Error::AddKeyFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
fn remove_associated_key(
&mut self,
account_hash_ptr: u32,
account_hash_size: usize,
) -> Result<i32, Trap> {
let account_hash = {
let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
let source: AccountHash =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
match self.context.remove_associated_key(account_hash) {
Ok(_) => Ok(0),
Err(Error::RemoveKeyFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
fn update_associated_key(
&mut self,
account_hash_ptr: u32,
account_hash_size: usize,
weight_value: u8,
) -> Result<i32, Trap> {
let account_hash = {
let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
let source: AccountHash =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
let weight = Weight::new(weight_value);
match self.context.update_associated_key(account_hash, weight) {
Ok(_) => Ok(0),
Err(Error::UpdateKeyFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
fn set_action_threshold(
&mut self,
action_type_value: u32,
threshold_value: u8,
) -> Result<i32, Trap> {
match ActionType::try_from(action_type_value) {
Ok(action_type) => {
let threshold = Weight::new(threshold_value);
match self.context.set_action_threshold(action_type, threshold) {
Ok(_) => Ok(0),
Err(Error::SetThresholdFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
Err(_) => Err(Trap::new(TrapKind::Unreachable)),
}
}
fn get_mint_contract(&self) -> ContractHash {
self.context.protocol_data().mint()
}
fn get_pos_contract(&self) -> ContractHash {
self.context.protocol_data().proof_of_stake()
}
fn get_standard_payment_contract(&self) -> ContractHash {
self.context.protocol_data().standard_payment()
}
fn mint_create(&mut self, mint_contract_hash: ContractHash) -> Result<URef, Error> {
let result = self.call_contract(mint_contract_hash, "create", RuntimeArgs::new())?;
let purse = result.into_t()?;
Ok(purse)
}
fn create_purse(&mut self) -> Result<URef, Error> {
self.mint_create(self.get_mint_contract())
}
fn mint_transfer(
&mut self,
mint_contract_hash: ContractHash,
source: URef,
target: URef,
amount: U512,
) -> Result<(), Error> {
const ARG_SOURCE: &str = "source";
const ARG_TARGET: &str = "target";
const ARG_AMOUNT: &str = "amount";
let args_values: RuntimeArgs = runtime_args! {
ARG_SOURCE => source,
ARG_TARGET => target,
ARG_AMOUNT => amount,
};
let result = self.call_contract(mint_contract_hash, "transfer", args_values)?;
let result: Result<(), mint::Error> = result.into_t()?;
Ok(result.map_err(system_contract_errors::Error::from)?)
}
fn transfer_to_new_account(
&mut self,
source: URef,
target: AccountHash,
amount: U512,
) -> Result<TransferResult, Error> {
let mint_contract_hash = self.get_mint_contract();
let target_key = Key::Account(target);
if amount > self.get_balance(source)?.unwrap_or_default() {
return Ok(Err(ApiError::Transfer));
}
let target_purse = self.mint_create(mint_contract_hash)?;
if source == target_purse {
return Ok(Err(ApiError::Transfer));
}
match self.mint_transfer(mint_contract_hash, source, target_purse, amount) {
Ok(_) => {
let account = Account::create(target, Default::default(), target_purse);
self.context.write_account(target_key, account)?;
Ok(Ok(TransferredTo::NewAccount))
}
Err(_) => Ok(Err(ApiError::Transfer)),
}
}
fn transfer_to_existing_account(
&mut self,
source: URef,
target: URef,
amount: U512,
) -> Result<TransferResult, Error> {
let mint_contract_key = self.get_mint_contract();
self.context.insert_uref(target);
match self.mint_transfer(mint_contract_key, source, target, amount) {
Ok(_) => Ok(Ok(TransferredTo::ExistingAccount)),
Err(_) => Ok(Err(ApiError::Transfer)),
}
}
fn transfer_to_account(
&mut self,
target: AccountHash,
amount: U512,
) -> Result<TransferResult, Error> {
let source = self.context.get_main_purse()?;
self.transfer_from_purse_to_account(source, target, amount)
}
fn transfer_from_purse_to_account(
&mut self,
source: URef,
target: AccountHash,
amount: U512,
) -> Result<TransferResult, Error> {
let target_key = Key::Account(target);
match self.context.read_account(&target_key)? {
None => {
self.transfer_to_new_account(source, target, amount)
}
Some(StoredValue::Account(account)) => {
let target = account.main_purse_add_only();
if source == target {
return Ok(Ok(TransferredTo::ExistingAccount));
}
self.transfer_to_existing_account(source, target, amount)
}
Some(_) => {
Err(Error::AccountNotFound(target_key))
}
}
}
fn transfer_from_purse_to_purse(
&mut self,
source_ptr: u32,
source_size: u32,
target_ptr: u32,
target_size: u32,
amount_ptr: u32,
amount_size: u32,
) -> Result<Result<(), ApiError>, Error> {
let source: URef = {
let bytes = self.bytes_from_mem(source_ptr, source_size as usize)?;
bytesrepr::deserialize(bytes).map_err(Error::BytesRepr)?
};
let target: URef = {
let bytes = self.bytes_from_mem(target_ptr, target_size as usize)?;
bytesrepr::deserialize(bytes).map_err(Error::BytesRepr)?
};
let amount: U512 = {
let bytes = self.bytes_from_mem(amount_ptr, amount_size as usize)?;
bytesrepr::deserialize(bytes).map_err(Error::BytesRepr)?
};
let mint_contract_key = self.get_mint_contract();
if self
.mint_transfer(mint_contract_key, source, target, amount)
.is_ok()
{
Ok(Ok(()))
} else {
Ok(Err(ApiError::Transfer))
}
}
fn get_balance(&mut self, purse: URef) -> Result<Option<U512>, Error> {
let key = purse.addr();
let uref_key = match self.context.read_ls(&key)? {
Some(cl_value) => {
let key: Key = cl_value.into_t().expect("expected Key type");
match key {
Key::URef(_) => (),
_ => panic!("expected Key::Uref(_)"),
}
key
}
None => return Ok(None),
};
let ret = match self.context.read_gs_direct(&uref_key)? {
Some(StoredValue::CLValue(cl_value)) => {
if *cl_value.cl_type() == CLType::U512 {
let balance: U512 = cl_value.into_t()?;
Some(balance)
} else {
panic!("expected U512")
}
}
Some(_) => panic!("expected U512"),
None => None,
};
Ok(ret)
}
fn get_balance_host_buffer(
&mut self,
purse_ptr: u32,
purse_size: usize,
output_size_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let purse: URef = {
let bytes = self.bytes_from_mem(purse_ptr, purse_size)?;
match bytesrepr::deserialize(bytes) {
Ok(purse) => purse,
Err(error) => return Ok(Err(error.into())),
}
};
let balance = match self.get_balance(purse)? {
Some(balance) => balance,
None => return Ok(Err(ApiError::InvalidPurse)),
};
let balance_cl_value = match CLValue::from_t(balance) {
Ok(cl_value) => cl_value,
Err(error) => return Ok(Err(error.into())),
};
let balance_size = balance_cl_value.inner_bytes().len() as i32;
if let Err(error) = self.write_host_buffer(balance_cl_value) {
return Ok(Err(error));
}
let balance_size_bytes = balance_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size_ptr, &balance_size_bytes) {
return Err(Error::Interpreter(error.into()));
}
Ok(Ok(()))
}
fn get_system_contract(
&mut self,
system_contract_index: u32,
dest_ptr: u32,
_dest_size: u32,
) -> Result<Result<(), ApiError>, Trap> {
let contract_hash: ContractHash = match SystemContractType::try_from(system_contract_index)
{
Ok(SystemContractType::Mint) => self.get_mint_contract(),
Ok(SystemContractType::ProofOfStake) => self.get_pos_contract(),
Ok(SystemContractType::StandardPayment) => self.get_standard_payment_contract(),
Err(error) => return Ok(Err(error)),
};
match self.memory.set(dest_ptr, &contract_hash) {
Ok(_) => Ok(Ok(())),
Err(error) => Err(Error::Interpreter(error.into()).into()),
}
}
pub fn take_host_buffer(&mut self) -> Option<CLValue> {
self.host_buffer.take()
}
fn can_write_to_host_buffer(&self) -> bool {
self.host_buffer.is_none()
}
fn write_host_buffer(&mut self, data: CLValue) -> Result<(), ApiError> {
match self.host_buffer {
Some(_) => return Err(ApiError::HostBufferFull),
None => self.host_buffer = Some(data),
}
Ok(())
}
fn read_host_buffer(
&mut self,
dest_ptr: u32,
dest_size: usize,
bytes_written_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
let (_cl_type, serialized_value) = match self.take_host_buffer() {
None => return Ok(Err(ApiError::HostBufferEmpty)),
Some(cl_value) => cl_value.destructure(),
};
if serialized_value.len() > u32::max_value() as usize {
return Ok(Err(ApiError::OutOfMemory));
}
if serialized_value.len() > dest_size {
return Ok(Err(ApiError::BufferTooSmall));
}
let sliced_buf = &serialized_value[..cmp::min(dest_size, serialized_value.len())];
if let Err(error) = self.memory.set(dest_ptr, sliced_buf) {
return Err(Error::Interpreter(error.into()));
}
let bytes_written = sliced_buf.len() as u32;
let bytes_written_data = bytes_written.to_le_bytes();
if let Err(error) = self.memory.set(bytes_written_ptr, &bytes_written_data) {
return Err(Error::Interpreter(error.into()));
}
Ok(Ok(()))
}
#[cfg(feature = "test-support")]
fn print(&mut self, text_ptr: u32, text_size: u32) -> Result<(), Trap> {
let text = self.string_from_mem(text_ptr, text_size)?;
println!("{}", text);
Ok(())
}
fn get_named_arg_size(
&mut self,
name_ptr: u32,
name_size: usize,
size_ptr: u32,
) -> Result<Result<(), ApiError>, Trap> {
let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
let name = String::from_utf8_lossy(&name_bytes);
let arg_size = match self.context.args().get(&name) {
Some(arg) if arg.inner_bytes().len() > u32::max_value() as usize => {
return Ok(Err(ApiError::OutOfMemory));
}
Some(arg) => arg.inner_bytes().len() as u32,
None => return Ok(Err(ApiError::MissingArgument)),
};
let arg_size_bytes = arg_size.to_le_bytes();
if let Err(e) = self.memory.set(size_ptr, &arg_size_bytes) {
return Err(Error::Interpreter(e.into()).into());
}
Ok(Ok(()))
}
fn get_named_arg(
&mut self,
name_ptr: u32,
name_size: usize,
output_ptr: u32,
output_size: usize,
) -> Result<Result<(), ApiError>, Trap> {
let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
let name = String::from_utf8_lossy(&name_bytes);
let arg = match self.context.args().get(&name) {
Some(arg) => arg,
None => return Ok(Err(ApiError::MissingArgument)),
};
if arg.inner_bytes().len() > output_size {
return Ok(Err(ApiError::OutOfMemory));
}
if let Err(e) = self
.memory
.set(output_ptr, &arg.inner_bytes()[..output_size])
{
return Err(Error::Interpreter(e.into()).into());
}
Ok(Ok(()))
}
fn validate_entry_point_access(
&self,
package: &ContractPackage,
access: &EntryPointAccess,
) -> Result<(), Error> {
runtime_context::validate_entry_point_access_with(package, access, |uref| {
self.context.validate_uref(uref).is_ok()
})
}
fn remove_contract_user_group(
&mut self,
package_key: ContractPackageHash,
label: Group,
) -> Result<Result<(), ApiError>, Error> {
let mut package: ContractPackage =
self.context.get_validated_contract_package(package_key)?;
let group_to_remove = Group::new(label);
let groups = package.groups_mut();
if groups.get(&group_to_remove).is_none() {
return Ok(Err(contracts::Error::GroupDoesNotExist.into()));
}
let versions = package.versions();
for contract_hash in versions.values() {
let entry_points = {
let contract: Contract = self.context.read_gs_typed(&Key::from(*contract_hash))?;
contract.entry_points().clone().take_entry_points()
};
for entry_point in entry_points {
match entry_point.access() {
EntryPointAccess::Public => {
continue;
}
EntryPointAccess::Groups(groups) => {
if groups.contains(&group_to_remove) {
return Ok(Err(contracts::Error::GroupInUse.into()));
}
}
}
}
}
if !package.remove_group(&group_to_remove) {
return Ok(Err(contracts::Error::GroupInUse.into()));
}
self.context.state().borrow_mut().write(
Key::from(package_key),
StoredValue::ContractPackage(package),
);
Ok(Ok(()))
}
#[allow(clippy::too_many_arguments)]
fn provision_contract_user_group_uref(
&mut self,
package_ptr: u32,
package_size: u32,
label_ptr: u32,
label_size: u32,
output_size_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
let contract_package_hash = self.t_from_mem(package_ptr, package_size)?;
let label: String = self.t_from_mem(label_ptr, label_size)?;
let mut contract_package = self
.context
.get_validated_contract_package(contract_package_hash)?;
let groups = contract_package.groups_mut();
let group_label = Group::new(label);
let total_urefs: usize = groups.values().map(|urefs| urefs.len()).sum();
if total_urefs + 1 > contracts::MAX_TOTAL_UREFS {
return Ok(Err(contracts::Error::MaxTotalURefsExceeded.into()));
}
let group = match groups.get_mut(&group_label) {
Some(group) if group.len() + 1 > contracts::MAX_GROUPS as usize => {
return Ok(Err(contracts::Error::MaxTotalURefsExceeded.into()));
}
Some(group) => group,
None => return Ok(Err(contracts::Error::GroupDoesNotExist.into())),
};
let new_uref = self.context.new_unit_uref()?;
if !group.insert(new_uref) {
return Ok(Err(contracts::Error::URefAlreadyExists.into()));
}
if let Err(err) = self.check_host_buffer() {
return Ok(Err(err));
}
let new_uref_value = CLValue::from_t(new_uref)?;
let value_size = new_uref_value.inner_bytes().len();
if let Err(err) = self.write_host_buffer(new_uref_value) {
return Ok(Err(err));
}
let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self.memory.set(output_size_ptr, &output_size_bytes) {
return Err(Error::Interpreter(error.into()));
}
self.context.state().borrow_mut().write(
Key::from(contract_package_hash),
StoredValue::ContractPackage(contract_package),
);
Ok(Ok(()))
}
#[allow(clippy::too_many_arguments)]
fn remove_contract_user_group_urefs(
&mut self,
package_ptr: u32,
package_size: u32,
label_ptr: u32,
label_size: u32,
urefs_ptr: u32,
urefs_size: u32,
) -> Result<Result<(), ApiError>, Error> {
let contract_package_hash: ContractPackageHash =
self.t_from_mem(package_ptr, package_size)?;
let label: String = self.t_from_mem(label_ptr, label_size)?;
let urefs: BTreeSet<URef> = self.t_from_mem(urefs_ptr, urefs_size)?;
let mut contract_package = self
.context
.get_validated_contract_package(contract_package_hash)?;
let groups = contract_package.groups_mut();
let group_label = Group::new(label);
let group = match groups.get_mut(&group_label) {
Some(group) => group,
None => return Ok(Err(contracts::Error::GroupDoesNotExist.into())),
};
if urefs.is_empty() {
return Ok(Ok(()));
}
for uref in urefs {
if !group.remove(&uref) {
return Ok(Err(contracts::Error::UnableToRemoveURef.into()));
}
}
self.context.state().borrow_mut().write(
Key::from(contract_package_hash),
StoredValue::ContractPackage(contract_package),
);
Ok(Ok(()))
}
}
#[cfg(test)]
mod tests {
use proptest::{
array,
collection::{btree_map, vec},
option,
prelude::*,
result,
};
use types::{gens::*, CLType, CLValue, Key, URef};
use super::extract_urefs;
fn cl_value_with_urefs_arb() -> impl Strategy<Value = (CLValue, Vec<URef>)> {
let stub: Option<CLType> = None;
if let Some(cl_type) = stub {
match cl_type {
CLType::Bool
| CLType::I32
| CLType::I64
| CLType::U8
| CLType::U32
| CLType::U64
| CLType::U128
| CLType::U256
| CLType::U512
| CLType::Unit
| CLType::String
| CLType::Key
| CLType::URef
| CLType::Option(_)
| CLType::List(_)
| CLType::FixedList(..)
| CLType::Result { .. }
| CLType::Map { .. }
| CLType::Tuple1(_)
| CLType::Tuple2(_)
| CLType::Tuple3(_)
| CLType::Any => (),
}
};
prop_oneof![
Just((CLValue::from_t(()).expect("should create CLValue"), vec![])),
any::<bool>()
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
any::<i32>().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
any::<i64>().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
any::<u8>().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
any::<u32>().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
any::<u64>().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
u128_arb().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
u256_arb().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
u512_arb().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
key_arb().prop_map(|x| {
let urefs = x.as_uref().into_iter().cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
uref_arb().prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![x])),
".*".prop_map(|x: String| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
option::of(any::<u64>())
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
option::of(uref_arb()).prop_map(|x| {
let urefs = x.iter().cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
option::of(key_arb()).prop_map(|x| {
let urefs = x.iter().filter_map(Key::as_uref).cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
vec(any::<i32>(), 0..100)
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
vec(uref_arb(), 0..100).prop_map(|x| (
CLValue::from_t(x.clone()).expect("should create CLValue"),
x
)),
vec(key_arb(), 0..100).prop_map(|x| (
CLValue::from_t(x.clone()).expect("should create CLValue"),
x.into_iter().filter_map(Key::into_uref).collect()
)),
[any::<u64>(); 32]
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
array::uniform8(uref_arb()).prop_map(|x| {
let urefs = x.to_vec();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
array::uniform8(key_arb()).prop_map(|x| {
let urefs = x.iter().filter_map(Key::as_uref).cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
result::maybe_err(key_arb(), ".*").prop_map(|x| {
let urefs = match &x {
Ok(key) => key.as_uref().into_iter().cloned().collect(),
Err(_) => vec![],
};
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
result::maybe_ok(".*", uref_arb()).prop_map(|x| {
let urefs = match &x {
Ok(_) => vec![],
Err(uref) => vec![*uref],
};
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
btree_map(".*", u512_arb(), 0..100)
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
btree_map(uref_arb(), u512_arb(), 0..100).prop_map(|x| {
let urefs = x.keys().cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
btree_map(".*", uref_arb(), 0..100).prop_map(|x| {
let urefs = x.values().cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
btree_map(uref_arb(), key_arb(), 0..100).prop_map(|x| {
let mut urefs: Vec<URef> = x.keys().cloned().collect();
urefs.extend(x.values().filter_map(Key::as_uref).cloned());
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
(any::<bool>())
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
(uref_arb())
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![x])),
(any::<bool>(), any::<i32>())
.prop_map(|x| (CLValue::from_t(x).expect("should create CLValue"), vec![])),
(uref_arb(), any::<i32>()).prop_map(|x| {
let uref = x.0;
(
CLValue::from_t(x).expect("should create CLValue"),
vec![uref],
)
}),
(any::<i32>(), key_arb()).prop_map(|x| {
let urefs = x.1.as_uref().into_iter().cloned().collect();
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
(uref_arb(), key_arb()).prop_map(|x| {
let mut urefs = vec![x.0];
urefs.extend(x.1.as_uref().into_iter().cloned());
(CLValue::from_t(x).expect("should create CLValue"), urefs)
}),
]
}
proptest! {
#[test]
fn should_extract_urefs((cl_value, urefs) in cl_value_with_urefs_arb()) {
let extracted_urefs = extract_urefs(&cl_value).unwrap();
assert_eq!(extracted_urefs, urefs);
}
}
}