1use crate::internal_prelude::*;
2use crate::kernel::kernel_callback_api::CallFrameReferences;
3use radix_engine_interface::api::{AttachedModuleId, ModuleId};
4
5#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
6pub struct InstanceContext {
7 pub outer_object: GlobalAddress,
8}
9
10#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
11pub enum MethodType {
12 Main,
13 Direct,
14 Module(AttachedModuleId),
15}
16
17impl MethodType {
18 pub fn module_id(&self) -> ModuleId {
19 match self {
20 MethodType::Module(module_id) => (*module_id).into(),
21 MethodType::Main | MethodType::Direct => ModuleId::Main,
22 }
23 }
24}
25
26#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
27pub struct MethodActor {
28 pub method_type: MethodType,
29 pub node_id: NodeId,
30 pub ident: String,
31
32 pub auth_zone: NodeId,
33
34 pub object_info: ObjectInfo,
36}
37
38impl MethodActor {
39 pub fn get_blueprint_id(&self) -> BlueprintId {
40 match self.method_type {
41 MethodType::Main | MethodType::Direct => {
42 self.object_info.blueprint_info.blueprint_id.clone()
43 }
44 MethodType::Module(module_id) => module_id.static_blueprint(),
45 }
46 }
47}
48
49#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
50pub struct FunctionActor {
51 pub blueprint_id: BlueprintId,
52 pub ident: String,
53
54 pub auth_zone: NodeId,
55}
56
57impl FunctionActor {
58 pub fn as_global_caller(&self) -> GlobalCaller {
59 GlobalCaller::PackageBlueprint(self.blueprint_id.clone())
60 }
61}
62
63#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
64pub struct BlueprintHookActor {
65 pub receiver: Option<NodeId>,
66 pub hook: BlueprintHook,
67 pub blueprint_id: BlueprintId,
68}
69
70#[allow(clippy::large_enum_variant)]
71#[derive(Debug, Default, Clone, ScryptoSbor, PartialEq, Eq)]
72pub enum Actor {
73 #[default]
83 Root,
84 Method(MethodActor),
85 Function(FunctionActor),
86 BlueprintHook(BlueprintHookActor),
87}
88
89impl CallFrameReferences for Actor {
90 fn global_references(&self) -> Vec<NodeId> {
91 let mut global_refs = Vec::new();
92
93 if let Some(blueprint_id) = self.blueprint_id() {
94 global_refs.push(blueprint_id.package_address.into_node_id());
95 }
96
97 if let Actor::Method(MethodActor {
98 node_id,
99 object_info,
100 ..
101 }) = self
102 {
103 if let OuterObjectInfo::Some { outer_object } =
104 object_info.blueprint_info.outer_obj_info
105 {
106 global_refs.push(outer_object.into_node_id());
107 }
108
109 if node_id.is_global() {
110 global_refs.push(*node_id);
111 }
112 }
113
114 global_refs
115 }
116
117 fn direct_access_references(&self) -> Vec<NodeId> {
118 if self.is_direct_access() {
119 self.node_id().into_iter().collect()
120 } else {
121 vec![]
122 }
123 }
124
125 fn stable_transient_references(&self) -> Vec<NodeId> {
126 let mut references = vec![];
127 references.extend(self.self_auth_zone());
128
129 if !self.is_direct_access() {
130 references.extend(self.node_id().filter(|n| !n.is_global()));
131 }
132
133 references
134 }
135
136 fn len(&self) -> usize {
137 match self {
138 Actor::Root => 1,
139 Actor::Method(MethodActor { ident, node_id, .. }) => {
140 node_id.as_bytes().len() + ident.len()
141 }
142 Actor::Function(FunctionActor {
143 blueprint_id,
144 ident,
145 ..
146 }) => {
147 blueprint_id.package_address.as_bytes().len()
148 + blueprint_id.blueprint_name.len()
149 + ident.len()
150 }
151 Actor::BlueprintHook(BlueprintHookActor { blueprint_id, .. }) => {
152 blueprint_id.package_address.as_bytes().len()
153 + blueprint_id.blueprint_name.len()
154 + 1
155 }
156 }
157 }
158}
159
160impl Actor {
161 pub fn is_root(&self) -> bool {
162 matches!(self, Actor::Root)
163 }
164
165 pub fn self_auth_zone(&self) -> Option<NodeId> {
166 match self {
167 Actor::Root | Actor::BlueprintHook(..) => None,
168 Actor::Method(method_actor) => Some(method_actor.auth_zone),
169 Actor::Function(function_actor) => Some(function_actor.auth_zone),
170 }
171 }
172
173 pub fn instance_context(&self) -> Option<InstanceContext> {
174 let method_actor = match self {
175 Actor::Method(method_actor) => method_actor,
176 _ => return None,
177 };
178
179 match method_actor.method_type {
180 MethodType::Main | MethodType::Direct => {
181 if method_actor.object_info.is_global() {
182 Some(InstanceContext {
183 outer_object: GlobalAddress::new_or_panic(method_actor.node_id.0),
184 })
185 } else {
186 match &method_actor.object_info.blueprint_info.outer_obj_info {
187 OuterObjectInfo::Some { outer_object } => Some(InstanceContext {
188 outer_object: *outer_object,
189 }),
190 OuterObjectInfo::None => None,
191 }
192 }
193 }
194 _ => None,
195 }
196 }
197
198 pub fn get_object_id(&self) -> Option<(NodeId, Option<AttachedModuleId>)> {
199 match self {
200 Actor::Method(method_actor) => Some((
201 method_actor.node_id,
202 method_actor.method_type.module_id().into(),
203 )),
204 Actor::BlueprintHook(BlueprintHookActor {
205 receiver: Some(node_id),
206 ..
207 }) => Some((*node_id, None)),
208 Actor::BlueprintHook(..) | Actor::Root | Actor::Function(..) => None,
209 }
210 }
211
212 pub fn is_barrier(&self) -> bool {
213 match self {
214 Actor::Method(MethodActor { object_info, .. }) => object_info.is_global(),
215 Actor::Function { .. } => true,
216 Actor::BlueprintHook { .. } => true,
217 Actor::Root => false,
218 }
219 }
220
221 pub fn node_id(&self) -> Option<NodeId> {
222 match self {
223 Actor::Method(MethodActor { node_id, .. }) => Some(*node_id),
224 Actor::BlueprintHook(BlueprintHookActor {
225 receiver: node_id, ..
226 }) => *node_id,
227 _ => None,
228 }
229 }
230
231 pub fn is_direct_access(&self) -> bool {
232 match self {
233 Actor::Method(MethodActor { method_type, .. }) => {
234 matches!(method_type, MethodType::Direct)
235 }
236 _ => false,
237 }
238 }
239
240 pub fn blueprint_id(&self) -> Option<BlueprintId> {
241 match self {
242 Actor::Method(actor) => Some(actor.get_blueprint_id()),
243 Actor::Function(FunctionActor { blueprint_id, .. })
244 | Actor::BlueprintHook(BlueprintHookActor { blueprint_id, .. }) => {
245 Some(blueprint_id.clone())
246 }
247 Actor::Root => None,
248 }
249 }
250
251 pub fn package_address(&self) -> Option<PackageAddress> {
252 self.blueprint_id().map(|id| id.package_address)
253 }
254}