1use crate::internal_prelude::*;
2use crate::kernel::kernel_api::DroppedNode;
3use crate::kernel::kernel_callback_api::CallFrameReferences;
4use crate::kernel::substate_io::{
5 IOAccessHandler, SubstateDevice, SubstateIO, SubstateReadHandler,
6};
7use crate::track::interface::{CallbackError, CommitableSubstateStore, IOAccess, NodeSubstates};
8use radix_engine_interface::api::field_api::LockFlags;
9use radix_engine_interface::types::{NodeId, SubstateHandle, SubstateKey};
10use radix_substate_store_interface::db_key_mapper::SubstateKeyContent;
11
12use super::heap::{Heap, HeapRemovePartitionError};
13
14#[derive(Default, Debug, Clone, PartialEq, Eq)]
18pub struct CallFrameMessage {
19 pub move_nodes: Vec<NodeId>,
21
22 pub copy_global_references: Vec<NodeId>,
24
25 pub copy_direct_access_references: Vec<NodeId>,
27
28 pub copy_stable_transient_references: Vec<NodeId>,
32}
33
34impl CallFrameMessage {
35 pub fn from_input<C: CallFrameReferences>(value: &IndexedScryptoValue, references: &C) -> Self {
36 let mut copy_global_references = Vec::new();
37 let mut copy_direct_access_references = Vec::new();
38
39 for arg_ref in value.references().clone() {
40 if arg_ref.is_global() {
41 copy_global_references.push(arg_ref);
42 } else {
43 copy_direct_access_references.push(arg_ref);
44 }
45 }
46
47 copy_global_references.extend(references.global_references());
48 copy_direct_access_references.extend(references.direct_access_references());
49
50 Self {
51 move_nodes: value.owned_nodes().clone(),
52 copy_global_references,
53 copy_direct_access_references,
54 copy_stable_transient_references: references.stable_transient_references(),
55 }
56 }
57
58 pub fn from_output(value: &IndexedScryptoValue) -> Self {
59 let mut copy_global_references = Vec::new();
60 let mut copy_direct_access_references = Vec::new();
61
62 for arg_ref in value.references().clone() {
63 if arg_ref.is_global() {
64 copy_global_references.push(arg_ref);
65 } else {
66 copy_direct_access_references.push(arg_ref);
67 }
68 }
69
70 Self {
71 move_nodes: value.owned_nodes().clone(),
72 copy_global_references,
73 copy_direct_access_references,
74 copy_stable_transient_references: vec![],
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
80pub struct OpenedSubstate<L> {
81 pub references: IndexSet<NodeId>,
82 pub owned_nodes: IndexSet<NodeId>,
83 pub ref_origin: ReferenceOrigin,
84 pub global_substate_handle: u32,
85 pub device: SubstateDevice,
86 pub data: L,
87}
88
89impl<L> OpenedSubstate<L> {
90 fn diff_on_close(&self) -> SubstateDiff {
91 SubstateDiff {
92 added_owns: index_set_new(),
93 added_refs: index_set_new(),
94 removed_owns: self.owned_nodes.clone(),
95 removed_refs: self.references.clone(),
96 }
97 }
98
99 fn diff(&self, updated_value: &IndexedScryptoValue) -> Result<SubstateDiff, SubstateDiffError> {
100 let (added_owned_nodes, removed_owned_nodes) = {
102 let mut added_owned_nodes: IndexSet<NodeId> = index_set_new();
103 let mut new_owned_nodes: IndexSet<NodeId> = index_set_new();
104 for own in updated_value.owned_nodes() {
105 if !new_owned_nodes.insert(own.clone()) {
106 return Err(SubstateDiffError::ContainsDuplicateOwns);
107 }
108
109 if !self.owned_nodes.contains(own) {
110 added_owned_nodes.insert(*own);
111 }
112 }
113
114 let mut removed_owned_nodes: IndexSet<NodeId> = index_set_new();
115 for own in &self.owned_nodes {
116 if !new_owned_nodes.contains(own) {
117 removed_owned_nodes.insert(*own);
118 }
119 }
120
121 (added_owned_nodes, removed_owned_nodes)
122 };
123
124 let (added_references, removed_references) = {
128 let updated_references: IndexSet<NodeId> =
130 updated_value.references().clone().into_iter().collect();
131
132 let mut added_references: IndexSet<NodeId> = index_set_new();
133 for reference in &updated_references {
134 let reference_is_new = !self.references.contains(reference);
135
136 if reference_is_new {
137 added_references.insert(reference.clone());
138 }
139 }
140
141 let mut removed_references: IndexSet<NodeId> = index_set_new();
142 for old_ref in &self.references {
143 if !updated_references.contains(old_ref) {
144 removed_references.insert(*old_ref);
145 }
146 }
147
148 (added_references, removed_references)
149 };
150
151 Ok(SubstateDiff {
152 added_owns: added_owned_nodes,
153 removed_owns: removed_owned_nodes,
154 added_refs: added_references,
155 removed_refs: removed_references,
156 })
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161struct SubstateDiff {
162 added_owns: IndexSet<NodeId>,
163 removed_owns: IndexSet<NodeId>,
164 added_refs: IndexSet<NodeId>,
165 removed_refs: IndexSet<NodeId>,
166}
167
168impl SubstateDiff {
169 pub fn from_new_substate(
170 substate_value: &IndexedScryptoValue,
171 ) -> Result<Self, SubstateDiffError> {
172 let mut added_owns = index_set_new();
173 let mut added_refs = index_set_new();
174
175 for own in substate_value.owned_nodes() {
176 if !added_owns.insert(own.clone()) {
177 return Err(SubstateDiffError::ContainsDuplicateOwns);
178 }
179 }
180
181 for reference in substate_value.references() {
182 added_refs.insert(reference.clone());
183 }
184
185 Ok(Self {
186 added_owns,
187 added_refs,
188 removed_owns: index_set_new(),
189 removed_refs: index_set_new(),
190 })
191 }
192
193 pub fn from_drop_substate(substate_value: &IndexedScryptoValue) -> Self {
194 let mut removed_owns = index_set_new();
195 let mut removed_refs = index_set_new();
196
197 for own in substate_value.owned_nodes() {
198 if !removed_owns.insert(own.clone()) {
199 panic!("Should never have been able to create duplicate owns");
200 }
201 }
202
203 for reference in substate_value.references() {
204 removed_refs.insert(reference.clone());
205 }
206
207 Self {
208 added_owns: index_set_new(),
209 added_refs: index_set_new(),
210 removed_owns,
211 removed_refs,
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
217pub enum StableReferenceType {
218 Global,
219 DirectAccess,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
223pub struct TransientReference {
224 ref_count: usize,
225 ref_origin: ReferenceOrigin,
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
229pub enum ReferenceOrigin {
230 FrameOwned,
231 Global(GlobalAddress),
232 DirectlyAccessed,
233 SubstateNonGlobalReference(SubstateDevice),
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
237pub enum Visibility {
238 StableReference(StableReferenceType),
239 FrameOwned,
240 Borrowed(ReferenceOrigin),
241}
242
243impl Visibility {
244 pub fn is_direct_access(&self) -> bool {
245 matches!(
246 self,
247 Self::StableReference(StableReferenceType::DirectAccess)
248 )
249 }
250
251 pub fn is_normal(&self) -> bool {
252 !self.is_direct_access()
253 }
254}
255
256pub struct NodeVisibility(pub BTreeSet<Visibility>);
257
258impl NodeVisibility {
259 pub fn is_visible(&self) -> bool {
263 !self.0.is_empty()
264 }
265
266 pub fn can_be_invoked(&self, direct_access: bool) -> bool {
267 if direct_access {
268 self.0.iter().any(|x| x.is_direct_access())
269 } else {
270 self.0.iter().any(|x| x.is_normal())
271 }
272 }
273
274 pub fn can_be_referenced_in_substate(&self) -> bool {
275 self.0.iter().any(|x| x.is_normal())
276 }
277
278 pub fn is_global(&self) -> bool {
279 for v in &self.0 {
280 if let Visibility::StableReference(StableReferenceType::Global) = v {
281 return true;
282 }
283 }
284 return false;
285 }
286
287 pub fn reference_origin(&self, node_id: NodeId) -> Option<ReferenceOrigin> {
289 let mut found_direct_access = false;
290 for v in &self.0 {
291 match v {
292 Visibility::StableReference(StableReferenceType::Global) => {
293 return Some(ReferenceOrigin::Global(GlobalAddress::new_or_panic(
294 node_id.0,
295 )));
296 }
297 Visibility::StableReference(StableReferenceType::DirectAccess) => {
298 found_direct_access = true
299 }
300 Visibility::Borrowed(ref_origin) => return Some(ref_origin.clone()),
301 Visibility::FrameOwned => {
302 return Some(ReferenceOrigin::FrameOwned);
303 }
304 }
305 }
306
307 if found_direct_access {
308 return Some(ReferenceOrigin::DirectlyAccessed);
309 }
310
311 return None;
312 }
313}
314
315pub trait CallFrameIOAccessHandler<C, L, E> {
317 fn on_io_access(
318 &mut self,
319 current_frame: &CallFrame<C, L>,
320 heap: &Heap,
321 io_access: IOAccess,
322 ) -> Result<(), E>;
323}
324
325pub trait CallFrameSubstateReadHandler<C, L> {
327 type Error;
328
329 fn on_read_substate(
330 &mut self,
331 current_frame: &CallFrame<C, L>,
332 heap: &Heap,
333 handle: SubstateHandle,
334 value: &IndexedScryptoValue,
335 device: SubstateDevice,
336 ) -> Result<(), Self::Error>;
337}
338
339struct CallFrameToIOAccessAdapter<'g, C, L, E, H: CallFrameIOAccessHandler<C, L, E>> {
340 handler: &'g mut H,
341 call_frame: &'g mut CallFrame<C, L>,
342 phantom: PhantomData<E>,
343}
344
345impl<'g, C, L, E, H: CallFrameIOAccessHandler<C, L, E>> IOAccessHandler<E>
346 for CallFrameToIOAccessAdapter<'g, C, L, E, H>
347{
348 fn on_io_access(&mut self, heap: &Heap, io_access: IOAccess) -> Result<(), E> {
349 self.handler.on_io_access(self.call_frame, heap, io_access)
350 }
351}
352
353struct CallFrameToIOSubstateReadAdapter<'g, C, L, H: CallFrameSubstateReadHandler<C, L>> {
354 handler: &'g mut H,
355 call_frame: &'g CallFrame<C, L>,
356 handle: SubstateHandle,
357}
358
359impl<'g, C, L, H: CallFrameSubstateReadHandler<C, L>> SubstateReadHandler
360 for CallFrameToIOSubstateReadAdapter<'g, C, L, H>
361{
362 type Error = H::Error;
363
364 fn on_read_substate(
365 &mut self,
366 heap: &Heap,
367 value: &IndexedScryptoValue,
368 location: SubstateDevice,
369 ) -> Result<(), Self::Error> {
370 self.handler
371 .on_read_substate(self.call_frame, heap, self.handle, value, location)
372 }
373}
374
375pub struct CallFrame<C, L> {
378 stack_id: usize,
380
381 depth: usize,
383
384 call_frame_data: C,
386
387 owned_root_nodes: IndexSet<NodeId>,
389
390 transient_references: NonIterMap<NodeId, TransientReference>,
393
394 stable_references: BTreeMap<NodeId, StableReferenceType>,
398
399 next_handle: SubstateHandle,
400 open_substates: IndexMap<SubstateHandle, OpenedSubstate<L>>,
401
402 always_visible_global_nodes: &'static IndexSet<NodeId>,
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
408pub enum CreateFrameError {
409 PassMessageError(PassMessageError),
410}
411
412#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
414pub enum PassMessageError {
415 TakeNodeError(TakeNodeError),
416 GlobalRefNotFound(error_models::ReferencedNodeId),
417 DirectRefNotFound(error_models::ReferencedNodeId),
418 TransientRefNotFound(error_models::ReferencedNodeId),
419}
420
421#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
423pub enum CreateNodeError {
424 ProcessSubstateError(ProcessSubstateError),
425 ProcessSubstateKeyError(ProcessSubstateKeyError),
426 SubstateDiffError(SubstateDiffError),
427}
428
429#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
431pub enum DropNodeError {
432 TakeNodeError(TakeNodeError),
433 NodeBorrowed(error_models::ReferencedNodeId),
434 SubstateBorrowed(error_models::ReferencedNodeId),
435 ProcessSubstateError(ProcessSubstateError),
436}
437
438#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
440pub enum PersistNodeError {
441 ContainsNonGlobalRef(error_models::ReferencedNodeId),
442 NodeBorrowed(error_models::ReferencedNodeId),
443 CannotPersistPinnedNode(error_models::OwnedNodeId),
444}
445
446#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
448pub enum TakeNodeError {
449 OwnNotFound(error_models::OwnedNodeId),
450 SubstateBorrowed(error_models::ReferencedNodeId),
451}
452
453#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
455pub enum MovePartitionError {
456 NodeNotAvailable(error_models::ReferencedNodeId),
457 HeapRemovePartitionError(HeapRemovePartitionError),
458 NonGlobalRefNotAllowed(error_models::ReferencedNodeId),
459 PersistNodeError(PersistNodeError),
460 SubstateBorrowed(error_models::ReferencedNodeId),
461 MoveFromStoreNotPermitted,
462}
463
464#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
465pub enum PinNodeError {
466 NodeNotVisible(error_models::ReferencedNodeId),
467}
468
469#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
470pub enum MarkTransientSubstateError {
471 NodeNotVisible(error_models::ReferencedNodeId),
472}
473
474#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
476pub enum OpenSubstateError {
477 NodeNotVisible(error_models::ReferencedNodeId),
478 SubstateFault,
479 InvalidDefaultValue,
480 ProcessSubstateKeyError(ProcessSubstateKeyError),
481 SubstateLocked(error_models::OwnedNodeId, PartitionNumber, SubstateKey),
482 LockUnmodifiedBaseOnHeapNode,
483 LockUnmodifiedBaseOnNewSubstate(error_models::OwnedNodeId, PartitionNumber, SubstateKey),
484 LockUnmodifiedBaseOnOnUpdatedSubstate(error_models::OwnedNodeId, PartitionNumber, SubstateKey),
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
489pub enum ReadSubstateError {
490 HandleNotFound(SubstateHandle),
491}
492
493#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
495pub enum WriteSubstateError {
496 HandleNotFound(SubstateHandle),
497 ProcessSubstateError(ProcessSubstateError),
498 NoWritePermission,
499 SubstateDiffError(SubstateDiffError),
500}
501
502#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
504pub enum CloseSubstateError {
505 HandleNotFound(SubstateHandle),
506 SubstateBorrowed(error_models::ReferencedNodeId),
507}
508
509#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
510pub enum CallFrameSetSubstateError {
511 NodeNotVisible(error_models::ReferencedNodeId),
512 SubstateLocked(error_models::OwnedNodeId, PartitionNumber, SubstateKey),
513 ProcessSubstateKeyError(ProcessSubstateKeyError),
514}
515
516#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
517pub enum CallFrameRemoveSubstateError {
518 NodeNotVisible(error_models::ReferencedNodeId),
519 SubstateLocked(error_models::OwnedNodeId, PartitionNumber, SubstateKey),
520 ProcessSubstateKeyError(ProcessSubstateKeyError),
521}
522
523#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
524pub enum CallFrameScanKeysError {
525 NodeNotVisible(error_models::ReferencedNodeId),
526 ProcessSubstateKeyError(ProcessSubstateKeyError),
527}
528
529#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
530pub enum CallFrameDrainSubstatesError {
531 NodeNotVisible(error_models::ReferencedNodeId),
532 NonGlobalRefNotSupported(error_models::ReferencedNodeId),
533 ProcessSubstateKeyError(ProcessSubstateKeyError),
534}
535
536#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
537pub enum CallFrameScanSortedSubstatesError {
538 NodeNotVisible(error_models::ReferencedNodeId),
539 OwnedNodeNotSupported(error_models::OwnedNodeId),
540 ProcessSubstateKeyError(ProcessSubstateKeyError),
541}
542
543#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
544pub enum ProcessSubstateKeyError {
545 NodeNotVisible(error_models::ReferencedNodeId),
546 DecodeError(DecodeError),
547 OwnedNodeNotSupported,
548 NonGlobalRefNotSupported,
549}
550
551#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
552pub enum ProcessSubstateError {
553 TakeNodeError(TakeNodeError),
554 CantDropNodeInStore(error_models::ReferencedNodeId),
555 RefNotFound(error_models::ReferencedNodeId),
556 RefCantBeAddedToSubstate(error_models::ReferencedNodeId),
557 NonGlobalRefNotAllowed(error_models::ReferencedNodeId),
558 PersistNodeError(PersistNodeError),
559}
560
561#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
562pub enum SubstateDiffError {
563 ContainsDuplicateOwns,
564}
565
566#[derive(Debug)]
567pub struct CallFrameInit<C> {
568 pub data: C,
569 pub global_addresses: IndexSet<GlobalAddress>,
570 pub direct_accesses: IndexSet<InternalAddress>,
571 pub always_visible_global_nodes: &'static IndexSet<NodeId>,
572 pub stack_id: usize,
573}
574
575impl<C, L: Clone> CallFrame<C, L> {
576 pub fn new_root(init: CallFrameInit<C>) -> Self {
577 let mut call_frame = Self {
578 stack_id: init.stack_id,
579 depth: 0,
580 call_frame_data: init.data,
581 stable_references: Default::default(),
582 transient_references: NonIterMap::new(),
583 owned_root_nodes: index_set_new(),
584 next_handle: 0u32,
585 open_substates: index_map_new(),
586 always_visible_global_nodes: init.always_visible_global_nodes,
587 };
588
589 for global_ref in init.global_addresses {
590 call_frame.add_global_reference(global_ref);
591 }
592 for direct_access in init.direct_accesses {
593 call_frame.add_direct_access_reference(direct_access);
594 }
595
596 call_frame
597 }
598
599 pub fn new_child_from_parent<S: CommitableSubstateStore>(
600 substate_io: &SubstateIO<S>,
601 parent: &mut CallFrame<C, L>,
602 call_frame_data: C,
603 message: CallFrameMessage,
604 ) -> Result<Self, CreateFrameError> {
605 let mut frame = Self {
606 stack_id: parent.stack_id,
607 depth: parent.depth + 1,
608 call_frame_data,
609 stable_references: Default::default(),
610 transient_references: NonIterMap::new(),
611 owned_root_nodes: index_set_new(),
612 next_handle: 0u32,
613 open_substates: index_map_new(),
614 always_visible_global_nodes: parent.always_visible_global_nodes,
615 };
616
617 Self::pass_message(substate_io, parent, &mut frame, message)
619 .map_err(CreateFrameError::PassMessageError)?;
620
621 Ok(frame)
622 }
623
624 pub fn pass_message<S: CommitableSubstateStore>(
625 substate_io: &SubstateIO<S>,
626 from: &mut CallFrame<C, L>,
627 to: &mut CallFrame<C, L>,
628 message: CallFrameMessage,
629 ) -> Result<(), PassMessageError> {
630 for node_id in message.move_nodes {
631 from.take_node_internal(substate_io, &node_id)
634 .map_err(PassMessageError::TakeNodeError)?;
635 to.owned_root_nodes.insert(node_id);
636 }
637
638 for node_id in message.copy_global_references {
640 if from.get_node_visibility(&node_id).is_global() {
641 to.stable_references
644 .insert(node_id, StableReferenceType::Global);
645 } else {
646 return Err(PassMessageError::GlobalRefNotFound(node_id.into()));
647 }
648 }
649
650 for node_id in message.copy_direct_access_references {
651 if from.get_node_visibility(&node_id).can_be_invoked(true) {
652 to.stable_references
653 .insert(node_id, StableReferenceType::DirectAccess);
654 } else {
655 return Err(PassMessageError::DirectRefNotFound(node_id.into()));
656 }
657 }
658
659 for node_id in message.copy_stable_transient_references {
660 if let Some(ref_origin) = from.get_node_visibility(&node_id).reference_origin(node_id) {
661 to.transient_references
662 .entry(node_id.clone())
663 .or_insert(TransientReference {
664 ref_count: 0usize,
665 ref_origin,
666 })
667 .ref_count
668 .add_assign(1);
669
670 if let ReferenceOrigin::Global(global_address) = ref_origin {
671 to.stable_references
672 .insert(global_address.into_node_id(), StableReferenceType::Global);
673 }
674 } else {
675 return Err(PassMessageError::TransientRefNotFound(node_id.into()));
676 }
677 }
678
679 Ok(())
680 }
681
682 pub fn stack_id(&self) -> usize {
683 self.stack_id
684 }
685
686 pub fn depth(&self) -> usize {
687 self.depth
688 }
689
690 pub fn data(&self) -> &C {
691 &self.call_frame_data
692 }
693
694 pub fn data_mut(&mut self) -> &mut C {
695 &mut self.call_frame_data
696 }
697
698 pub fn pin_node<'f, S: CommitableSubstateStore>(
699 &mut self,
700 substate_io: &mut SubstateIO<S>,
701 node_id: NodeId,
702 ) -> Result<(), PinNodeError> {
703 let (_ref_origin, device) = self
705 .get_node_ref(&node_id)
706 .ok_or_else(|| PinNodeError::NodeNotVisible(node_id.into()))?;
707
708 match device {
709 SubstateDevice::Heap => {
710 substate_io.pinned_to_heap.insert(node_id);
711 }
712 SubstateDevice::Store => {
713 }
715 }
716
717 Ok(())
718 }
719
720 pub fn mark_substate_as_transient<'f, S: CommitableSubstateStore>(
721 &mut self,
722 substate_io: &mut SubstateIO<S>,
723 node_id: NodeId,
724 partition_num: PartitionNumber,
725 substate_key: SubstateKey,
726 ) -> Result<(), MarkTransientSubstateError> {
727 let (_ref_origin, device) = self
729 .get_node_ref(&node_id)
730 .ok_or_else(|| MarkTransientSubstateError::NodeNotVisible(node_id.into()))?;
731
732 match device {
733 SubstateDevice::Heap => {
734 substate_io.heap_transient_substates.mark_as_transient(
735 node_id,
736 partition_num,
737 substate_key,
738 );
739 }
740 SubstateDevice::Store => {
741 substate_io
742 .store
743 .mark_as_transient(node_id, partition_num, substate_key);
744 }
745 }
746
747 Ok(())
748 }
749
750 pub fn create_node<'f, S: CommitableSubstateStore, E>(
751 &mut self,
752 substate_io: &mut SubstateIO<S>,
753 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
754 node_id: NodeId,
755 node_substates: NodeSubstates,
756 ) -> Result<(), CallbackError<CreateNodeError, E>> {
757 let destination_device = if node_id.is_global() {
762 SubstateDevice::Store
763 } else {
764 SubstateDevice::Heap
765 };
766
767 for (_partition_number, module) in &node_substates {
768 for (substate_key, substate_value) in module {
769 self.process_input_substate_key(substate_key).map_err(|e| {
770 CallbackError::Error(CreateNodeError::ProcessSubstateKeyError(e))
771 })?;
772 let diff = SubstateDiff::from_new_substate(&substate_value)
773 .map_err(|e| CallbackError::Error(CreateNodeError::SubstateDiffError(e)))?;
774
775 self.process_substate_diff(substate_io, handler, destination_device, &diff)
776 .map_err(|e| e.map(CreateNodeError::ProcessSubstateError))?;
777 }
778 }
779
780 match destination_device {
781 SubstateDevice::Store => {
782 self.stable_references
783 .insert(node_id, StableReferenceType::Global);
784 }
785 SubstateDevice::Heap => {
786 self.owned_root_nodes.insert(node_id);
787 }
788 }
789
790 let mut adapter = CallFrameToIOAccessAdapter {
791 call_frame: self,
792 handler,
793 phantom: PhantomData::default(),
794 };
795
796 substate_io.create_node(destination_device, node_id, node_substates, &mut adapter)?;
797
798 Ok(())
799 }
800
801 pub fn drop_node<E, S: CommitableSubstateStore>(
803 &mut self,
804 substate_io: &mut SubstateIO<S>,
805 node_id: &NodeId,
806 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
807 ) -> Result<DroppedNode, CallbackError<DropNodeError, E>> {
808 self.take_node_internal(substate_io, node_id)
809 .map_err(|e| CallbackError::Error(DropNodeError::TakeNodeError(e)))?;
810
811 let mut adapter = CallFrameToIOAccessAdapter {
812 call_frame: self,
813 handler,
814 phantom: PhantomData::default(),
815 };
816 let substates = substate_io
817 .drop_node(SubstateDevice::Heap, node_id, &mut adapter)
818 .map_err(|e| match e {
819 CallbackError::Error(e) => CallbackError::Error(e),
820 CallbackError::CallbackError(e) => CallbackError::CallbackError(e),
821 })?;
822 for (_partition_number, module) in &substates {
823 for (_substate_key, substate_value) in module {
824 let diff = SubstateDiff::from_drop_substate(&substate_value);
825 adapter
826 .call_frame
827 .process_substate_diff(
828 substate_io,
829 adapter.handler,
830 SubstateDevice::Heap,
831 &diff,
832 )
833 .map_err(|e| match e {
834 CallbackError::Error(e) => {
835 CallbackError::Error(DropNodeError::ProcessSubstateError(e))
836 }
837 CallbackError::CallbackError(e) => CallbackError::CallbackError(e),
838 })?;
839 }
840 }
841
842 let pinned_to_heap = substate_io.pinned_to_heap.remove(node_id);
843
844 Ok(DroppedNode {
845 substates,
846 pinned_to_heap,
847 })
848 }
849
850 pub fn move_partition<'f, S: CommitableSubstateStore, E>(
851 &mut self,
852 substate_io: &'f mut SubstateIO<S>,
853 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
854 src_node_id: &NodeId,
855 src_partition_number: PartitionNumber,
856 dest_node_id: &NodeId,
857 dest_partition_number: PartitionNumber,
858 ) -> Result<(), CallbackError<MovePartitionError, E>> {
859 let (_ref_origin, src_device) = self.get_node_ref(src_node_id).ok_or_else(|| {
861 CallbackError::Error(MovePartitionError::NodeNotAvailable(
862 src_node_id.clone().into(),
863 ))
864 })?;
865
866 let (_ref_origin, dest_device) = self.get_node_ref(dest_node_id).ok_or_else(|| {
868 CallbackError::Error(MovePartitionError::NodeNotAvailable(
869 dest_node_id.clone().into(),
870 ))
871 })?;
872
873 let mut adapter = CallFrameToIOAccessAdapter {
874 call_frame: self,
875 handler,
876 phantom: PhantomData::default(),
877 };
878 substate_io.move_partition(
879 src_device,
880 src_node_id,
881 src_partition_number,
882 dest_device,
883 dest_node_id,
884 dest_partition_number,
885 &mut adapter,
886 )?;
887
888 Ok(())
889 }
890
891 fn process_input_substate_key(
892 &self,
893 substate_key: &SubstateKey,
894 ) -> Result<(), ProcessSubstateKeyError> {
895 match substate_key {
896 SubstateKey::Sorted((_, map_key)) | SubstateKey::Map(map_key) => {
897 let key_value = IndexedScryptoValue::from_slice(map_key)
898 .map_err(|e| ProcessSubstateKeyError::DecodeError(e))?;
899
900 if !key_value.owned_nodes().is_empty() {
902 return Err(ProcessSubstateKeyError::OwnedNodeNotSupported);
903 }
904
905 for reference in key_value.references() {
907 if !reference.is_global() {
908 return Err(ProcessSubstateKeyError::NonGlobalRefNotSupported);
909 }
910
911 if !self.get_node_visibility(reference).is_visible() {
912 return Err(ProcessSubstateKeyError::NodeNotVisible(
913 reference.clone().into(),
914 ));
915 }
916 }
917 }
918 _ => {}
919 }
920
921 Ok(())
922 }
923
924 fn process_output_substate_key(
925 &mut self,
926 substate_key: &SubstateKey,
927 ) -> Result<(), ProcessSubstateKeyError> {
928 match substate_key {
929 SubstateKey::Sorted((_, map_key)) | SubstateKey::Map(map_key) => {
930 let key = IndexedScryptoValue::from_slice(map_key).unwrap();
931
932 if !key.owned_nodes().is_empty() {
934 panic!("Unexpected owns in substate key")
935 }
936
937 for reference in key.references() {
939 if reference.is_global() {
940 self.stable_references
941 .insert(reference.clone(), StableReferenceType::Global);
942 } else {
943 panic!("Unexpected non-global refs in substate key")
944 }
945 }
946 }
947 _ => {}
948 }
949
950 Ok(())
951 }
952
953 pub fn open_substate<S: CommitableSubstateStore, E, F: FnOnce() -> IndexedScryptoValue>(
954 &mut self,
955 substate_io: &mut SubstateIO<S>,
956 node_id: &NodeId,
957 partition_num: PartitionNumber,
958 substate_key: &SubstateKey,
959 flags: LockFlags,
960 default: Option<F>,
961 data: L,
962 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
963 ) -> Result<(SubstateHandle, usize), CallbackError<OpenSubstateError, E>> {
964 let (ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
965 CallbackError::Error(OpenSubstateError::NodeNotVisible(node_id.clone().into()))
966 })?;
967
968 self.process_input_substate_key(substate_key)
969 .map_err(|e| CallbackError::Error(OpenSubstateError::ProcessSubstateKeyError(e)))?;
970
971 let mut adapter = CallFrameToIOAccessAdapter {
972 call_frame: self,
973 handler,
974 phantom: PhantomData::default(),
975 };
976
977 let (global_substate_handle, substate_value) = substate_io.open_substate(
978 device,
979 node_id,
980 partition_num,
981 substate_key,
982 flags,
983 default,
984 &mut adapter,
985 )?;
986
987 let value_len = substate_value.len();
988 for node_id in substate_value.references() {
989 if node_id.is_global() {
990 self.stable_references
992 .insert(node_id.clone(), StableReferenceType::Global);
993 }
994 }
995
996 let mut open_substate = OpenedSubstate {
997 references: index_set_new(),
998 owned_nodes: index_set_new(),
999 ref_origin,
1000 global_substate_handle,
1001 device,
1002 data,
1003 };
1004
1005 let diff = SubstateDiff::from_new_substate(substate_value)
1006 .expect("There should be no issues with already stored substate value");
1007
1008 Self::apply_diff_to_open_substate(
1009 &mut self.transient_references,
1010 substate_io,
1011 &mut open_substate,
1012 &diff,
1013 );
1014
1015 let substate_handle = self.next_handle;
1017 self.open_substates.insert(substate_handle, open_substate);
1018 self.next_handle = self.next_handle + 1;
1019
1020 Ok((substate_handle, value_len))
1021 }
1022
1023 pub fn read_substate<'f, S: CommitableSubstateStore, H: CallFrameSubstateReadHandler<C, L>>(
1024 &mut self,
1025 substate_io: &'f mut SubstateIO<S>,
1026 lock_handle: SubstateHandle,
1027 handler: &mut H,
1028 ) -> Result<&'f IndexedScryptoValue, CallbackError<ReadSubstateError, H::Error>> {
1029 let OpenedSubstate {
1030 global_substate_handle,
1031 ..
1032 } = self
1033 .open_substates
1034 .get(&lock_handle)
1035 .ok_or(CallbackError::Error(ReadSubstateError::HandleNotFound(
1036 lock_handle,
1037 )))?;
1038
1039 let mut adapter = CallFrameToIOSubstateReadAdapter {
1040 call_frame: self,
1041 handler,
1042 handle: *global_substate_handle,
1043 };
1044
1045 let substate = substate_io
1046 .read_substate(*global_substate_handle, &mut adapter)
1047 .map_err(|e| CallbackError::CallbackError(e))?;
1048
1049 Ok(substate)
1050 }
1051
1052 pub fn write_substate<'f, S: CommitableSubstateStore, E>(
1053 &mut self,
1054 substate_io: &'f mut SubstateIO<S>,
1055 lock_handle: SubstateHandle,
1056 substate: IndexedScryptoValue,
1057 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1058 ) -> Result<(), CallbackError<WriteSubstateError, E>> {
1059 let mut opened_substate =
1060 self.open_substates
1061 .swap_remove(&lock_handle)
1062 .ok_or(CallbackError::Error(WriteSubstateError::HandleNotFound(
1063 lock_handle,
1064 )))?;
1065
1066 let (.., data) = substate_io
1067 .substate_locks
1068 .get(opened_substate.global_substate_handle);
1069 if !data.flags.contains(LockFlags::MUTABLE) {
1070 return Err(CallbackError::Error(WriteSubstateError::NoWritePermission));
1071 }
1072
1073 let diff = opened_substate
1074 .diff(&substate)
1075 .map_err(|e| CallbackError::Error(WriteSubstateError::SubstateDiffError(e)))?;
1076
1077 self.process_substate_diff(substate_io, handler, opened_substate.device, &diff)
1078 .map_err(|e| e.map(WriteSubstateError::ProcessSubstateError))?;
1079
1080 Self::apply_diff_to_open_substate(
1081 &mut self.transient_references,
1082 substate_io,
1083 &mut opened_substate,
1084 &diff,
1085 );
1086
1087 let mut adapter = CallFrameToIOAccessAdapter {
1088 call_frame: self,
1089 handler,
1090 phantom: PhantomData::default(),
1091 };
1092
1093 substate_io.write_substate(
1094 opened_substate.global_substate_handle,
1095 substate,
1096 &mut adapter,
1097 )?;
1098
1099 self.open_substates.insert(lock_handle, opened_substate);
1100
1101 Ok(())
1102 }
1103
1104 pub fn close_substate<S: CommitableSubstateStore>(
1105 &mut self,
1106 substate_io: &mut SubstateIO<S>,
1107 lock_handle: SubstateHandle,
1108 ) -> Result<(), CloseSubstateError> {
1109 let mut open_substate = self
1110 .open_substates
1111 .swap_remove(&lock_handle)
1112 .ok_or_else(|| CloseSubstateError::HandleNotFound(lock_handle))?;
1113
1114 for node_id in open_substate.owned_nodes.iter() {
1115 if substate_io.substate_locks.node_is_locked(node_id) {
1119 return Err(CloseSubstateError::SubstateBorrowed(node_id.clone().into()));
1120 }
1121 }
1122
1123 substate_io.close_substate(open_substate.global_substate_handle);
1124
1125 let diff = open_substate.diff_on_close();
1126 Self::apply_diff_to_open_substate(
1127 &mut self.transient_references,
1128 substate_io,
1129 &mut open_substate,
1130 &diff,
1131 );
1132
1133 Ok(())
1134 }
1135
1136 pub fn open_substates(&self) -> Vec<u32> {
1137 self.open_substates.keys().cloned().into_iter().collect()
1138 }
1139
1140 pub fn close_all_substates<S: CommitableSubstateStore>(
1141 &mut self,
1142 substate_io: &mut SubstateIO<S>,
1143 ) {
1144 for (_lock_handle, mut open_substate) in self.open_substates.drain(..) {
1146 substate_io.close_substate(open_substate.global_substate_handle);
1147 let diff = open_substate.diff_on_close();
1148 Self::apply_diff_to_open_substate(
1149 &mut self.transient_references,
1150 substate_io,
1151 &mut open_substate,
1152 &diff,
1153 );
1154 }
1155 }
1156
1157 pub fn get_handle_info(&self, lock_handle: SubstateHandle) -> Option<L> {
1158 self.open_substates
1159 .get(&lock_handle)
1160 .map(|substate_lock| substate_lock.data.clone())
1161 }
1162
1163 pub fn add_global_reference(&mut self, address: GlobalAddress) {
1164 self.stable_references
1165 .insert(address.into_node_id(), StableReferenceType::Global);
1166 }
1167
1168 pub fn add_direct_access_reference(&mut self, address: InternalAddress) {
1169 self.stable_references
1170 .insert(address.into_node_id(), StableReferenceType::DirectAccess);
1171 }
1172
1173 pub fn set_substate<'f, S: CommitableSubstateStore, E>(
1181 &mut self,
1182 substate_io: &'f mut SubstateIO<S>,
1183 node_id: &NodeId,
1184 partition_num: PartitionNumber,
1185 key: SubstateKey,
1186 value: IndexedScryptoValue,
1187 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1188 ) -> Result<(), CallbackError<CallFrameSetSubstateError, E>> {
1189 let (_ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
1190 CallbackError::Error(CallFrameSetSubstateError::NodeNotVisible(
1191 node_id.clone().into(),
1192 ))
1193 })?;
1194
1195 self.process_input_substate_key(&key).map_err(|e| {
1196 CallbackError::Error(CallFrameSetSubstateError::ProcessSubstateKeyError(e))
1197 })?;
1198
1199 let mut adapter = CallFrameToIOAccessAdapter {
1203 call_frame: self,
1204 handler,
1205 phantom: PhantomData::default(),
1206 };
1207
1208 substate_io.set_substate(device, node_id, partition_num, key, value, &mut adapter)?;
1209
1210 Ok(())
1211 }
1212
1213 pub fn remove_substate<'f, S: CommitableSubstateStore, E>(
1214 &mut self,
1215 substate_io: &'f mut SubstateIO<S>,
1216 node_id: &NodeId,
1217 partition_num: PartitionNumber,
1218 key: &SubstateKey,
1219 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1220 ) -> Result<Option<IndexedScryptoValue>, CallbackError<CallFrameRemoveSubstateError, E>> {
1221 let (_ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
1222 CallbackError::Error(CallFrameRemoveSubstateError::NodeNotVisible(
1223 node_id.clone().into(),
1224 ))
1225 })?;
1226
1227 self.process_input_substate_key(&key).map_err(|e| {
1228 CallbackError::Error(CallFrameRemoveSubstateError::ProcessSubstateKeyError(e))
1229 })?;
1230
1231 let mut adapter = CallFrameToIOAccessAdapter {
1232 call_frame: self,
1233 handler,
1234 phantom: PhantomData::default(),
1235 };
1236
1237 let removed =
1238 substate_io.remove_substate(device, node_id, partition_num, key, &mut adapter)?;
1239
1240 Ok(removed)
1241 }
1242
1243 pub fn scan_keys<'f, K: SubstateKeyContent, S: CommitableSubstateStore, E>(
1244 &mut self,
1245 substate_io: &'f mut SubstateIO<S>,
1246 node_id: &NodeId,
1247 partition_num: PartitionNumber,
1248 limit: u32,
1249 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1250 ) -> Result<Vec<SubstateKey>, CallbackError<CallFrameScanKeysError, E>> {
1251 let (_ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
1253 CallbackError::Error(CallFrameScanKeysError::NodeNotVisible(
1254 node_id.clone().into(),
1255 ))
1256 })?;
1257
1258 let mut adapter = CallFrameToIOAccessAdapter {
1259 call_frame: self,
1260 handler,
1261 phantom: PhantomData::default(),
1262 };
1263
1264 let keys =
1265 substate_io.scan_keys::<K, E>(device, node_id, partition_num, limit, &mut adapter)?;
1266
1267 for key in &keys {
1268 self.process_output_substate_key(key).map_err(|e| {
1269 CallbackError::Error(CallFrameScanKeysError::ProcessSubstateKeyError(e))
1270 })?;
1271 }
1272
1273 Ok(keys)
1274 }
1275
1276 pub fn drain_substates<'f, K: SubstateKeyContent, S: CommitableSubstateStore, E>(
1277 &mut self,
1278 substate_io: &'f mut SubstateIO<S>,
1279 node_id: &NodeId,
1280 partition_num: PartitionNumber,
1281 limit: u32,
1282 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1283 ) -> Result<
1284 Vec<(SubstateKey, IndexedScryptoValue)>,
1285 CallbackError<CallFrameDrainSubstatesError, E>,
1286 > {
1287 let (_ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
1289 CallbackError::Error(CallFrameDrainSubstatesError::NodeNotVisible(
1290 node_id.clone().into(),
1291 ))
1292 })?;
1293
1294 let mut adapter = CallFrameToIOAccessAdapter {
1295 call_frame: self,
1296 handler,
1297 phantom: PhantomData::default(),
1298 };
1299
1300 let substates = substate_io.drain_substates::<K, E>(
1301 device,
1302 node_id,
1303 partition_num,
1304 limit,
1305 &mut adapter,
1306 )?;
1307
1308 for (key, substate) in &substates {
1309 self.process_output_substate_key(key).map_err(|e| {
1310 CallbackError::Error(CallFrameDrainSubstatesError::ProcessSubstateKeyError(e))
1311 })?;
1312
1313 if !substate.owned_nodes().is_empty() {
1314 panic!("Unexpected owns from drain_substates");
1315 }
1316
1317 for reference in substate.references() {
1318 if reference.is_global() {
1319 self.stable_references
1320 .insert(reference.clone(), StableReferenceType::Global);
1321 } else {
1322 panic!("Unexpected non-global ref from drain_substates");
1323 }
1324 }
1325 }
1326
1327 Ok(substates)
1328 }
1329
1330 pub fn scan_sorted<'f, S: CommitableSubstateStore, E>(
1333 &mut self,
1334 substate_io: &'f mut SubstateIO<S>,
1335 node_id: &NodeId,
1336 partition_num: PartitionNumber,
1337 count: u32,
1338 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1339 ) -> Result<
1340 Vec<(SortedKey, IndexedScryptoValue)>,
1341 CallbackError<CallFrameScanSortedSubstatesError, E>,
1342 > {
1343 let (_ref_origin, device) = self.get_node_ref(node_id).ok_or_else(|| {
1345 CallbackError::Error(CallFrameScanSortedSubstatesError::NodeNotVisible(
1346 node_id.clone().into(),
1347 ))
1348 })?;
1349
1350 let mut adapter = CallFrameToIOAccessAdapter {
1351 call_frame: self,
1352 handler,
1353 phantom: PhantomData::default(),
1354 };
1355
1356 let substates =
1357 substate_io.scan_sorted(device, node_id, partition_num, count, &mut adapter)?;
1358
1359 for (key, substate) in &substates {
1360 self.process_output_substate_key(&SubstateKey::Sorted(key.clone()))
1361 .map_err(|e| {
1362 CallbackError::Error(
1363 CallFrameScanSortedSubstatesError::ProcessSubstateKeyError(e),
1364 )
1365 })?;
1366
1367 if !substate.owned_nodes().is_empty() {
1368 panic!("Unexpected owns from scan_substates");
1369 }
1370
1371 for reference in substate.references() {
1372 if reference.is_global() {
1373 self.stable_references
1374 .insert(reference.clone(), StableReferenceType::Global);
1375 } else {
1376 panic!("Unexpected non-global ref from scan_substates");
1377 }
1378 }
1379 }
1380
1381 Ok(substates)
1382 }
1383
1384 pub fn owned_nodes(&self) -> Vec<NodeId> {
1385 self.owned_root_nodes.clone().into_iter().collect()
1386 }
1387
1388 fn get_node_ref(&self, node_id: &NodeId) -> Option<(ReferenceOrigin, SubstateDevice)> {
1389 let node_visibility = self.get_node_visibility(node_id);
1390 let ref_origin = node_visibility.reference_origin(node_id.clone().into())?;
1391 let device = match ref_origin {
1392 ReferenceOrigin::FrameOwned => SubstateDevice::Heap,
1393 ReferenceOrigin::Global(..) | ReferenceOrigin::DirectlyAccessed => {
1394 SubstateDevice::Store
1395 }
1396 ReferenceOrigin::SubstateNonGlobalReference(device) => device,
1397 };
1398
1399 Some((ref_origin, device))
1400 }
1401
1402 pub fn get_node_visibility(&self, node_id: &NodeId) -> NodeVisibility {
1403 let mut visibilities = BTreeSet::<Visibility>::new();
1404
1405 if let Some(reference_type) = self.stable_references.get(node_id) {
1407 visibilities.insert(Visibility::StableReference(reference_type.clone()));
1408 }
1409 if self.always_visible_global_nodes.contains(node_id) {
1410 visibilities.insert(Visibility::StableReference(StableReferenceType::Global));
1411 }
1412
1413 if self.owned_root_nodes.contains(node_id) {
1415 visibilities.insert(Visibility::FrameOwned);
1416 }
1417
1418 if let Some(transient_ref) = self.transient_references.get(node_id) {
1420 visibilities.insert(Visibility::Borrowed(transient_ref.ref_origin));
1421 }
1422
1423 NodeVisibility(visibilities)
1424 }
1425
1426 fn process_substate_diff<S: CommitableSubstateStore, E>(
1427 &mut self,
1428 substate_io: &mut SubstateIO<S>,
1429 handler: &mut impl CallFrameIOAccessHandler<C, L, E>,
1430 device: SubstateDevice,
1431 diff: &SubstateDiff,
1432 ) -> Result<(), CallbackError<ProcessSubstateError, E>> {
1433 {
1435 for added_own in &diff.added_owns {
1436 self.take_node_internal(substate_io, added_own)
1438 .map_err(|e| CallbackError::Error(ProcessSubstateError::TakeNodeError(e)))?;
1439 }
1440
1441 for removed_own in &diff.removed_owns {
1442 self.owned_root_nodes.insert(removed_own.clone());
1445 }
1446
1447 for added_ref in &diff.added_refs {
1448 let node_visibility = self.get_node_visibility(added_ref);
1449 if !node_visibility.is_visible() {
1450 return Err(CallbackError::Error(ProcessSubstateError::RefNotFound(
1451 added_ref.clone().into(),
1452 )));
1453 }
1454 if !node_visibility.can_be_referenced_in_substate() {
1455 return Err(CallbackError::Error(
1456 ProcessSubstateError::RefCantBeAddedToSubstate(added_ref.clone().into()),
1457 ));
1458 }
1459 }
1460
1461 for removed_ref in &diff.removed_refs {
1462 if removed_ref.is_global() {
1463 self.stable_references
1464 .insert(*removed_ref, StableReferenceType::Global);
1465 }
1466 }
1467 }
1468
1469 match device {
1471 SubstateDevice::Heap => {
1472 for added_ref in &diff.added_refs {
1473 if !added_ref.is_global() {
1474 let (_, device) = self.get_node_ref(added_ref).unwrap();
1475 substate_io
1476 .non_global_node_refs
1477 .increment_ref_count(*added_ref, device);
1478 }
1479 }
1480 for removed_ref in &diff.removed_refs {
1481 if !removed_ref.is_global() {
1482 substate_io
1483 .non_global_node_refs
1484 .decrement_ref_count(removed_ref);
1485 }
1486 }
1487 }
1488 SubstateDevice::Store => {
1489 let mut adapter = CallFrameToIOAccessAdapter {
1490 call_frame: self,
1491 handler,
1492 phantom: PhantomData::default(),
1493 };
1494
1495 for added_own in &diff.added_owns {
1496 substate_io
1497 .move_node_from_heap_to_store(added_own, &mut adapter)
1498 .map_err(|e| e.map(ProcessSubstateError::PersistNodeError))?;
1499 }
1500
1501 if let Some(removed_own) = diff.removed_owns.iter().next() {
1502 return Err(CallbackError::Error(
1503 ProcessSubstateError::CantDropNodeInStore(removed_own.clone().into()),
1504 ));
1505 }
1506
1507 if let Some(non_global_ref) =
1508 diff.added_refs.iter().filter(|r| !r.is_global()).next()
1509 {
1510 return Err(CallbackError::Error(
1511 ProcessSubstateError::NonGlobalRefNotAllowed(non_global_ref.clone().into()),
1512 ));
1513 }
1514
1515 if let Some(non_global_ref) =
1516 diff.removed_refs.iter().filter(|r| !r.is_global()).next()
1517 {
1518 panic!(
1519 "Should never have contained a non global reference: {:?}",
1520 non_global_ref
1521 );
1522 }
1523 }
1524 }
1525
1526 Ok(())
1527 }
1528
1529 fn apply_diff_to_open_substate<S: CommitableSubstateStore>(
1530 transient_references: &mut NonIterMap<NodeId, TransientReference>,
1531 substate_io: &SubstateIO<S>,
1532 open_substate: &mut OpenedSubstate<L>,
1533 diff: &SubstateDiff,
1534 ) {
1535 for added_own in &diff.added_owns {
1536 open_substate.owned_nodes.insert(*added_own);
1537 transient_references
1538 .entry(added_own.clone())
1539 .or_insert(TransientReference {
1540 ref_count: 0usize,
1541 ref_origin: open_substate.ref_origin, })
1543 .ref_count
1544 .add_assign(1);
1545 }
1546
1547 for removed_own in &diff.removed_owns {
1548 open_substate.owned_nodes.swap_remove(removed_own);
1549 let mut transient_ref = transient_references.remove(removed_own).unwrap();
1550 if transient_ref.ref_count > 1 {
1551 transient_ref.ref_count -= 1;
1552 transient_references.insert(*removed_own, transient_ref);
1553 }
1554 }
1555
1556 for added_ref in &diff.added_refs {
1557 open_substate.references.insert(*added_ref);
1558
1559 if !added_ref.is_global() {
1560 let device = substate_io.non_global_node_refs.get_ref_device(added_ref);
1561
1562 transient_references
1563 .entry(added_ref.clone())
1564 .or_insert(TransientReference {
1565 ref_count: 0usize,
1566 ref_origin: ReferenceOrigin::SubstateNonGlobalReference(device),
1567 })
1568 .ref_count
1569 .add_assign(1);
1570 }
1571 }
1572
1573 for removed_ref in &diff.removed_refs {
1574 open_substate.references.swap_remove(removed_ref);
1575
1576 if !removed_ref.is_global() {
1577 let mut transient_ref = transient_references.remove(&removed_ref).unwrap();
1578 if transient_ref.ref_count > 1 {
1579 transient_ref.ref_count -= 1;
1580 transient_references.insert(*removed_ref, transient_ref);
1581 }
1582 }
1583 }
1584 }
1585
1586 fn take_node_internal<S: CommitableSubstateStore>(
1587 &mut self,
1588 substate_io: &SubstateIO<S>,
1589 node_id: &NodeId,
1590 ) -> Result<(), TakeNodeError> {
1591 if substate_io.substate_locks.node_is_locked(node_id) {
1596 return Err(TakeNodeError::SubstateBorrowed(node_id.clone().into()));
1597 }
1598
1599 if self.owned_root_nodes.swap_remove(node_id) {
1600 Ok(())
1601 } else {
1602 Err(TakeNodeError::OwnNotFound(node_id.clone().into()))
1603 }
1604 }
1605
1606 #[cfg(feature = "radix_engine_tests")]
1607 pub fn stable_references(&self) -> &BTreeMap<NodeId, StableReferenceType> {
1608 &self.stable_references
1609 }
1610}
1611
1612pub struct NonGlobalNodeRefs {
1616 node_refs: NonIterMap<NodeId, (SubstateDevice, usize)>,
1617}
1618
1619impl NonGlobalNodeRefs {
1620 pub fn new() -> Self {
1621 Self {
1622 node_refs: NonIterMap::new(),
1623 }
1624 }
1625
1626 pub fn node_is_referenced(&self, node_id: &NodeId) -> bool {
1627 self.node_refs
1628 .get(node_id)
1629 .map(|(_, ref_count)| ref_count.gt(&0))
1630 .unwrap_or(false)
1631 }
1632
1633 fn get_ref_device(&self, node_id: &NodeId) -> SubstateDevice {
1634 let (device, ref_count) = self.node_refs.get(node_id).unwrap();
1635
1636 if ref_count.eq(&0) {
1637 panic!("Reference no longer exists");
1638 }
1639
1640 *device
1641 }
1642
1643 fn increment_ref_count(&mut self, node_id: NodeId, device: SubstateDevice) {
1644 let (_, ref_count) = self.node_refs.entry(node_id).or_insert((device, 0));
1645 ref_count.add_assign(1);
1646 }
1647
1648 fn decrement_ref_count(&mut self, node_id: &NodeId) {
1649 let (_, ref_count) = self
1650 .node_refs
1651 .get_mut(node_id)
1652 .unwrap_or_else(|| panic!("Node {:?} not found", node_id));
1653 ref_count.sub_assign(1);
1654 }
1655}
1656
1657pub struct TransientSubstates {
1660 pub transient_substates: BTreeMap<NodeId, BTreeSet<(PartitionNumber, SubstateKey)>>,
1661}
1662
1663impl TransientSubstates {
1664 pub fn new() -> Self {
1665 Self {
1666 transient_substates: BTreeMap::new(),
1667 }
1668 }
1669
1670 pub fn mark_as_transient(
1671 &mut self,
1672 node_id: NodeId,
1673 partition_num: PartitionNumber,
1674 substate_key: SubstateKey,
1675 ) {
1676 self.transient_substates
1677 .entry(node_id)
1678 .or_insert(BTreeSet::new())
1679 .insert((partition_num, substate_key));
1680 }
1681
1682 pub fn is_transient(
1683 &self,
1684 node_id: &NodeId,
1685 partition_num: PartitionNumber,
1686 substate_key: &SubstateKey,
1687 ) -> bool {
1688 match self.transient_substates.get(node_id) {
1689 Some(transient) => transient.contains(&(partition_num, substate_key.clone())),
1690 None => false,
1691 }
1692 }
1693}