radix_engine/kernel/
call_frame.rs

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/// A message used for communication between call frames.
15///
16/// Note that it's just an intent, not checked/allowed by kernel yet.
17#[derive(Default, Debug, Clone, PartialEq, Eq)]
18pub struct CallFrameMessage {
19    /// Nodes to be moved from src to dest
20    pub move_nodes: Vec<NodeId>,
21
22    /// Copy of a global ref from src to dest
23    pub copy_global_references: Vec<NodeId>,
24
25    /// Copy of a direct access ref from src to dest
26    pub copy_direct_access_references: Vec<NodeId>,
27
28    /// Create a "stable" transient in dest from src. The src node may
29    /// have global or borrowed visibility
30    /// TODO: Cleanup abstraction (perhaps by adding another type of visibility)
31    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        // Process owned nodes
101        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        //====================
125        // Process references
126        //====================
127        let (added_references, removed_references) = {
128            // De-duplicate
129            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    /// Note that system may enforce further constraints on this.
260    /// For instance, system currently only allows substates of actor,
261    /// actor's outer object, and any visible key value store.
262    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    // TODO: Should we return Vec<ReferenceOrigin> and not supersede global with direct access reference
288    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
315/// Callback for IO access, from call frame
316pub 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
325/// Callback for substate read, from call frame
326pub 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
375/// A call frame is the basic unit that forms a transaction call stack, which keeps track of the
376/// owned objects and references by this function.
377pub struct CallFrame<C, L> {
378    /// The stack id.
379    stack_id: usize,
380
381    /// The frame id
382    depth: usize,
383
384    /// Call frame system layer data
385    call_frame_data: C,
386
387    /// Owned nodes which by definition must live on heap
388    owned_root_nodes: IndexSet<NodeId>,
389
390    /// References to non-GLOBAL nodes, obtained from substate loading, ref counted.
391    /// These references may NOT be passed between call frames as arguments
392    transient_references: NonIterMap<NodeId, TransientReference>,
393
394    /// Stable references points to nodes in track, which can't moved/deleted.
395    /// Current two types: `GLOBAL` (root, stored) and `DirectAccess`.
396    /// These references MAY be passed between call frames
397    stable_references: BTreeMap<NodeId, StableReferenceType>,
398
399    next_handle: SubstateHandle,
400    open_substates: IndexMap<SubstateHandle, OpenedSubstate<L>>,
401
402    /// The set of nodes that are always globally visible.
403    always_visible_global_nodes: &'static IndexSet<NodeId>,
404}
405
406/// Represents an error when creating a new frame.
407#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
408pub enum CreateFrameError {
409    PassMessageError(PassMessageError),
410}
411
412/// Represents an error when passing message between frames.
413#[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/// Represents an error when creating a node.
422#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
423pub enum CreateNodeError {
424    ProcessSubstateError(ProcessSubstateError),
425    ProcessSubstateKeyError(ProcessSubstateKeyError),
426    SubstateDiffError(SubstateDiffError),
427}
428
429/// Represents an error when dropping a node.
430#[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/// Represents an error when persisting a node into store.
439#[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/// Represents an error when taking a node from current frame.
447#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
448pub enum TakeNodeError {
449    OwnNotFound(error_models::OwnedNodeId),
450    SubstateBorrowed(error_models::ReferencedNodeId),
451}
452
453/// Represents an error when moving modules from one node to another.
454#[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/// Represents an error when attempting to lock a substate.
475#[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/// Represents an error when reading substates.
488#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
489pub enum ReadSubstateError {
490    HandleNotFound(SubstateHandle),
491}
492
493/// Represents an error when writing substates.
494#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
495pub enum WriteSubstateError {
496    HandleNotFound(SubstateHandle),
497    ProcessSubstateError(ProcessSubstateError),
498    NoWritePermission,
499    SubstateDiffError(SubstateDiffError),
500}
501
502/// Represents an error when dropping a substate lock.
503#[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        // Copy references and move nodes
618        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            // Note that this has no impact on the `transient_references` because
632            // we don't allow move of "locked nodes".
633            from.take_node_internal(substate_io, &node_id)
634                .map_err(PassMessageError::TakeNodeError)?;
635            to.owned_root_nodes.insert(node_id);
636        }
637
638        // Only allow copy of `Global` and `DirectAccess` references
639        for node_id in message.copy_global_references {
640            if from.get_node_visibility(&node_id).is_global() {
641                // Note that GLOBAL and DirectAccess references are mutually exclusive,
642                // so okay to overwrite
643                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        // Get device
704        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                // Nodes in store are always pinned
714            }
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        // Get device
728        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        // TODO: We need to protect transient blueprints from being globalized directly
758        // into store. This isn't a problem for now since only native objects are allowed
759        // to be transient.
760
761        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    /// Removes node from call frame and owned nodes will be possessed by this call frame.
802    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        // Check src visibility
860        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        // Check dest visibility
867        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                // Check owns
901                if !key_value.owned_nodes().is_empty() {
902                    return Err(ProcessSubstateKeyError::OwnedNodeNotSupported);
903                }
904
905                // Check references
906                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                // Check owns
933                if !key.owned_nodes().is_empty() {
934                    panic!("Unexpected owns in substate key")
935                }
936
937                // Check references
938                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                // Again, safe to overwrite because Global and DirectAccess are exclusive.
991                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        // Issue lock handle
1016        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            // We must maintain the invariant that opened substates must always
1116            // be from a visible node. Thus, we cannot close a substate if there is a
1117            // child opened substate.
1118            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        // Closing of all substates should always be possible as no invariant needs to be maintained
1145        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    //====================================================================================
1174    // Note that reference model isn't fully implemented for set/remove/scan/take APIs.
1175    // They're intended for internal use only and extra caution must be taken.
1176    //====================================================================================
1177
1178    // Substate Virtualization does not apply to this call
1179    // Should this be prevented at this layer?
1180    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        // TODO: Should process value here (For example, not allow owned objects or references) but
1200        // this isn't a problem for now since only native objects are allowed to use set_substate
1201
1202        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        // Check node visibility
1252        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        // Check node visibility
1288        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    // Substate Virtualization does not apply to this call
1331    // Should this be prevented at this layer?
1332    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        // Check node visibility
1344        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        // Stable references
1406        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        // Frame owned nodes
1414        if self.owned_root_nodes.contains(node_id) {
1415            visibilities.insert(Visibility::FrameOwned);
1416        }
1417
1418        // Borrowed from substate loading
1419        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        // Verify and Update call frame state based on diff
1434        {
1435            for added_own in &diff.added_owns {
1436                // Node no longer owned by frame
1437                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                // Owned nodes discarded by the substate go back to the call frame,
1443                // and must be explicitly dropped.
1444                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        // Update global state
1470        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, // Child inherits reference origin
1542                })
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 there exists a non-global node-ref we still allow the node to be
1592        // taken. We prevent substate locked nodes from being taken though.
1593        // We do not need to check children of the node as a node must be
1594        // substate locked in order to access any of it's children.
1595        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
1612/// Non Global Node References
1613/// This struct should be maintained with CallFrame as the call frame should be the only
1614/// manipulator. Substate I/O though the "owner" only has read-access to this structure.
1615pub 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
1657/// Structure which keeps track of all transient substates or substates
1658/// which are never committed though can have transaction runtime state
1659pub 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}