mod args;
mod externals;
mod mint_internal;
mod proof_of_stake_internal;
mod standard_payment_internal;
use std::{
cmp,
collections::{BTreeMap, 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 contract::args_parser::ArgsParser;
use engine_shared::{account::Account, contract::Contract, 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::{ActionType, PublicKey, Weight},
bytesrepr::{self, FromBytes, ToBytes},
system_contract_errors,
system_contract_errors::mint,
AccessRights, ApiError, CLType, CLTyped, CLValue, Key, ProtocolVersion, SystemContractType,
TransferResult, TransferredTo, URef, U128, U256, U512,
};
use crate::{
engine_state::{system_contract_cache::SystemContractCache, EngineConfig},
execution::{Error, MINT_NAME, POS_NAME},
resolvers::{create_module_resolver, memory_resolver::MemoryResolver},
runtime_context::RuntimeContext,
Address,
};
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,
Key::Local { .. } => 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: BTreeMap<String, Key> = 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 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_function_by_name(&mut self, name_ptr: u32, name_size: u32) -> Result<Vec<u8>, Trap> {
let name = self.string_from_mem(name_ptr, name_size)?;
let has_name: bool = self
.module
.export_section()
.and_then(|export_section| {
export_section
.entries()
.iter()
.find(|export_entry| export_entry.field() == name)
})
.is_some();
if has_name {
let mut module = self.module.clone();
pwasm_utils::optimize(&mut module, vec![&name]).unwrap();
rename_export_to_call(&mut module, name);
parity_wasm::serialize(module).map_err(|e| Error::ParityWasm(e).into())
} else {
Err(Error::FunctionNotFound(name).into())
}
}
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 get_arg_size(&mut self, index: usize, size_ptr: u32) -> Result<Result<(), ApiError>, Trap> {
let arg_size = match self.context.args().get(index) {
Some(arg) if arg.inner_bytes().len() > u32::max_value() as usize => {
return Ok(Err(ApiError::OutOfMemory))
}
None => return Ok(Err(ApiError::MissingArgument)),
Some(arg) => arg.inner_bytes().len() as u32,
};
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());
}
Ok(Ok(()))
}
fn get_arg(
&mut self,
index: usize,
output_ptr: u32,
output_size: usize,
) -> Result<Result<(), ApiError>, Trap> {
let arg = match self.context.args().get(index) {
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());
}
Ok(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());
}
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());
}
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())
}
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());
}
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())
}
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())
}
fn ret(&mut self, value_ptr: u32, value_size: usize) -> Trap {
self.host_buffer = None;
let mem_get = self
.memory
.get(value_ptr, value_size)
.map_err(Error::Interpreter);
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) => Error::Ret(urefs).into(),
Err(e) => e.into(),
}
}
Err(e) => e.into(),
}
}
pub fn is_mint(&self, key: Key) -> bool {
match key {
Key::URef(uref) if self.protocol_data().mint().addr() == uref.addr() => true,
_ => false,
}
}
pub fn is_proof_of_stake(&self, key: Key) -> bool {
match key {
Key::URef(uref) if self.protocol_data().proof_of_stake().addr() == uref.addr() => true,
_ => false,
}
}
fn get_argument<T: FromBytes + CLTyped>(args: &[CLValue], index: usize) -> Result<T, Error> {
let arg: CLValue = args
.get(index)
.cloned()
.ok_or_else(|| Error::Revert(ApiError::MissingArgument.into()))?;
arg.into_t()
.map_err(|_| Error::Revert(ApiError::InvalidArgument.into()))
}
fn reverter<T: Into<ApiError>>(error: T) -> Error {
let api_error: ApiError = error.into();
Error::Revert(api_error.into())
}
pub fn call_host_mint(
&mut self,
protocol_version: ProtocolVersion,
mut named_keys: BTreeMap<String, Key>,
args: &[CLValue],
extra_urefs: &[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_urefs);
keys.push(self.get_mint_contract_uref().into());
keys.push(self.get_pos_contract_uref().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_deployhash();
let gas_limit = self.context.gas_limit();
let gas_counter = self.context.gas_counter();
let fn_store_id = self.context.fn_store_id();
let address_generator = self.context.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,
&mut named_keys,
access_rights,
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 method_name: String = Self::get_argument(&args, 0)?;
let ret: CLValue = match method_name.as_str() {
METHOD_MINT => {
let amount: U512 = Self::get_argument(&args, 1)?;
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_argument(&args, 1)?;
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_argument(&args, 1)?;
let target: URef = Self::get_argument(&args, 2)?;
let amount: U512 = Self::get_argument(&args, 3)?;
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,
mut named_keys: BTreeMap<String, Key>,
args: &[CLValue],
extra_urefs: &[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";
let state = self.context.state();
let access_rights = {
let mut keys: Vec<Key> = named_keys.values().cloned().collect();
keys.extend(extra_urefs);
keys.push(self.get_mint_contract_uref().into());
keys.push(self.get_pos_contract_uref().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_deployhash();
let gas_limit = self.context.gas_limit();
let gas_counter = self.context.gas_counter();
let fn_store_id = self.context.fn_store_id();
let address_generator = self.context.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,
&mut named_keys,
access_rights,
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 method_name: String = Self::get_argument(&args, 0)?;
let ret: CLValue = match method_name.as_str() {
METHOD_BOND => {
if self.config.highway() {
let err = Error::Revert(ApiError::Unhandled.into());
return Err(err);
}
let validator: PublicKey = runtime.context.get_caller();
let amount: U512 = Self::get_argument(&args, 1)?;
let source_uref: URef = Self::get_argument(&args, 2)?;
runtime
.bond(validator, amount, source_uref)
.map_err(Self::reverter)?;
CLValue::from_t(()).map_err(Self::reverter)?
}
METHOD_UNBOND => {
if self.config.highway() {
let err = Error::Revert(ApiError::Unhandled.into());
return Err(err);
}
let validator: PublicKey = runtime.context.get_caller();
let maybe_amount: Option<U512> = Self::get_argument(&args, 1)?;
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_argument(&args, 1)?;
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_argument(&args, 1)?;
let account: PublicKey = Self::get_argument(&args, 2)?;
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 first_arg = match self.context.args().first() {
Some(cl_value) => cl_value.clone(),
None => return Err(Error::InvalidContext),
};
let amount = first_arg.into_t()?;
self.pay(amount).map_err(Self::reverter)
}
pub fn call_contract(&mut self, key: Key, args_bytes: Vec<u8>) -> Result<CLValue, Error> {
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 contract_version = contract.protocol_version();
let current_version = self.context.protocol_version();
if !contract_version.is_compatible_with(¤t_version) {
return Err(Error::IncompatibleProtocolMajorVersion {
actual: current_version.value().major,
expected: contract_version.value().major,
});
}
let args: Vec<CLValue> = bytesrepr::deserialize(args_bytes)?;
let mut extra_urefs = vec![];
for arg in &args {
extra_urefs.extend(
extract_urefs(arg)?
.into_iter()
.map(<Key as From<URef>>::from),
);
}
for key in &extra_urefs {
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(),
contract.take_named_keys(),
&args,
&extra_urefs,
);
} else if self.is_proof_of_stake(key) {
return self.call_host_proof_of_stake(
self.context.protocol_version(),
contract.take_named_keys(),
&args,
&extra_urefs,
);
}
}
let maybe_module = match key {
Key::URef(uref) => self.system_contract_cache.get(&uref),
_ => None,
};
let module = match maybe_module {
Some(module) => module,
None => parity_wasm::deserialize_buffer(contract.bytes())?,
};
let mut named_keys = contract.take_named_keys();
let (instance, memory) = instance_and_memory(module.clone(), contract_version)?;
let access_rights = {
let mut keys: Vec<Key> = named_keys.values().cloned().collect();
keys.extend(extra_urefs);
keys.push(self.get_mint_contract_uref().into());
keys.push(self.get_pos_contract_uref().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(),
&mut named_keys,
access_rights,
args,
self.context.authorization_keys().clone(),
&self.context.account(),
key,
self.context.get_blocktime(),
self.context.get_deployhash(),
self.context.gas_limit(),
self.context.gas_counter(),
self.context.fn_store_id(),
self.context.address_generator(),
contract_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("call", &[], &mut runtime);
self.context.set_gas_counter(runtime.context.gas_counter());
let error = match result {
Err(error) => error,
Ok(_) => 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);
return runtime.take_host_buffer().ok_or(Error::ExpectedReturnValue);
}
Error::Revert(status) => {
return Err(Error::Revert(*status));
}
Error::InvalidContext => {
return Err(Error::InvalidContext);
}
_ => {}
}
}
Err(Error::Interpreter(error))
}
fn call_contract_host_buffer(
&mut self,
key: Key,
args_bytes: Vec<u8>,
result_size_ptr: u32,
) -> Result<Result<(), ApiError>, Error> {
if !self.can_write_to_host_buffer() {
return Ok(Err(ApiError::HostBufferFull));
}
let result = self.call_contract(key, args_bytes)?;
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));
}
Ok(Ok(()))
}
fn load_named_keys(
&mut self,
total_keys_ptr: u32,
result_size_ptr: u32,
) -> Result<Result<(), ApiError>, Trap> {
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());
}
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());
}
Ok(Ok(()))
}
fn store_function(
&mut self,
fn_bytes: Vec<u8>,
named_keys: BTreeMap<String, Key>,
) -> Result<[u8; 32], Error> {
let contract = Contract::new(fn_bytes, named_keys, self.context.protocol_version());
let contract_addr = self
.context
.store_function(StoredValue::Contract(contract))?;
Ok(contract_addr)
}
fn store_function_at_hash(
&mut self,
fn_bytes: Vec<u8>,
named_keys: BTreeMap<String, Key>,
) -> Result<[u8; 32], Error> {
let contract = Contract::new(fn_bytes, named_keys, self.context.protocol_version());
let new_hash = self
.context
.store_function_at_hash(StoredValue::Contract(contract))?;
Ok(new_hash)
}
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())
}
fn new_uref(&mut self, key_ptr: u32, value_ptr: u32, value_size: u32) -> Result<(), Trap> {
let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
let key = self.context.new_uref(StoredValue::CLValue(cl_value))?;
self.memory
.set(key_ptr, &key.into_bytes().map_err(Error::BytesRepr)?)
.map_err(|e| Error::Interpreter(e).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)
}
pub fn add_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
.add_ls(&key_bytes, 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());
}
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());
}
Ok(Ok(()))
}
fn revert(&mut self, status: u32) -> Trap {
Error::Revert(status).into()
}
fn add_associated_key(
&mut self,
public_key_ptr: u32,
public_key_size: usize,
weight_value: u8,
) -> Result<i32, Trap> {
let public_key = {
let source_serialized = self.bytes_from_mem(public_key_ptr, public_key_size)?;
let source: PublicKey =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
let weight = Weight::new(weight_value);
match self.context.add_associated_key(public_key, weight) {
Ok(_) => Ok(0),
Err(Error::AddKeyFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
fn remove_associated_key(
&mut self,
public_key_ptr: u32,
public_key_size: usize,
) -> Result<i32, Trap> {
let public_key = {
let source_serialized = self.bytes_from_mem(public_key_ptr, public_key_size)?;
let source: PublicKey =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
match self.context.remove_associated_key(public_key) {
Ok(_) => Ok(0),
Err(Error::RemoveKeyFailure(e)) => Ok(e as i32),
Err(e) => Err(e.into()),
}
}
fn update_associated_key(
&mut self,
public_key_ptr: u32,
public_key_size: usize,
weight_value: u8,
) -> Result<i32, Trap> {
let public_key = {
let source_serialized = self.bytes_from_mem(public_key_ptr, public_key_size)?;
let source: PublicKey =
bytesrepr::deserialize(source_serialized).map_err(Error::BytesRepr)?;
source
};
let weight = Weight::new(weight_value);
match self.context.update_associated_key(public_key, 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_uref(&self) -> URef {
let mint = self.context.protocol_data().mint();
self.context.attenuate_uref(mint)
}
fn get_pos_contract_uref(&self) -> URef {
let pos = self.context.protocol_data().proof_of_stake();
self.context.attenuate_uref(pos)
}
fn get_standard_payment_contract_uref(&self) -> URef {
let standard_payment = self.context.protocol_data().standard_payment();
self.context.attenuate_uref(standard_payment)
}
fn mint_create(&mut self, mint_contract_key: Key) -> Result<URef, Error> {
let args_bytes = {
let args = ("create",);
ArgsParser::parse(args)?.into_bytes()?
};
let result = self.call_contract(mint_contract_key, args_bytes)?;
let purse = result.into_t()?;
Ok(purse)
}
fn create_purse(&mut self) -> Result<URef, Error> {
let mint_contract_key = self.get_mint_contract_uref().into();
self.mint_create(mint_contract_key)
}
fn mint_transfer(
&mut self,
mint_contract_key: Key,
source: URef,
target: URef,
amount: U512,
) -> Result<(), Error> {
let args_bytes = {
let args = ("transfer", source, target, amount);
ArgsParser::parse(args)?.into_bytes()?
};
let result = self.call_contract(mint_contract_key, args_bytes)?;
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: PublicKey,
amount: U512,
) -> Result<TransferResult, Error> {
let mint_contract_key = self.get_mint_contract_uref().into();
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_key)?;
if source == target_purse {
return Ok(Err(ApiError::Transfer));
}
match self.mint_transfer(mint_contract_key, source, target_purse, amount) {
Ok(_) => {
let named_keys = vec![
(
String::from(MINT_NAME),
Key::from(self.get_mint_contract_uref()),
),
(
String::from(POS_NAME),
Key::from(self.get_pos_contract_uref()),
),
]
.into_iter()
.map(|(name, key)| {
if let Some(uref) = key.as_uref() {
(name, Key::URef(URef::new(uref.addr(), AccessRights::READ)))
} else {
(name, key)
}
})
.collect();
let account = Account::create(target, named_keys, 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_uref().into();
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: PublicKey,
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: PublicKey,
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_uref().into();
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 seed = self.get_mint_contract_uref().addr();
let key = purse.addr().into_bytes()?;
let uref_key = match self.context.read_ls_with_seed(seed, &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));
}
Ok(Ok(()))
}
fn upgrade_contract_at_uref(
&mut self,
name_ptr: u32,
name_size: u32,
key_ptr: u32,
key_size: u32,
) -> Result<Result<(), ApiError>, Trap> {
let key = self.key_from_mem(key_ptr, key_size)?;
let named_keys = match self.context.read_gs(&key)? {
None => Err(Error::KeyNotFound(key)),
Some(StoredValue::Contract(contract)) => Ok(contract.named_keys().clone()),
Some(_) => Err(Error::FunctionNotFound(format!(
"Value at {:?} is not a contract",
key
))),
}?;
let bytes = self.get_function_by_name(name_ptr, name_size)?;
match self
.context
.upgrade_contract_at_uref(key, bytes, named_keys)
{
Ok(_) => Ok(Ok(())),
Err(_) => Ok(Err(ApiError::UpgradeContractAtURef)),
}
}
fn get_system_contract(
&mut self,
system_contract_index: u32,
dest_ptr: u32,
_dest_size: u32,
) -> Result<Result<(), ApiError>, Trap> {
let attenuated_uref = match SystemContractType::try_from(system_contract_index) {
Ok(SystemContractType::Mint) => self.get_mint_contract_uref(),
Ok(SystemContractType::ProofOfStake) => self.get_pos_contract_uref(),
Ok(SystemContractType::StandardPayment) => self.get_standard_payment_contract_uref(),
Err(error) => return Ok(Err(error)),
};
let attenuated_uref_bytes = attenuated_uref.into_bytes().map_err(Error::BytesRepr)?;
match self.memory.set(dest_ptr, &attenuated_uref_bytes) {
Ok(_) => Ok(Ok(())),
Err(error) => Err(Error::Interpreter(error).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));
}
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));
}
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);
}
}
}