1use crate::blueprints::models::*;
2use crate::blueprints::package::PackageAuthNativeBlueprint;
3use crate::blueprints::util::*;
4use crate::internal_prelude::*;
5use crate::kernel::kernel_api::KernelSubstateApi;
6use crate::object_modules::role_assignment::{LockOwnerRoleEvent, SetOwnerRoleEvent};
7use crate::system::system::SystemService;
8use crate::system::system_callback::*;
9use crate::system::system_modules::auth::{AuthError, ResolvedPermission};
10use crate::system::system_substates::FieldSubstate;
11use crate::{errors::*, event_schema};
12use radix_blueprint_schema_init::*;
13use radix_engine_interface::api::field_api::LockFlags;
14use radix_engine_interface::api::*;
15use radix_engine_interface::blueprints::package::*;
16use radix_engine_interface::blueprints::resource::*;
17use radix_engine_interface::object_modules::role_assignment::*;
18use radix_engine_interface::types::*;
19use radix_native_sdk::runtime::Runtime;
20
21use super::*;
22
23#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
24pub enum RoleAssignmentError {
25 UsedReservedRole(String),
26 UsedReservedSpace,
27 ExceededMaxRoleNameLen { limit: usize, actual: usize },
28 ExceededMaxAccessRuleDepth,
29 ExceededMaxAccessRuleNodes,
30 InvalidName(InvalidNameError),
31 ExceededMaxRoles,
32 CannotSetRoleIfNotAttached,
33}
34
35pub struct RoleAssignmentNativePackage;
36
37impl RoleAssignmentNativePackage {
38 pub fn definition() -> PackageDefinition {
39 let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
40
41 let state = RoleAssignmentStateSchemaInit::create_schema_init(&mut aggregator);
42
43 let mut functions = index_map_new();
44 functions.insert(
45 ROLE_ASSIGNMENT_CREATE_IDENT.to_string(),
46 FunctionSchemaInit {
47 receiver: None,
48 input: TypeRef::Static(
49 aggregator.add_child_type_and_descendents::<RoleAssignmentCreateInput>(),
50 ),
51 output: TypeRef::Static(
52 aggregator.add_child_type_and_descendents::<RoleAssignmentCreateOutput>(),
53 ),
54 export: ROLE_ASSIGNMENT_CREATE_IDENT.to_string(),
55 },
56 );
57 functions.insert(
58 ROLE_ASSIGNMENT_SET_OWNER_IDENT.to_string(),
59 FunctionSchemaInit {
60 receiver: Some(ReceiverInfo::normal_ref_mut()),
61 input: TypeRef::Static(
62 aggregator.add_child_type_and_descendents::<RoleAssignmentSetOwnerInput>(),
63 ),
64 output: TypeRef::Static(
65 aggregator.add_child_type_and_descendents::<RoleAssignmentSetOwnerOutput>(),
66 ),
67 export: ROLE_ASSIGNMENT_SET_OWNER_IDENT.to_string(),
68 },
69 );
70 functions.insert(
71 ROLE_ASSIGNMENT_LOCK_OWNER_IDENT.to_string(),
72 FunctionSchemaInit {
73 receiver: Some(ReceiverInfo::normal_ref_mut()),
74 input: TypeRef::Static(
75 aggregator.add_child_type_and_descendents::<RoleAssignmentLockOwnerInput>(),
76 ),
77 output: TypeRef::Static(
78 aggregator.add_child_type_and_descendents::<RoleAssignmentLockOwnerOutput>(),
79 ),
80 export: ROLE_ASSIGNMENT_LOCK_OWNER_IDENT.to_string(),
81 },
82 );
83 functions.insert(
84 ROLE_ASSIGNMENT_SET_IDENT.to_string(),
85 FunctionSchemaInit {
86 receiver: Some(ReceiverInfo::normal_ref_mut()),
87 input: TypeRef::Static(
88 aggregator.add_child_type_and_descendents::<RoleAssignmentSetInput>(),
89 ),
90 output: TypeRef::Static(
91 aggregator.add_child_type_and_descendents::<RoleAssignmentSetOutput>(),
92 ),
93 export: ROLE_ASSIGNMENT_SET_IDENT.to_string(),
94 },
95 );
96 functions.insert(
97 ROLE_ASSIGNMENT_GET_IDENT.to_string(),
98 FunctionSchemaInit {
99 receiver: Some(ReceiverInfo::normal_ref_mut()),
100 input: TypeRef::Static(
101 aggregator.add_child_type_and_descendents::<RoleAssignmentGetInput>(),
102 ),
103 output: TypeRef::Static(
104 aggregator.add_child_type_and_descendents::<RoleAssignmentGetOutput>(),
105 ),
106 export: ROLE_ASSIGNMENT_GET_IDENT.to_string(),
107 },
108 );
109
110 let events = event_schema! {
111 aggregator,
112 [
113 SetOwnerRoleEvent,
114 SetRoleEvent,
115 LockOwnerRoleEvent
116 ]
117 };
118
119 let schema = generate_full_schema(aggregator);
120 let blueprints = indexmap!(
121 ROLE_ASSIGNMENT_BLUEPRINT.to_string() => BlueprintDefinitionInit {
122 blueprint_type: BlueprintType::default(),
123 is_transient: true,
124 feature_set: indexset!(),
125 dependencies: indexset!(),
126
127 schema: BlueprintSchemaInit {
128 generics: vec![],
129 schema,
130 state,
131 events,
132 types: BlueprintTypeSchemaInit::default(),
133 functions: BlueprintFunctionsSchemaInit {
134 functions,
135 },
136 hooks: BlueprintHooksInit::default(),
137 },
138
139 royalty_config: PackageRoyaltyConfig::default(),
140 auth_config: AuthConfig {
141 function_auth: FunctionAuth::AllowAll,
142 method_auth: MethodAuthTemplate::AllowAll, },
144 }
145 );
146
147 PackageDefinition { blueprints }
148 }
149
150 pub fn authorization<Y: SystemBasedKernelApi>(
151 global_address: &GlobalAddress,
152 ident: &str,
153 input: &IndexedScryptoValue,
154 api: &mut SystemService<Y>,
155 ) -> Result<ResolvedPermission, RuntimeError> {
156 let permission = match ident {
157 ROLE_ASSIGNMENT_SET_IDENT => {
158 let input: RoleAssignmentSetInput = input.as_typed().map_err(|e| {
159 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
160 })?;
161 let role_list = Self::resolve_update_role_method_permission(
162 global_address.as_node_id(),
163 input.module,
164 &input.role_key,
165 api,
166 )?;
167 ResolvedPermission::RoleList {
168 role_assignment_of: global_address.clone(),
169 role_list,
170 module_id: input.module,
171 }
172 }
173 ROLE_ASSIGNMENT_SET_OWNER_IDENT => {
174 Self::resolve_update_owner_role_method_permission(global_address.as_node_id(), api)?
175 }
176 ROLE_ASSIGNMENT_LOCK_OWNER_IDENT => {
177 Self::resolve_update_owner_role_method_permission(global_address.as_node_id(), api)?
178 }
179 ROLE_ASSIGNMENT_GET_IDENT | ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT => {
180 ResolvedPermission::AllowAll
181 }
182 _ => {
183 return Err(RuntimeError::SystemModuleError(
184 SystemModuleError::AuthError(AuthError::NoMethodMapping(FnIdentifier {
185 blueprint_id: BlueprintId::new(
186 &ROLE_ASSIGNMENT_MODULE_PACKAGE,
187 ROLE_ASSIGNMENT_BLUEPRINT,
188 ),
189 ident: ident.to_string(),
190 })),
191 ));
192 }
193 };
194
195 Ok(permission)
196 }
197
198 pub fn invoke_export<Y: SystemApi<RuntimeError>>(
199 export_name: &str,
200 input: &IndexedScryptoValue,
201 api: &mut Y,
202 ) -> Result<IndexedScryptoValue, RuntimeError> {
203 match export_name {
204 ROLE_ASSIGNMENT_CREATE_IDENT => {
205 let input: RoleAssignmentCreateInput = input.as_typed().map_err(|e| {
206 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
207 })?;
208
209 let rtn = Self::create(input.owner_role, input.roles, api)?;
210 Ok(IndexedScryptoValue::from_typed(&rtn))
211 }
212 ROLE_ASSIGNMENT_SET_OWNER_IDENT => {
213 let input: RoleAssignmentSetOwnerInput = input.as_typed().map_err(|e| {
214 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
215 })?;
216
217 let rtn = Self::set_owner_role(input.rule, api)?;
218 Ok(IndexedScryptoValue::from_typed(&rtn))
219 }
220 ROLE_ASSIGNMENT_LOCK_OWNER_IDENT => {
221 let _input: RoleAssignmentLockOwnerInput = input.as_typed().map_err(|e| {
222 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
223 })?;
224
225 let rtn = Self::lock_owner_role(api)?;
226 Ok(IndexedScryptoValue::from_typed(&rtn))
227 }
228 ROLE_ASSIGNMENT_SET_IDENT => {
229 let input: RoleAssignmentSetInput = input.as_typed().map_err(|e| {
230 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
231 })?;
232
233 let rtn = Self::set_role(input.module, input.role_key, input.rule, api)?;
234 Ok(IndexedScryptoValue::from_typed(&rtn))
235 }
236 ROLE_ASSIGNMENT_GET_IDENT => {
237 let input: RoleAssignmentGetInput = input.as_typed().map_err(|e| {
238 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
239 })?;
240
241 let rtn = Self::get_role(input.module, input.role_key, api)?;
242 Ok(IndexedScryptoValue::from_typed(&rtn))
243 }
244 _ => Err(RuntimeError::ApplicationError(
245 ApplicationError::ExportDoesNotExist(export_name.to_string()),
246 )),
247 }
248 }
249
250 pub fn is_role_key_reserved(role_key: &RoleKey) -> bool {
254 return role_key.key.starts_with("_");
255 }
256
257 pub fn is_role_key_reserved_and_defined(role_key: &RoleKey) -> bool {
261 Self::is_role_key_reserved(role_key)
262 && (role_key.key.eq(OWNER_ROLE) || role_key.key.eq(SELF_ROLE))
263 }
264
265 pub fn verify_access_rule(access_rule: &AccessRule) -> Result<(), RoleAssignmentError> {
266 pub struct AccessRuleVerifier(usize);
267 impl AccessRuleVisitor for AccessRuleVerifier {
268 type Error = RoleAssignmentError;
269 fn visit(
270 &mut self,
271 _node: &CompositeRequirement,
272 depth: usize,
273 ) -> Result<(), Self::Error> {
274 if depth > MAX_ACCESS_RULE_DEPTH {
276 return Err(RoleAssignmentError::ExceededMaxAccessRuleDepth);
277 }
278
279 self.0 += 1;
280
281 if self.0 > MAX_COMPOSITE_REQUIREMENTS {
282 return Err(RoleAssignmentError::ExceededMaxAccessRuleNodes);
283 }
284
285 Ok(())
286 }
287 }
288
289 access_rule.dfs_traverse_nodes(&mut AccessRuleVerifier(0))
290 }
291
292 fn resolve_update_owner_role_method_permission<Y: SystemBasedKernelApi>(
293 receiver: &NodeId,
294 api: &mut SystemService<Y>,
295 ) -> Result<ResolvedPermission, RuntimeError> {
296 let handle = api.kernel_open_substate(
297 receiver,
298 ROLE_ASSIGNMENT_BASE_PARTITION
299 .at_offset(ROLE_ASSIGNMENT_FIELDS_PARTITION_OFFSET)
300 .unwrap(),
301 &SubstateKey::Field(0u8),
302 LockFlags::read_only(),
303 SystemLockData::default(),
304 )?;
305
306 let owner_role_substate: FieldSubstate<RoleAssignmentOwnerFieldPayload> =
307 api.kernel_read_substate(handle)?.as_typed().unwrap();
308 api.kernel_close_substate(handle)?;
309
310 let owner_role = owner_role_substate
311 .into_payload()
312 .fully_update_and_into_latest_version();
313
314 let rule = match owner_role.owner_role_entry.updater {
315 OwnerRoleUpdater::None => AccessRule::DenyAll,
316 OwnerRoleUpdater::Owner => owner_role.owner_role_entry.rule,
317 OwnerRoleUpdater::Object => rule!(require(global_caller(GlobalAddress::new_or_panic(
318 receiver.0
319 )))),
320 };
321
322 Ok(ResolvedPermission::AccessRule(rule))
323 }
324
325 fn resolve_update_role_method_permission<Y: SystemBasedKernelApi>(
326 receiver: &NodeId,
327 module: ModuleId,
328 role_key: &RoleKey,
329 service: &mut SystemService<Y>,
330 ) -> Result<RoleList, RuntimeError> {
331 if Self::is_role_key_reserved(&role_key) || module.eq(&ModuleId::RoleAssignment) {
332 return Ok(RoleList::none());
333 }
334
335 let blueprint_id = service
336 .get_blueprint_info(receiver, module.into())?
337 .blueprint_id;
338
339 let auth_template = PackageAuthNativeBlueprint::get_bp_auth_template(
340 blueprint_id.package_address.as_node_id(),
341 &BlueprintVersionKey::new_default(blueprint_id.blueprint_name.as_str()),
342 service.api(),
343 )?
344 .method_auth;
345
346 match auth_template {
347 MethodAuthTemplate::AllowAll => Ok(RoleList::none()),
348 MethodAuthTemplate::StaticRoleDefinition(roles) => match roles.roles {
349 RoleSpecification::Normal(roles) => match roles.get(role_key) {
350 Some(role_list) => Ok(role_list.clone()),
351 None => Ok(RoleList::none()),
352 },
353 RoleSpecification::UseOuter => Ok(RoleList::none()),
354 },
355 }
356 }
357
358 pub fn init_system_struct(
359 owner_role: OwnerRoleEntry,
360 roles: IndexMap<ModuleId, RoleAssignmentInit>,
361 ) -> Result<
362 (
363 IndexMap<u8, FieldValue>,
364 IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
365 ),
366 RoleAssignmentError,
367 > {
368 if roles.contains_key(&ModuleId::RoleAssignment) {
369 return Err(RoleAssignmentError::UsedReservedSpace);
370 }
371
372 Self::verify_access_rule(&owner_role.rule)?;
373
374 let owner_role_substate = OwnerRoleSubstate {
375 owner_role_entry: owner_role.clone(),
376 };
377
378 let owner_role_field = match owner_role.updater {
379 OwnerRoleUpdater::None => FieldValue::immutable(
380 &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
381 ),
382 OwnerRoleUpdater::Owner | OwnerRoleUpdater::Object => FieldValue::new(
383 &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
384 ),
385 };
386
387 let mut role_entries = index_map_new();
388
389 for (module, roles) in roles {
390 if roles.data.len() > MAX_ROLES {
391 return Err(RoleAssignmentError::ExceededMaxRoles);
392 }
393
394 for (role_key, role_def) in roles.data {
395 if Self::is_role_key_reserved(&role_key) {
396 return Err(RoleAssignmentError::UsedReservedRole(
397 role_key.key.to_string(),
398 ));
399 }
400 check_name(&role_key.key).map_err(RoleAssignmentError::InvalidName)?;
401
402 if role_key.key.len() > MAX_ROLE_NAME_LEN {
403 return Err(RoleAssignmentError::ExceededMaxRoleNameLen {
404 limit: MAX_ROLE_NAME_LEN,
405 actual: role_key.key.len(),
406 });
407 }
408
409 let module_role_key = ModuleRoleKey::new(module, role_key);
410
411 if let Some(access_rule) = &role_def {
412 Self::verify_access_rule(access_rule)?;
413 }
414
415 let value = role_def.map(|rule| {
416 scrypto_encode(&RoleAssignmentAccessRuleEntryPayload::from_content_source(
417 rule,
418 ))
419 .unwrap()
420 });
421
422 let kv_entry = KVEntry {
423 value,
424 locked: false,
425 };
426
427 role_entries.insert(scrypto_encode(&module_role_key).unwrap(), kv_entry);
428 }
429 }
430
431 Ok((
432 indexmap!(RoleAssignmentField::Owner.field_index() => owner_role_field),
433 indexmap!(RoleAssignmentCollection::AccessRuleKeyValue.collection_index() => role_entries),
434 ))
435 }
436
437 pub(crate) fn create<Y: SystemApi<RuntimeError>>(
438 owner_role: OwnerRoleEntry,
439 roles: IndexMap<ModuleId, RoleAssignmentInit>,
440 api: &mut Y,
441 ) -> Result<Own, RuntimeError> {
442 let (fields, kv_entries) = Self::init_system_struct(owner_role, roles).map_err(|e| {
443 RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
444 })?;
445
446 let component_id = api.new_object(
447 ROLE_ASSIGNMENT_BLUEPRINT,
448 vec![],
449 GenericArgs::default(),
450 fields,
451 kv_entries,
452 )?;
453
454 Ok(Own(component_id))
455 }
456
457 fn set_owner_role<Y: SystemApi<RuntimeError>>(
458 rule: AccessRule,
459 api: &mut Y,
460 ) -> Result<(), RuntimeError> {
461 Self::verify_access_rule(&rule).map_err(|e| {
462 RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
463 })?;
464
465 let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
466
467 let mut owner_role = api
468 .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
469 .fully_update_and_into_latest_version();
470 owner_role.owner_role_entry.rule = rule.clone();
471 api.field_write_typed(
472 handle,
473 &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
474 )?;
475 api.field_close(handle)?;
476
477 Runtime::emit_event(api, SetOwnerRoleEvent { rule })?;
478
479 Ok(())
480 }
481
482 fn lock_owner_role<Y: SystemApi<RuntimeError>>(api: &mut Y) -> Result<(), RuntimeError> {
483 let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
484 let mut owner_role = api
485 .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
486 .fully_update_and_into_latest_version();
487 owner_role.owner_role_entry.updater = OwnerRoleUpdater::None;
488 api.field_write_typed(
489 handle,
490 &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
491 )?;
492 api.field_lock(handle)?;
493 api.field_close(handle)?;
494
495 Runtime::emit_event(api, LockOwnerRoleEvent {})?;
496
497 Ok(())
498 }
499
500 fn set_role<Y: SystemApi<RuntimeError>>(
501 module: ModuleId,
502 role_key: RoleKey,
503 rule: AccessRule,
504 api: &mut Y,
505 ) -> Result<(), RuntimeError> {
506 if module.eq(&ModuleId::RoleAssignment) {
507 return Err(RuntimeError::ApplicationError(
508 ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedSpace),
509 ));
510 }
511 if Self::is_role_key_reserved(&role_key) {
512 return Err(RuntimeError::ApplicationError(
513 ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedRole(
514 role_key.key.to_string(),
515 )),
516 ));
517 }
518 if role_key.key.len() > MAX_ROLE_NAME_LEN {
519 return Err(RuntimeError::ApplicationError(
520 ApplicationError::RoleAssignmentError(
521 RoleAssignmentError::ExceededMaxRoleNameLen {
522 limit: MAX_ROLE_NAME_LEN,
523 actual: role_key.key.len(),
524 },
525 ),
526 ));
527 }
528 check_name(&role_key.key).map_err(|error| {
529 RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
530 RoleAssignmentError::InvalidName(error),
531 ))
532 })?;
533
534 let module_role_key = ModuleRoleKey::new(module, role_key.clone());
535
536 Self::verify_access_rule(&rule).map_err(|e| {
537 RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
538 })?;
539
540 api.actor_get_node_id(ACTOR_REF_GLOBAL)
544 .map_err(|e| match e {
545 RuntimeError::SystemError(SystemError::GlobalAddressDoesNotExist) => {
546 RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
547 RoleAssignmentError::CannotSetRoleIfNotAttached,
548 ))
549 }
550 _ => e,
551 })?;
552
553 let handle = api.actor_open_key_value_entry(
554 ACTOR_STATE_SELF,
555 RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
556 &scrypto_encode(&module_role_key).unwrap(),
557 LockFlags::MUTABLE,
558 )?;
559
560 api.key_value_entry_set_typed(
562 handle,
563 RoleAssignmentAccessRuleEntryPayload::from_content_source(rule.clone()),
564 )?;
565 api.key_value_entry_close(handle)?;
566
567 Runtime::emit_event(api, SetRoleEvent { role_key, rule })?;
568
569 Ok(())
570 }
571
572 pub(crate) fn get_role<Y: SystemApi<RuntimeError>>(
573 module: ModuleId,
574 role_key: RoleKey,
575 api: &mut Y,
576 ) -> Result<Option<AccessRule>, RuntimeError> {
577 let module_role_key = ModuleRoleKey::new(module, role_key);
578
579 let handle = api.actor_open_key_value_entry(
580 ACTOR_STATE_SELF,
581 RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
582 &scrypto_encode(&module_role_key).unwrap(),
583 LockFlags::read_only(),
584 )?;
585
586 let rule = api.key_value_entry_get_typed::<RoleAssignmentAccessRuleEntryPayload>(handle)?;
587
588 api.key_value_entry_close(handle)?;
589
590 Ok(rule.map(|v| v.fully_update_and_into_latest_version()))
591 }
592}
593
594pub struct RoleAssignmentBottlenoseExtension;
595
596impl RoleAssignmentBottlenoseExtension {
597 pub fn added_functions_schema() -> (
598 IndexMap<String, FunctionSchemaInit>,
599 VersionedSchema<ScryptoCustomSchema>,
600 ) {
601 let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
602 let mut functions = index_map_new();
603 functions.insert(
604 ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
605 FunctionSchemaInit {
606 receiver: Some(ReceiverInfo::normal_ref()),
607 input: TypeRef::Static(
608 aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleInput>(),
609 ),
610 output: TypeRef::Static(
611 aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleOutput>(),
612 ),
613 export: ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
614 },
615 );
616 let schema = generate_full_schema(aggregator);
617 (functions, schema)
618 }
619
620 pub fn invoke_export<Y: SystemApi<RuntimeError>>(
621 export_name: &str,
622 input: &IndexedScryptoValue,
623 api: &mut Y,
624 ) -> Result<IndexedScryptoValue, RuntimeError> {
625 match export_name {
626 ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT => {
627 input
628 .as_typed::<RoleAssignmentGetOwnerRoleInput>()
629 .map_err(|e| {
630 RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
631 })?;
632
633 let rtn = Self::get_owner_role(api)?;
634 Ok(IndexedScryptoValue::from_typed(&rtn))
635 }
636 _ => Err(RuntimeError::ApplicationError(
637 ApplicationError::ExportDoesNotExist(export_name.to_string()),
638 )),
639 }
640 }
641
642 pub(crate) fn get_owner_role<Y: SystemApi<RuntimeError>>(
643 api: &mut Y,
644 ) -> Result<OwnerRoleEntry, RuntimeError> {
645 let handle = api.actor_open_field(
646 ACTOR_STATE_SELF,
647 RoleAssignmentField::Owner.field_index(),
648 LockFlags::read_only(),
649 )?;
650 let owner_role_entry = api
651 .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
652 .fully_update_and_into_latest_version()
653 .owner_role_entry;
654 api.field_close(handle)?;
655
656 Ok(owner_role_entry)
657 }
658}