radix_engine/system/transaction/
multithread_intent_processor.rs1use crate::blueprints::resource::AuthZone;
2use crate::blueprints::transaction_processor::{
3 IntentProcessor, ResumeResult, MAX_TOTAL_BLOB_SIZE_PER_INVOCATION,
4};
5use crate::errors::{KernelError, RuntimeError, SystemError};
6use crate::internal_prelude::*;
7use crate::kernel::kernel_callback_api::KernelCallbackObject;
8use crate::system::actor::{Actor, FunctionActor};
9use crate::system::node_init::type_info_partition;
10use crate::system::system::SystemService;
11use crate::system::system_callback::{System, SystemBasedKernelApi};
12use crate::system::system_modules::auth::{AuthModule, Authorization, AuthorizationCheckResult};
13use crate::system::type_info::TypeInfoSubstate;
14use radix_common::constants::{RESOURCE_PACKAGE, TRANSACTION_PROCESSOR_PACKAGE};
15use radix_common::prelude::{BlueprintId, EntityType, GlobalAddressReservation, Reference};
16use radix_common::types::{GlobalCaller, NodeId};
17use radix_engine_interface::blueprints::package::BlueprintVersion;
18use radix_engine_interface::blueprints::transaction_processor::{
19 TRANSACTION_PROCESSOR_BLUEPRINT, TRANSACTION_PROCESSOR_RUN_IDENT,
20};
21use radix_engine_interface::prelude::{
22 AccessRule, AuthZoneField, BlueprintInfo, ObjectInfo, ObjectType, OuterObjectInfo,
23 AUTH_ZONE_BLUEPRINT, FUNGIBLE_PROOF_BLUEPRINT, MAIN_BASE_PARTITION,
24 NON_FUNGIBLE_PROOF_BLUEPRINT, TYPE_INFO_FIELD_PARTITION,
25};
26use radix_rust::prelude::*;
27use radix_transactions::model::{ExecutableTransaction, InstructionV2};
28use sbor::prelude::ToString;
29
30pub struct MultiThreadIntentProcessor<'e> {
32 pub threads: Vec<(IntentProcessor<'e, InstructionV2>, Vec<usize>)>,
33}
34
35impl<'e> MultiThreadIntentProcessor<'e> {
36 pub fn init<Y: SystemBasedKernelApi>(
37 executable: &'e ExecutableTransaction,
38 global_address_reservations: &[GlobalAddressReservation],
39 api: &mut Y,
40 ) -> Result<Self, RuntimeError> {
41 let mut txn_processors = vec![];
42
43 for (thread_id, intent) in executable.all_intents().enumerate() {
45 api.kernel_switch_stack(thread_id)?;
46
47 let mut system_service = SystemService::new(api);
51 let simulate_every_proof_under_resources = intent
52 .auth_zone_init
53 .simulate_every_proof_under_resources
54 .clone();
55 let initial_non_fungible_id_proofs =
56 intent.auth_zone_init.initial_non_fungible_id_proofs.clone();
57 let auth_zone = AuthModule::create_auth_zone(
58 &mut system_service,
59 None,
60 simulate_every_proof_under_resources,
61 initial_non_fungible_id_proofs,
62 )?;
63
64 api.kernel_set_call_frame_data(Actor::Function(FunctionActor {
65 blueprint_id: BlueprintId::new(
66 &TRANSACTION_PROCESSOR_PACKAGE,
67 TRANSACTION_PROCESSOR_BLUEPRINT,
68 ),
69 ident: TRANSACTION_PROCESSOR_RUN_IDENT.to_string(),
70 auth_zone,
71 }))?;
72
73 let mut system_service = SystemService::new(api);
74 let txn_processor = IntentProcessor::<InstructionV2>::init(
75 intent.encoded_instructions.as_ref(),
76 global_address_reservations,
77 &intent.blobs,
78 MAX_TOTAL_BLOB_SIZE_PER_INVOCATION,
79 &mut system_service,
80 )?;
81
82 txn_processors.push((
83 txn_processor,
84 intent
85 .children_subintent_indices
86 .iter()
87 .map(|index| index.0 + 1)
88 .collect::<Vec<_>>(),
89 ));
90 }
91 Ok(Self {
92 threads: txn_processors,
93 })
94 }
95
96 pub fn execute<Y: SystemBasedKernelApi>(&mut self, api: &mut Y) -> Result<(), RuntimeError> {
97 let mut cur_thread = 0;
98 let mut parent_stack = vec![];
99 let mut passed_value = None;
100
101 enum PostExecution {
102 SwitchThread(usize, IndexedScryptoValue, bool),
103 VerifyParent(AccessRule),
104 RootIntentDone,
105 }
106
107 loop {
108 api.kernel_switch_stack(cur_thread)?;
109 let (txn_thread, children_mapping) = self.threads.get_mut(cur_thread).unwrap();
110
111 let mut system_service = SystemService::new(api);
112 let post_exec = match txn_thread.resume(passed_value.take(), &mut system_service)? {
113 ResumeResult::YieldToChild(child, value) => {
114 let child = *children_mapping
115 .get(child)
116 .ok_or(RuntimeError::SystemError(SystemError::IntentError(
117 IntentError::InvalidIntentIndex(child),
118 )))?;
119 parent_stack.push(cur_thread);
120 PostExecution::SwitchThread(child, value, false)
121 }
122 ResumeResult::YieldToParent(value) => {
123 let parent = parent_stack.pop().ok_or(RuntimeError::SystemError(
124 SystemError::IntentError(IntentError::NoParentToYieldTo),
125 ))?;
126 PostExecution::SwitchThread(parent, value, false)
127 }
128 ResumeResult::VerifyParent(rule) => PostExecution::VerifyParent(rule),
129 ResumeResult::DoneAndYieldToParent(value) => {
130 let parent = parent_stack.pop().ok_or(RuntimeError::SystemError(
131 SystemError::IntentError(IntentError::NoParentToYieldTo),
132 ))?;
133 PostExecution::SwitchThread(parent, value, true)
134 }
135 ResumeResult::Done => PostExecution::RootIntentDone,
136 };
137
138 match post_exec {
139 PostExecution::SwitchThread(next_thread, value, intent_done) => {
140 Self::check_yielded_value(&value, api)?;
142 api.kernel_send_to_stack(next_thread, &value)?;
143 passed_value = Some(value);
144
145 if intent_done {
147 Self::cleanup_stack(api)?;
148 }
149
150 cur_thread = next_thread;
151 }
152 PostExecution::VerifyParent(rule) => {
153 let save_cur_thread = cur_thread;
154 let system_version = api.system_service().system().versioned_system_logic;
155
156 let parent = if system_version.use_root_for_verify_parent_instruction() {
157 parent_stack.first()
158 } else {
159 parent_stack.last()
161 };
162 let parent_thread_index = parent.cloned().ok_or(RuntimeError::SystemError(
163 SystemError::IntentError(IntentError::CannotVerifyParentOnRoot),
164 ))?;
165 api.kernel_switch_stack(parent_thread_index)?;
166
167 {
171 let auth_zone = Self::create_temp_child_auth_zone_for_verify_parent(api)?;
172 let mut system_service = SystemService::new(api);
173 let auth_result = Authorization::check_authorization_against_access_rule(
174 &mut system_service,
175 &auth_zone,
176 &rule,
177 )?;
178 match auth_result {
179 AuthorizationCheckResult::Authorized => {}
180 AuthorizationCheckResult::Failed(..) => {
181 return Err(RuntimeError::SystemError(SystemError::IntentError(
182 IntentError::VerifyParentFailed,
183 )))
184 }
185 }
186 api.kernel_drop_node(&auth_zone)?;
187 }
188
189 api.kernel_switch_stack(save_cur_thread)?;
190 }
191 PostExecution::RootIntentDone => {
192 Self::cleanup_stack(api)?;
193 break;
194 }
195 }
196 }
197
198 assert!(parent_stack.is_empty());
199
200 Ok(())
201 }
202
203 fn create_temp_child_auth_zone_for_verify_parent<Y: SystemBasedKernelApi>(
204 api: &mut Y,
205 ) -> Result<NodeId, RuntimeError> {
206 let actor = api.kernel_get_system_state().current_call_frame;
207 let auth_zone = actor.self_auth_zone().unwrap();
208 let blueprint_id = actor.blueprint_id().unwrap();
209 let auth_zone = AuthZone::new(
210 vec![],
211 Default::default(),
212 Default::default(),
213 None,
214 Some((
215 GlobalCaller::PackageBlueprint(blueprint_id),
216 Reference(auth_zone),
217 )),
218 None,
219 );
220
221 let new_auth_zone = api.kernel_allocate_node_id(EntityType::InternalGenericComponent)?;
222
223 api.kernel_create_node(
224 new_auth_zone,
225 btreemap!(
226 MAIN_BASE_PARTITION => btreemap!(
227 AuthZoneField::AuthZone.into() => IndexedScryptoValue::from_typed(&FieldSubstate::new_unlocked_field(auth_zone))
228 ),
229 TYPE_INFO_FIELD_PARTITION => type_info_partition(TypeInfoSubstate::Object(ObjectInfo {
230 blueprint_info: BlueprintInfo {
231 blueprint_id: BlueprintId::new(&RESOURCE_PACKAGE, AUTH_ZONE_BLUEPRINT),
232 blueprint_version: BlueprintVersion::default(),
233 outer_obj_info: OuterObjectInfo::default(),
234 features: indexset!(),
235 generic_substitutions: vec![],
236 },
237 object_type: ObjectType::Owned,
238 }))
239 ),
240 )?;
241 api.kernel_pin_node(new_auth_zone)?;
242
243 Ok(new_auth_zone)
244 }
245
246 fn check_yielded_value<Y: SystemBasedKernelApi>(
247 value: &IndexedScryptoValue,
248 api: &mut Y,
249 ) -> Result<(), RuntimeError> {
250 let mut system_service = SystemService::new(api);
251 for node_id in value.owned_nodes() {
252 let object_info: ObjectInfo = system_service.get_object_info(node_id)?;
253
254 let blueprint_id = object_info.blueprint_info.blueprint_id;
255 if let (RESOURCE_PACKAGE, FUNGIBLE_PROOF_BLUEPRINT | NON_FUNGIBLE_PROOF_BLUEPRINT) = (
256 blueprint_id.package_address,
257 blueprint_id.blueprint_name.as_str(),
258 ) {
259 return Err(RuntimeError::SystemError(SystemError::IntentError(
260 IntentError::CannotYieldProof,
261 )));
262 }
263 }
264
265 Ok(())
266 }
267
268 fn cleanup_stack<Y: SystemBasedKernelApi>(api: &mut Y) -> Result<(), RuntimeError> {
269 let owned_nodes = api.kernel_get_owned_nodes()?;
270 System::auto_drop(owned_nodes, api)?;
271
272 let actor = api.kernel_get_system_state().current_call_frame;
273 match actor {
274 Actor::Function(FunctionActor { auth_zone, .. }) => {
275 let auth_zone = *auth_zone;
276 let mut system_service = SystemService::new(api);
277 AuthModule::teardown_auth_zone(&mut system_service, auth_zone)?;
278 }
279 _ => {
280 panic!("unexpected");
281 }
282 }
283 let owned_nodes = api.kernel_get_owned_nodes()?;
284 if !owned_nodes.is_empty() {
285 return Err(RuntimeError::KernelError(KernelError::OrphanedNodes(
286 owned_nodes
287 .into_iter()
288 .map(|node_id| node_id.into())
289 .collect(),
290 )));
291 }
292
293 Ok(())
294 }
295}