use std::{
cell::RefCell,
collections::{BTreeSet, HashMap, HashSet},
convert::{TryFrom, TryInto},
fmt::Debug,
rc::Rc,
};
use blake2::{
digest::{Update, VariableOutput},
VarBlake2b,
};
use casper_types::{
account::{
AccountHash, ActionType, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
UpdateKeyFailure, Weight,
},
bytesrepr,
bytesrepr::ToBytes,
contracts::NamedKeys,
AccessRights, BlockTime, CLType, CLValue, Contract, ContractPackage, ContractPackageHash,
DeployHash, DeployInfo, EntryPointAccess, EntryPointType, Key, Phase, ProtocolVersion,
RuntimeArgs, Transfer, TransferAddr, URef, KEY_HASH_LENGTH,
};
use crate::{
core::{
engine_state::execution_effect::ExecutionEffect,
execution::{AddressGenerator, Error},
tracking_copy::{AddResult, TrackingCopy},
Address,
},
shared::{account::Account, gas::Gas, newtypes::CorrelationId, stored_value::StoredValue},
storage::{global_state::StateReader, protocol_data::ProtocolData},
};
#[cfg(test)]
mod tests;
pub(crate) fn uref_has_access_rights(
uref: &URef,
access_rights: &HashMap<Address, HashSet<AccessRights>>,
) -> bool {
if let Some(known_rights) = access_rights.get(&uref.addr()) {
let new_rights = uref.access_rights();
known_rights
.iter()
.any(|right| *right & new_rights == new_rights)
} else {
false
}
}
pub fn validate_entry_point_access_with(
contract_package: &ContractPackage,
access: &EntryPointAccess,
validator: impl Fn(&URef) -> bool,
) -> Result<(), Error> {
if let EntryPointAccess::Groups(groups) = access {
if groups.is_empty() {
return Err(Error::InvalidContext);
}
let find_result = groups.iter().find(|g| {
contract_package
.groups()
.get(g)
.and_then(|set| set.iter().find(|u| validator(u)))
.is_some()
});
if find_result.is_none() {
return Err(Error::InvalidContext);
}
}
Ok(())
}
pub struct RuntimeContext<'a, R> {
tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
named_keys: &'a mut NamedKeys,
access_rights: HashMap<Address, HashSet<AccessRights>>,
account: &'a Account,
args: RuntimeArgs,
authorization_keys: BTreeSet<AccountHash>,
base_key: Key,
blocktime: BlockTime,
deploy_hash: DeployHash,
gas_limit: Gas,
gas_counter: Gas,
hash_address_generator: Rc<RefCell<AddressGenerator>>,
uref_address_generator: Rc<RefCell<AddressGenerator>>,
transfer_address_generator: Rc<RefCell<AddressGenerator>>,
protocol_version: ProtocolVersion,
correlation_id: CorrelationId,
phase: Phase,
protocol_data: ProtocolData,
entry_point_type: EntryPointType,
transfers: Vec<TransferAddr>,
}
impl<'a, R> RuntimeContext<'a, R>
where
R: StateReader<Key, StoredValue>,
R::Error: Into<Error>,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
entry_point_type: EntryPointType,
named_keys: &'a mut NamedKeys,
access_rights: HashMap<Address, HashSet<AccessRights>>,
runtime_args: RuntimeArgs,
authorization_keys: BTreeSet<AccountHash>,
account: &'a Account,
base_key: Key,
blocktime: BlockTime,
deploy_hash: DeployHash,
gas_limit: Gas,
gas_counter: Gas,
hash_address_generator: Rc<RefCell<AddressGenerator>>,
uref_address_generator: Rc<RefCell<AddressGenerator>>,
transfer_address_generator: Rc<RefCell<AddressGenerator>>,
protocol_version: ProtocolVersion,
correlation_id: CorrelationId,
phase: Phase,
protocol_data: ProtocolData,
transfers: Vec<TransferAddr>,
) -> Self {
RuntimeContext {
tracking_copy,
entry_point_type,
named_keys,
access_rights,
args: runtime_args,
account,
authorization_keys,
blocktime,
deploy_hash,
base_key,
gas_limit,
gas_counter,
hash_address_generator,
uref_address_generator,
transfer_address_generator,
protocol_version,
correlation_id,
phase,
protocol_data,
transfers,
}
}
pub fn authorization_keys(&self) -> &BTreeSet<AccountHash> {
&self.authorization_keys
}
pub fn named_keys_get(&self, name: &str) -> Option<&Key> {
self.named_keys.get(name)
}
pub fn named_keys(&self) -> &NamedKeys {
&self.named_keys
}
pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
&mut self.named_keys
}
pub fn named_keys_contains_key(&self, name: &str) -> bool {
self.named_keys.contains_key(name)
}
fn remove_key_from_contract(
&mut self,
key: Key,
mut contract: Contract,
name: &str,
) -> Result<(), Error> {
if contract.remove_named_key(name).is_none() {
return Ok(());
}
self.metered_write_gs_unsafe(key, contract)?;
Ok(())
}
pub fn remove_key(&mut self, name: &str) -> Result<(), Error> {
match self.base_key() {
account_hash @ Key::Account(_) => {
let account: Account = {
let mut account: Account = self.read_gs_typed(&account_hash)?;
account.named_keys_mut().remove(name);
account
};
self.named_keys.remove(name);
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(account_hash, account_value)?;
Ok(())
}
contract_uref @ Key::URef(_) => {
let contract: Contract = {
let value: StoredValue = self
.tracking_copy
.borrow_mut()
.read(self.correlation_id, &contract_uref)
.map_err(Into::into)?
.ok_or(Error::KeyNotFound(contract_uref))?;
value.try_into().map_err(Error::TypeMismatch)?
};
self.named_keys.remove(name);
self.remove_key_from_contract(contract_uref, contract, name)
}
contract_hash @ Key::Hash(_) => {
let contract: Contract = self.read_gs_typed(&contract_hash)?;
self.named_keys.remove(name);
self.remove_key_from_contract(contract_hash, contract, name)
}
transfer_addr @ Key::Transfer(_) => {
let _transfer: Transfer = self.read_gs_typed(&transfer_addr)?;
self.named_keys.remove(name);
Ok(())
}
deploy_info_addr @ Key::DeployInfo(_) => {
let _deploy_info: DeployInfo = self.read_gs_typed(&deploy_info_addr)?;
self.named_keys.remove(name);
Ok(())
}
}
}
pub fn get_caller(&self) -> AccountHash {
self.account.account_hash()
}
pub fn get_blocktime(&self) -> BlockTime {
self.blocktime
}
pub fn get_deploy_hash(&self) -> DeployHash {
self.deploy_hash
}
pub fn access_rights_extend(&mut self, access_rights: HashMap<Address, HashSet<AccessRights>>) {
self.access_rights.extend(access_rights);
}
pub fn access_rights(&self) -> &HashMap<Address, HashSet<AccessRights>> {
&self.access_rights
}
pub fn account(&self) -> &'a Account {
&self.account
}
pub fn args(&self) -> &RuntimeArgs {
&self.args
}
pub fn uref_address_generator(&self) -> Rc<RefCell<AddressGenerator>> {
Rc::clone(&self.uref_address_generator)
}
pub fn hash_address_generator(&self) -> Rc<RefCell<AddressGenerator>> {
Rc::clone(&self.hash_address_generator)
}
pub fn transfer_address_generator(&self) -> Rc<RefCell<AddressGenerator>> {
Rc::clone(&self.transfer_address_generator)
}
pub(super) fn state(&self) -> Rc<RefCell<TrackingCopy<R>>> {
Rc::clone(&self.tracking_copy)
}
pub fn gas_limit(&self) -> Gas {
self.gas_limit
}
pub fn gas_counter(&self) -> Gas {
self.gas_counter
}
pub fn set_gas_counter(&mut self, new_gas_counter: Gas) {
self.gas_counter = new_gas_counter;
}
pub fn base_key(&self) -> Key {
self.base_key
}
pub fn protocol_version(&self) -> ProtocolVersion {
self.protocol_version
}
pub fn correlation_id(&self) -> CorrelationId {
self.correlation_id
}
pub fn phase(&self) -> Phase {
self.phase
}
pub fn new_hash_address(&mut self) -> Result<[u8; KEY_HASH_LENGTH], Error> {
let pre_hash_bytes = self.hash_address_generator.borrow_mut().create_address();
let mut hasher = VarBlake2b::new(KEY_HASH_LENGTH).unwrap();
hasher.update(&pre_hash_bytes);
let mut hash_bytes = [0; KEY_HASH_LENGTH];
hasher.finalize_variable(|hash| hash_bytes.clone_from_slice(hash));
Ok(hash_bytes)
}
pub fn new_uref(&mut self, value: StoredValue) -> Result<URef, Error> {
let uref = {
let addr = self.uref_address_generator.borrow_mut().create_address();
URef::new(addr, AccessRights::READ_ADD_WRITE)
};
let key = Key::URef(uref);
self.insert_uref(uref);
self.metered_write_gs(key, value)?;
Ok(uref)
}
pub(crate) fn new_unit_uref(&mut self) -> Result<URef, Error> {
let cl_unit = CLValue::from_components(CLType::Unit, Vec::new());
self.new_uref(StoredValue::CLValue(cl_unit))
}
pub fn new_transfer_addr(&mut self) -> Result<TransferAddr, Error> {
let transfer_addr = self
.transfer_address_generator
.borrow_mut()
.create_address();
Ok(TransferAddr::new(transfer_addr))
}
pub fn put_key(&mut self, name: String, key: Key) -> Result<(), Error> {
let named_key_value = StoredValue::CLValue(CLValue::from_t((name.clone(), key))?);
self.validate_value(&named_key_value)?;
self.metered_add_gs_unsafe(self.base_key(), named_key_value)?;
self.insert_key(name, key);
Ok(())
}
pub fn read_ls(&mut self, key_bytes: &[u8]) -> Result<Option<CLValue>, Error> {
let actual_length = key_bytes.len();
if actual_length != KEY_HASH_LENGTH {
return Err(Error::InvalidKeyLength {
actual: actual_length,
expected: KEY_HASH_LENGTH,
});
}
let hash: [u8; KEY_HASH_LENGTH] = key_bytes.try_into().unwrap();
let key: Key = hash.into();
let maybe_stored_value = self
.tracking_copy
.borrow_mut()
.read(self.correlation_id, &key)
.map_err(Into::into)?;
if let Some(stored_value) = maybe_stored_value {
Ok(Some(stored_value.try_into().map_err(Error::TypeMismatch)?))
} else {
Ok(None)
}
}
pub fn write_ls(&mut self, key_bytes: &[u8], cl_value: CLValue) -> Result<(), Error> {
let actual_length = key_bytes.len();
if actual_length != KEY_HASH_LENGTH {
return Err(Error::InvalidKeyLength {
actual: actual_length,
expected: KEY_HASH_LENGTH,
});
}
let hash: [u8; KEY_HASH_LENGTH] = key_bytes.try_into().unwrap();
self.metered_write_gs_unsafe(hash, cl_value)?;
Ok(())
}
pub fn read_gs(&mut self, key: &Key) -> Result<Option<StoredValue>, Error> {
self.validate_readable(key)?;
self.validate_key(key)?;
self.tracking_copy
.borrow_mut()
.read(self.correlation_id, key)
.map_err(Into::into)
}
pub fn read_gs_direct(&mut self, key: &Key) -> Result<Option<StoredValue>, Error> {
self.tracking_copy
.borrow_mut()
.read(self.correlation_id, key)
.map_err(Into::into)
}
pub fn read_gs_typed<T>(&mut self, key: &Key) -> Result<T, Error>
where
T: TryFrom<StoredValue>,
T::Error: Debug,
{
let value = match self.read_gs(&key)? {
None => return Err(Error::KeyNotFound(*key)),
Some(value) => value,
};
value.try_into().map_err(|error| {
Error::FunctionNotFound(format!(
"Type mismatch for value under {:?}: {:?}",
key, error
))
})
}
pub fn read_account(&mut self, key: &Key) -> Result<Option<StoredValue>, Error> {
if let Key::Account(_) = key {
self.validate_key(key)?;
self.tracking_copy
.borrow_mut()
.read(self.correlation_id, key)
.map_err(Into::into)
} else {
panic!("Do not use this function for reading from non-account keys")
}
}
pub fn write_account(&mut self, key: Key, account: Account) -> Result<(), Error> {
if let Key::Account(_) = key {
self.validate_key(&key)?;
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(key, account_value)?;
Ok(())
} else {
panic!("Do not use this function for writing non-account keys")
}
}
pub fn write_transfer(&mut self, key: Key, value: Transfer) {
if let Key::Transfer(_) = key {
self.tracking_copy
.borrow_mut()
.write(key, StoredValue::Transfer(value));
} else {
panic!("Do not use this function for writing non-transfer keys")
}
}
pub fn store_function(
&mut self,
contract: StoredValue,
) -> Result<[u8; KEY_HASH_LENGTH], Error> {
self.validate_value(&contract)?;
self.new_uref(contract).map(|uref| uref.addr())
}
pub fn store_function_at_hash(
&mut self,
contract: StoredValue,
) -> Result<[u8; KEY_HASH_LENGTH], Error> {
let new_hash = self.new_hash_address()?;
self.validate_value(&contract)?;
self.metered_write_gs_unsafe(new_hash, contract)?;
Ok(new_hash)
}
pub fn insert_key(&mut self, name: String, key: Key) {
if let Key::URef(uref) = key {
self.insert_uref(uref);
}
self.named_keys.insert(name, key);
}
pub fn insert_uref(&mut self, uref: URef) {
let rights = uref.access_rights();
let entry = self
.access_rights
.entry(uref.addr())
.or_insert_with(|| std::iter::empty().collect());
entry.insert(rights);
}
pub fn effect(&self) -> ExecutionEffect {
self.tracking_copy.borrow_mut().effect()
}
pub fn transfers(&self) -> &Vec<TransferAddr> {
&self.transfers
}
pub fn transfers_mut(&mut self) -> &mut Vec<TransferAddr> {
&mut self.transfers
}
fn validate_value(&self, value: &StoredValue) -> Result<(), Error> {
match value {
StoredValue::CLValue(cl_value) => 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::Option(_)
| CLType::List(_)
| CLType::ByteArray(..)
| CLType::Result { .. }
| CLType::Map { .. }
| CLType::Tuple1(_)
| CLType::Tuple3(_)
| CLType::Any
| CLType::PublicKey => Ok(()),
CLType::Key => {
let key: Key = cl_value.to_owned().into_t()?;
self.validate_key(&key)
}
CLType::URef => {
let uref: URef = cl_value.to_owned().into_t()?;
self.validate_uref(&uref)
}
tuple @ CLType::Tuple2(_) if *tuple == casper_types::named_key_type() => {
let (_name, key): (String, Key) = cl_value.to_owned().into_t()?;
self.validate_key(&key)
}
CLType::Tuple2(_) => Ok(()),
},
StoredValue::Account(account) => {
account
.named_keys()
.values()
.try_for_each(|key| self.validate_key(key))
}
StoredValue::ContractWasm(_) => Ok(()),
StoredValue::Contract(contract_header) => contract_header
.named_keys()
.values()
.try_for_each(|key| self.validate_key(key)),
StoredValue::ContractPackage(_) => Ok(()),
StoredValue::Transfer(_) => Ok(()),
StoredValue::DeployInfo(_) => Ok(()),
}
}
pub fn validate_key(&self, key: &Key) -> Result<(), Error> {
let uref = match key {
Key::URef(uref) => uref,
_ => return Ok(()),
};
self.validate_uref(uref)
}
pub fn validate_uref(&self, uref: &URef) -> Result<(), Error> {
if self.account.main_purse().addr() == uref.addr() {
let rights = self.account.main_purse().access_rights();
let uref_rights = uref.access_rights();
if rights & uref_rights == uref_rights {
return Ok(());
}
}
if uref_has_access_rights(uref, &self.access_rights) {
Ok(())
} else {
Err(Error::ForgedReference(*uref))
}
}
pub fn deserialize_keys(&self, bytes: Vec<u8>) -> Result<Vec<Key>, Error> {
let keys: Vec<Key> = bytesrepr::deserialize(bytes)?;
keys.iter().try_for_each(|k| self.validate_key(k))?;
Ok(keys)
}
pub fn deserialize_urefs(&self, bytes: Vec<u8>) -> Result<Vec<URef>, Error> {
let keys: Vec<URef> = bytesrepr::deserialize(bytes)?;
keys.iter().try_for_each(|k| self.validate_uref(k))?;
Ok(keys)
}
fn validate_readable(&self, key: &Key) -> Result<(), Error> {
if self.is_readable(&key) {
Ok(())
} else {
Err(Error::InvalidAccess {
required: AccessRights::READ,
})
}
}
fn validate_addable(&self, key: &Key) -> Result<(), Error> {
if self.is_addable(&key) {
Ok(())
} else {
Err(Error::InvalidAccess {
required: AccessRights::ADD,
})
}
}
fn validate_writeable(&self, key: &Key) -> Result<(), Error> {
if self.is_writeable(&key) {
Ok(())
} else {
Err(Error::InvalidAccess {
required: AccessRights::WRITE,
})
}
}
pub fn is_readable(&self, key: &Key) -> bool {
match key {
Key::Account(_) => &self.base_key() == key,
Key::Hash(_) => true,
Key::URef(uref) => uref.is_readable(),
Key::Transfer(_) => true,
Key::DeployInfo(_) => true,
}
}
pub fn is_addable(&self, key: &Key) -> bool {
match key {
Key::Account(_) | Key::Hash(_) => &self.base_key() == key,
Key::URef(uref) => uref.is_addable(),
Key::Transfer(_) => false,
Key::DeployInfo(_) => false,
}
}
pub fn is_writeable(&self, key: &Key) -> bool {
match key {
Key::Account(_) | Key::Hash(_) => false,
Key::URef(uref) => uref.is_writeable(),
Key::DeployInfo(_) => false,
Key::Transfer(_) => false,
}
}
pub(crate) fn charge_gas(&mut self, amount: Gas) -> Result<(), Error> {
let prev = self.gas_counter();
let gas_limit = self.gas_limit();
match prev.checked_add(amount) {
None => {
self.set_gas_counter(gas_limit);
Err(Error::GasLimit)
}
Some(val) if val > gas_limit => {
self.set_gas_counter(gas_limit);
Err(Error::GasLimit)
}
Some(val) => {
self.set_gas_counter(val);
Ok(())
}
}
}
fn charge_gas_storage(&mut self, bytes_count: usize) -> Result<(), Error> {
let storage_costs = self.protocol_data().wasm_config().storage_costs();
let gas_cost = storage_costs.calculate_gas_cost(bytes_count);
self.charge_gas(gas_cost)
}
pub(crate) fn metered_write_gs_unsafe<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
where
K: Into<Key>,
V: Into<StoredValue>,
{
let stored_value = value.into();
let bytes_count = stored_value.serialized_length();
self.charge_gas_storage(bytes_count)?;
self.tracking_copy
.borrow_mut()
.write(key.into(), stored_value);
Ok(())
}
pub fn metered_write_gs<T>(&mut self, key: Key, value: T) -> Result<(), Error>
where
T: Into<StoredValue>,
{
let stored_value = value.into();
self.validate_writeable(&key)?;
self.validate_key(&key)?;
self.validate_value(&stored_value)?;
self.metered_write_gs_unsafe(key, stored_value)?;
Ok(())
}
fn metered_add_gs_unsafe(&mut self, key: Key, value: StoredValue) -> Result<(), Error> {
let value_bytes_count = value.serialized_length();
self.charge_gas_storage(value_bytes_count)?;
match self
.tracking_copy
.borrow_mut()
.add(self.correlation_id, key, value)
{
Err(storage_error) => Err(storage_error.into()),
Ok(AddResult::Success) => Ok(()),
Ok(AddResult::KeyNotFound(key)) => Err(Error::KeyNotFound(key)),
Ok(AddResult::TypeMismatch(type_mismatch)) => Err(Error::TypeMismatch(type_mismatch)),
Ok(AddResult::Serialization(error)) => Err(Error::BytesRepr(error)),
}
}
pub(crate) fn metered_add_gs<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
where
K: Into<Key>,
V: Into<StoredValue>,
{
let key = key.into();
let value = value.into();
self.validate_addable(&key)?;
self.validate_key(&key)?;
self.validate_value(&value)?;
self.metered_add_gs_unsafe(key, value)
}
pub fn add_associated_key(
&mut self,
account_hash: AccountHash,
weight: Weight,
) -> Result<(), Error> {
if !self.is_valid_context() {
return Err(AddKeyFailure::PermissionDenied.into());
}
if !self
.account()
.can_manage_keys_with(&self.authorization_keys)
{
return Err(AddKeyFailure::PermissionDenied.into());
}
let key = Key::Account(self.account().account_hash());
let account = {
let mut account: Account = self.read_gs_typed(&key)?;
account
.add_associated_key(account_hash, weight)
.map_err(Error::from)?;
account
};
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(key, account_value)?;
Ok(())
}
pub fn remove_associated_key(&mut self, account_hash: AccountHash) -> Result<(), Error> {
if !self.is_valid_context() {
return Err(RemoveKeyFailure::PermissionDenied.into());
}
if !self
.account()
.can_manage_keys_with(&self.authorization_keys)
{
return Err(RemoveKeyFailure::PermissionDenied.into());
}
let key = Key::Account(self.account().account_hash());
let mut account: Account = self.read_gs_typed(&key)?;
account
.remove_associated_key(account_hash)
.map_err(Error::from)?;
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(key, account_value)?;
Ok(())
}
pub fn update_associated_key(
&mut self,
account_hash: AccountHash,
weight: Weight,
) -> Result<(), Error> {
if !self.is_valid_context() {
return Err(UpdateKeyFailure::PermissionDenied.into());
}
if !self
.account()
.can_manage_keys_with(&self.authorization_keys)
{
return Err(UpdateKeyFailure::PermissionDenied.into());
}
let key = Key::Account(self.account().account_hash());
let mut account: Account = self.read_gs_typed(&key)?;
account
.update_associated_key(account_hash, weight)
.map_err(Error::from)?;
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(key, account_value)?;
Ok(())
}
pub fn set_action_threshold(
&mut self,
action_type: ActionType,
threshold: Weight,
) -> Result<(), Error> {
if !self.is_valid_context() {
return Err(SetThresholdFailure::PermissionDeniedError.into());
}
if !self
.account()
.can_manage_keys_with(&self.authorization_keys)
{
return Err(SetThresholdFailure::PermissionDeniedError.into());
}
let key = Key::Account(self.account().account_hash());
let mut account: Account = self.read_gs_typed(&key)?;
account
.set_action_threshold(action_type, threshold)
.map_err(Error::from)?;
let account_value = self.account_to_validated_value(account)?;
self.metered_write_gs_unsafe(key, account_value)?;
Ok(())
}
pub fn protocol_data(&self) -> &ProtocolData {
&self.protocol_data
}
fn account_to_validated_value(&self, account: Account) -> Result<StoredValue, Error> {
let value = StoredValue::Account(account);
self.validate_value(&value)?;
Ok(value)
}
fn is_valid_context(&self) -> bool {
self.base_key() == Key::Account(self.account().account_hash())
}
pub fn get_main_purse(&self) -> Result<URef, Error> {
if !self.is_valid_context() {
return Err(Error::InvalidContext);
}
Ok(self.account().main_purse())
}
pub fn entry_point_type(&self) -> EntryPointType {
self.entry_point_type
}
pub(crate) fn get_validated_contract_package(
&mut self,
package_hash: ContractPackageHash,
) -> Result<ContractPackage, Error> {
let package_hash_key = Key::from(package_hash);
self.validate_key(&package_hash_key)?;
let contract_package: ContractPackage = self.read_gs_typed(&Key::from(package_hash))?;
self.validate_uref(&contract_package.access_key())?;
Ok(contract_package)
}
}