use std::{
cell::RefCell,
collections::{BTreeSet, HashMap, HashSet},
iter::{self, FromIterator},
rc::Rc,
};
use rand::RngCore;
use engine_shared::{
account::{Account, AssociatedKeys},
additive_map::AdditiveMap,
gas::Gas,
newtypes::CorrelationId,
stored_value::StoredValue,
transform::Transform,
};
use engine_storage::global_state::{
in_memory::{InMemoryGlobalState, InMemoryGlobalStateView},
CommitResult, StateProvider,
};
use types::{
account::{
AccountHash, ActionType, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure, Weight,
},
contracts::NamedKeys,
AccessRights, BlockTime, CLValue, Contract, EntryPointType, EntryPoints, Key, Phase,
ProtocolVersion, RuntimeArgs, URef, KEY_HASH_LENGTH,
};
use super::{Address, Error, RuntimeContext};
use crate::{
execution::AddressGenerator, runtime::extract_access_rights_from_keys,
tracking_copy::TrackingCopy,
};
const DEPLOY_HASH: [u8; 32] = [1u8; 32];
const PHASE: Phase = Phase::Session;
fn mock_tracking_copy(
init_key: Key,
init_account: Account,
) -> TrackingCopy<InMemoryGlobalStateView> {
let correlation_id = CorrelationId::new();
let hist = InMemoryGlobalState::empty().unwrap();
let root_hash = hist.empty_root_hash;
let transform = Transform::Write(StoredValue::Account(init_account));
let mut m = AdditiveMap::new();
m.insert(init_key, transform);
let commit_result = hist
.commit(correlation_id, root_hash, m)
.expect("Creation of mocked account should be a success.");
let new_hash = match commit_result {
CommitResult::Success { state_root, .. } => state_root,
other => panic!("Commiting changes to test History failed: {:?}.", other),
};
let reader = hist
.checkout(new_hash)
.expect("Checkout should not throw errors.")
.expect("Root hash should exist.");
TrackingCopy::new(reader)
}
fn mock_account_with_purse(account_hash: AccountHash, purse: [u8; 32]) -> (Key, Account) {
let associated_keys = AssociatedKeys::new(account_hash, Weight::new(1));
let account = Account::new(
account_hash,
NamedKeys::new(),
URef::new(purse, AccessRights::READ_ADD_WRITE),
associated_keys,
Default::default(),
);
let key = Key::Account(account_hash);
(key, account)
}
fn mock_account(account_hash: AccountHash) -> (Key, Account) {
mock_account_with_purse(account_hash, [0; 32])
}
fn random_account_key<G: RngCore>(entropy_source: &mut G) -> Key {
let mut key = [0u8; 32];
entropy_source.fill_bytes(&mut key);
Key::Account(AccountHash::new(key))
}
fn random_contract_key<G: RngCore>(entropy_source: &mut G) -> Key {
let mut key = [0u8; 32];
entropy_source.fill_bytes(&mut key);
Key::Hash(key)
}
fn create_uref(address_generator: &mut AddressGenerator, rights: AccessRights) -> Key {
let address = address_generator.create_address();
Key::URef(URef::new(address, rights))
}
fn random_hash<G: RngCore>(entropy_source: &mut G) -> Key {
let mut key = [0u8; KEY_HASH_LENGTH];
entropy_source.fill_bytes(&mut key);
Key::Hash(key)
}
fn mock_runtime_context<'a>(
account: &'a Account,
base_key: Key,
named_keys: &'a mut NamedKeys,
access_rights: HashMap<Address, HashSet<AccessRights>>,
hash_address_generator: AddressGenerator,
uref_address_generator: AddressGenerator,
) -> RuntimeContext<'a, InMemoryGlobalStateView> {
let tracking_copy = mock_tracking_copy(base_key, account.clone());
RuntimeContext::new(
Rc::new(RefCell::new(tracking_copy)),
EntryPointType::Session,
named_keys,
access_rights,
RuntimeArgs::new(),
BTreeSet::from_iter(vec![AccountHash::new([0; 32])]),
&account,
base_key,
BlockTime::new(0),
[1u8; 32],
Gas::default(),
Gas::default(),
Rc::new(RefCell::new(hash_address_generator)),
Rc::new(RefCell::new(uref_address_generator)),
ProtocolVersion::V1_0_0,
CorrelationId::new(),
Phase::Session,
Default::default(),
)
}
#[allow(clippy::assertions_on_constants)]
fn assert_forged_reference<T>(result: Result<T, Error>) {
match result {
Err(Error::ForgedReference(_)) => assert!(true),
_ => panic!("Error. Test should have failed with ForgedReference error but didn't."),
}
}
#[allow(clippy::assertions_on_constants)]
fn assert_invalid_access<T: std::fmt::Debug>(result: Result<T, Error>, expecting: AccessRights) {
match result {
Err(Error::InvalidAccess { required }) if required == expecting => assert!(true),
other => panic!(
"Error. Test should have failed with InvalidAccess error but didn't: {:?}.",
other
),
}
}
fn test<T, F>(access_rights: HashMap<Address, HashSet<AccessRights>>, query: F) -> Result<T, Error>
where
F: FnOnce(RuntimeContext<InMemoryGlobalStateView>) -> Result<T, Error>,
{
let deploy_hash = [1u8; 32];
let (base_key, account) = mock_account(AccountHash::new([0u8; 32]));
let mut named_keys = NamedKeys::new();
let uref_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let hash_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let runtime_context = mock_runtime_context(
&account,
base_key,
&mut named_keys,
access_rights,
hash_address_generator,
uref_address_generator,
);
query(runtime_context)
}
#[test]
fn use_uref_valid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref = create_uref(&mut rng, AccessRights::READ_WRITE);
let access_rights = extract_access_rights_from_keys(vec![uref]);
let value = StoredValue::CLValue(CLValue::from_t(43_i32).unwrap());
let query_result = test(access_rights, |mut rc| rc.write_gs(uref, value));
query_result.expect("writing using valid uref should succeed");
}
#[test]
fn use_uref_forged() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref = create_uref(&mut rng, AccessRights::READ_WRITE);
let access_rights = HashMap::new();
let value = StoredValue::CLValue(CLValue::from_t(43_i32).unwrap());
let query_result = test(access_rights, |mut rc| rc.write_gs(uref, value));
assert_forged_reference(query_result);
}
#[test]
fn account_key_not_writeable() {
let mut rng = rand::thread_rng();
let acc_key = random_account_key(&mut rng);
let query_result = test(HashMap::new(), |mut rc| {
rc.write_gs(
acc_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert_invalid_access(query_result, AccessRights::WRITE);
}
#[test]
fn account_key_readable_valid() {
let query_result = test(HashMap::new(), |mut rc| {
let base_key = rc.base_key();
let result = rc
.read_gs(&base_key)
.expect("Account key is readable.")
.expect("Account is found in GS.");
assert_eq!(result, StoredValue::Account(rc.account().clone()));
Ok(())
});
assert!(query_result.is_ok());
}
#[test]
fn account_key_readable_invalid() {
let mut rng = rand::thread_rng();
let other_acc_key = random_account_key(&mut rng);
let query_result = test(HashMap::new(), |mut rc| rc.read_gs(&other_acc_key));
assert_invalid_access(query_result, AccessRights::READ);
}
#[test]
fn account_key_addable_valid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref = create_uref(&mut rng, AccessRights::READ);
let access_rights = extract_access_rights_from_keys(vec![uref]);
let query_result = test(access_rights, |mut rc| {
let base_key = rc.base_key();
let uref_name = "NewURef".to_owned();
let named_key = StoredValue::CLValue(CLValue::from_t((uref_name.clone(), uref)).unwrap());
rc.add_gs(base_key, named_key).expect("Adding should work.");
let named_key_transform = Transform::AddKeys(iter::once((uref_name, uref)).collect());
assert_eq!(
*rc.effect().transforms.get(&base_key).unwrap(),
named_key_transform
);
Ok(())
});
assert!(query_result.is_ok());
}
#[test]
fn account_key_addable_invalid() {
let mut rng = rand::thread_rng();
let other_acc_key = random_account_key(&mut rng);
let query_result = test(HashMap::new(), |mut rc| {
rc.add_gs(
other_acc_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert_invalid_access(query_result, AccessRights::ADD);
}
#[test]
fn contract_key_readable_valid() {
let mut rng = rand::thread_rng();
let contract_key = random_contract_key(&mut rng);
let query_result = test(HashMap::new(), |mut rc| rc.read_gs(&contract_key));
assert!(query_result.is_ok());
}
#[test]
fn contract_key_not_writeable() {
let mut rng = rand::thread_rng();
let contract_key = random_contract_key(&mut rng);
let query_result = test(HashMap::new(), |mut rc| {
rc.write_gs(
contract_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert_invalid_access(query_result, AccessRights::WRITE);
}
#[test]
fn contract_key_addable_valid() {
let account_hash = AccountHash::new([0u8; 32]);
let (account_key, account) = mock_account(account_hash);
let authorization_keys = BTreeSet::from_iter(vec![account_hash]);
let hash_address_generator = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let mut uref_address_generator = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let mut rng = rand::thread_rng();
let contract_key = random_contract_key(&mut rng);
let contract = StoredValue::Contract(Contract::default());
let tracking_copy = Rc::new(RefCell::new(mock_tracking_copy(
account_key,
account.clone(),
)));
tracking_copy.borrow_mut().write(contract_key, contract);
let mut named_keys = NamedKeys::new();
let uref = create_uref(&mut uref_address_generator, AccessRights::WRITE);
let uref_name = "NewURef".to_owned();
let named_uref_tuple =
StoredValue::CLValue(CLValue::from_t((uref_name.clone(), uref)).unwrap());
let access_rights = extract_access_rights_from_keys(vec![uref]);
let mut runtime_context = RuntimeContext::new(
Rc::clone(&tracking_copy),
EntryPointType::Session,
&mut named_keys,
access_rights,
RuntimeArgs::new(),
authorization_keys,
&account,
contract_key,
BlockTime::new(0),
DEPLOY_HASH,
Gas::default(),
Gas::default(),
Rc::new(RefCell::new(hash_address_generator)),
Rc::new(RefCell::new(uref_address_generator)),
ProtocolVersion::V1_0_0,
CorrelationId::new(),
PHASE,
Default::default(),
);
runtime_context
.add_gs(contract_key, named_uref_tuple)
.expect("Adding should work.");
let updated_contract = StoredValue::Contract(Contract::new(
[0u8; 32],
[0u8; 32],
iter::once((uref_name, uref)).collect(),
EntryPoints::default(),
ProtocolVersion::V1_0_0,
));
assert_eq!(
*tracking_copy
.borrow()
.effect()
.transforms
.get(&contract_key)
.unwrap(),
Transform::Write(updated_contract)
);
}
#[test]
fn contract_key_addable_invalid() {
let account_hash = AccountHash::new([0u8; 32]);
let (account_key, account) = mock_account(account_hash);
let authorization_keys = BTreeSet::from_iter(vec![account_hash]);
let hash_address_generator = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let mut uref_address_generator = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let mut rng = rand::thread_rng();
let contract_key = random_contract_key(&mut rng);
let other_contract_key = random_contract_key(&mut rng);
let contract = StoredValue::Contract(Contract::default());
let tracking_copy = Rc::new(RefCell::new(mock_tracking_copy(
account_key,
account.clone(),
)));
tracking_copy.borrow_mut().write(contract_key, contract);
let mut named_keys = NamedKeys::new();
let uref = create_uref(&mut uref_address_generator, AccessRights::WRITE);
let uref_name = "NewURef".to_owned();
let named_uref_tuple = StoredValue::CLValue(CLValue::from_t((uref_name, uref)).unwrap());
let access_rights = extract_access_rights_from_keys(vec![uref]);
let mut runtime_context = RuntimeContext::new(
Rc::clone(&tracking_copy),
EntryPointType::Session,
&mut named_keys,
access_rights,
RuntimeArgs::new(),
authorization_keys,
&account,
other_contract_key,
BlockTime::new(0),
DEPLOY_HASH,
Gas::default(),
Gas::default(),
Rc::new(RefCell::new(hash_address_generator)),
Rc::new(RefCell::new(uref_address_generator)),
ProtocolVersion::V1_0_0,
CorrelationId::new(),
PHASE,
Default::default(),
);
let result = runtime_context.add_gs(contract_key, named_uref_tuple);
assert_invalid_access(result, AccessRights::ADD);
}
#[test]
fn uref_key_readable_valid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::READ);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| rc.read_gs(&uref_key));
assert!(query_result.is_ok());
}
#[test]
fn uref_key_readable_invalid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::WRITE);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| rc.read_gs(&uref_key));
assert_invalid_access(query_result, AccessRights::READ);
}
#[test]
fn uref_key_writeable_valid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::WRITE);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| {
rc.write_gs(
uref_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert!(query_result.is_ok());
}
#[test]
fn uref_key_writeable_invalid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::READ);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| {
rc.write_gs(
uref_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert_invalid_access(query_result, AccessRights::WRITE);
}
#[test]
fn uref_key_addable_valid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::ADD_WRITE);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| {
rc.write_gs(
uref_key,
StoredValue::CLValue(CLValue::from_t(10_i32).unwrap()),
)
.expect("Writing to the GlobalState should work.");
rc.add_gs(
uref_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert!(query_result.is_ok());
}
#[test]
fn uref_key_addable_invalid() {
let mut rng = AddressGenerator::new(&DEPLOY_HASH, PHASE);
let uref_key = create_uref(&mut rng, AccessRights::WRITE);
let access_rights = extract_access_rights_from_keys(vec![uref_key]);
let query_result = test(access_rights, |mut rc| {
rc.add_gs(
uref_key,
StoredValue::CLValue(CLValue::from_t(1_i32).unwrap()),
)
});
assert_invalid_access(query_result, AccessRights::ADD);
}
#[test]
fn hash_key_readable() {
let query = |runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
let mut rng = rand::thread_rng();
let key = random_hash(&mut rng);
runtime_context.validate_readable(&key)
};
let query_result = test(HashMap::new(), query);
assert!(query_result.is_ok())
}
#[test]
fn hash_key_writeable() {
let query = |runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
let mut rng = rand::thread_rng();
let key = random_hash(&mut rng);
runtime_context.validate_writeable(&key)
};
let query_result = test(HashMap::new(), query);
assert!(query_result.is_err())
}
#[test]
fn hash_key_addable_invalid() {
let query = |runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
let mut rng = rand::thread_rng();
let key = random_hash(&mut rng);
runtime_context.validate_addable(&key)
};
let query_result = test(HashMap::new(), query);
assert!(query_result.is_err())
}
#[test]
fn manage_associated_keys() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
let account_hash = AccountHash::new([42; 32]);
let weight = Weight::new(155);
runtime_context
.add_associated_key(account_hash, weight)
.expect("Unable to add key");
let effect = runtime_context.effect();
let transform = effect.transforms.get(&runtime_context.base_key()).unwrap();
let account = match transform {
Transform::Write(StoredValue::Account(account)) => account,
_ => panic!("Invalid transform operation found"),
};
account
.get_associated_key_weight(account_hash)
.expect("Account hash wasn't added to associated keys");
let new_weight = Weight::new(100);
runtime_context
.update_associated_key(account_hash, new_weight)
.expect("Unable to update key");
let effect = runtime_context.effect();
let transform = effect.transforms.get(&runtime_context.base_key()).unwrap();
let account = match transform {
Transform::Write(StoredValue::Account(account)) => account,
_ => panic!("Invalid transform operation found"),
};
let value = account
.get_associated_key_weight(account_hash)
.expect("Account hash wasn't added to associated keys");
assert_eq!(value, &new_weight, "value was not updated");
runtime_context
.remove_associated_key(account_hash)
.expect("Unable to remove key");
let effect = runtime_context.effect();
let transform = effect.transforms.get(&runtime_context.base_key()).unwrap();
let account = match transform {
Transform::Write(StoredValue::Account(account)) => account,
_ => panic!("Invalid transform operation found"),
};
assert!(account.get_associated_key_weight(account_hash).is_none());
runtime_context
.remove_associated_key(account_hash)
.expect_err("A non existing key was unexpectedly removed again");
Ok(())
};
let _ = test(access_rights, query);
}
#[test]
fn action_thresholds_management() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
runtime_context
.add_associated_key(AccountHash::new([42; 32]), Weight::new(254))
.expect("Unable to add associated key with maximum weight");
runtime_context
.set_action_threshold(ActionType::KeyManagement, Weight::new(253))
.expect("Unable to set action threshold KeyManagement");
runtime_context
.set_action_threshold(ActionType::Deployment, Weight::new(252))
.expect("Unable to set action threshold Deployment");
let effect = runtime_context.effect();
let transform = effect.transforms.get(&runtime_context.base_key()).unwrap();
let mutated_account = match transform {
Transform::Write(StoredValue::Account(account)) => account,
_ => panic!("Invalid transform operation found"),
};
assert_eq!(
mutated_account.action_thresholds().deployment(),
&Weight::new(252)
);
assert_eq!(
mutated_account.action_thresholds().key_management(),
&Weight::new(253)
);
runtime_context
.set_action_threshold(ActionType::Deployment, Weight::new(255))
.expect_err("Shouldn't be able to set deployment threshold higher than key management");
Ok(())
};
let _ = test(access_rights, query);
}
#[test]
fn should_verify_ownership_before_adding_key() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
runtime_context.base_key = Key::Hash([1; 32]);
let err = runtime_context
.add_associated_key(AccountHash::new([84; 32]), Weight::new(123))
.expect_err("This operation should return error");
match err {
Error::AddKeyFailure(AddKeyFailure::PermissionDenied) => {}
e => panic!("Invalid error variant: {:?}", e),
}
Ok(())
};
let _ = test(access_rights, query);
}
#[test]
fn should_verify_ownership_before_removing_a_key() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
runtime_context.base_key = Key::Hash([1; 32]);
let err = runtime_context
.remove_associated_key(AccountHash::new([84; 32]))
.expect_err("This operation should return error");
match err {
Error::RemoveKeyFailure(RemoveKeyFailure::PermissionDenied) => {}
ref e => panic!("Invalid error variant: {:?}", e),
}
Ok(())
};
let _ = test(access_rights, query);
}
#[test]
fn should_verify_ownership_before_setting_action_threshold() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
runtime_context.base_key = Key::Hash([1; 32]);
let err = runtime_context
.set_action_threshold(ActionType::Deployment, Weight::new(123))
.expect_err("This operation should return error");
match err {
Error::SetThresholdFailure(SetThresholdFailure::PermissionDeniedError) => {}
ref e => panic!("Invalid error variant: {:?}", e),
}
Ok(())
};
let _ = test(access_rights, query);
}
#[test]
fn can_roundtrip_key_value_pairs() {
let access_rights = HashMap::new();
let query = |mut runtime_context: RuntimeContext<InMemoryGlobalStateView>| {
let mut rng = rand::thread_rng();
let test_key = random_hash(&mut rng).into_hash().expect("should be hash");
let test_value = CLValue::from_t("test_value".to_string()).unwrap();
runtime_context
.write_ls(&test_key, test_value.clone())
.expect("should write_ls");
let result = runtime_context.read_ls(&test_key).expect("should read_ls");
Ok(result == Some(test_value))
};
let query_result = test(access_rights, query).expect("should be ok");
assert!(query_result)
}
#[test]
fn remove_uref_works() {
let access_rights = HashMap::new();
let deploy_hash = [1u8; 32];
let (base_key, account) = mock_account(AccountHash::new([0u8; 32]));
let hash_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let mut uref_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let uref_name = "Foo".to_owned();
let uref_key = create_uref(&mut uref_address_generator, AccessRights::READ);
let mut named_keys = iter::once((uref_name.clone(), uref_key)).collect();
let mut runtime_context = mock_runtime_context(
&account,
base_key,
&mut named_keys,
access_rights,
hash_address_generator,
uref_address_generator,
);
assert!(runtime_context.named_keys_contains_key(&uref_name));
assert!(runtime_context.remove_key(&uref_name).is_ok());
assert!(runtime_context.validate_key(&uref_key).is_err());
assert!(!runtime_context.named_keys_contains_key(&uref_name));
let effects = runtime_context.effect();
let transform = effects.transforms.get(&base_key).unwrap();
let account = match transform {
Transform::Write(StoredValue::Account(account)) => account,
_ => panic!("Invalid transform operation found"),
};
assert!(!account.named_keys().contains_key(&uref_name));
}
#[test]
fn validate_valid_purse_of_an_account() {
let mock_purse = [42u8; 32];
let access_rights = HashMap::new();
let deploy_hash = [1u8; 32];
let (base_key, account) = mock_account_with_purse(AccountHash::new([0u8; 32]), mock_purse);
let mut named_keys = NamedKeys::new();
let hash_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let uref_address_generator = AddressGenerator::new(&deploy_hash, Phase::Session);
let runtime_context = mock_runtime_context(
&account,
base_key,
&mut named_keys,
access_rights,
hash_address_generator,
uref_address_generator,
);
let purse = URef::new(mock_purse, AccessRights::READ_ADD_WRITE);
assert!(runtime_context.validate_uref(&purse).is_ok());
let purse = URef::new(mock_purse, AccessRights::READ);
assert!(runtime_context.validate_uref(&purse).is_ok());
let purse = URef::new(mock_purse, AccessRights::ADD);
assert!(runtime_context.validate_uref(&purse).is_ok());
let purse = URef::new(mock_purse, AccessRights::WRITE);
assert!(runtime_context.validate_uref(&purse).is_ok());
let purse = URef::new([53; 32], AccessRights::READ_ADD_WRITE);
assert!(runtime_context.validate_uref(&purse).is_err());
}