1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::base_types::{SequenceNumber, VersionDigest};
use crate::effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents};
use crate::error::SuiResult;
use crate::execution::DynamicallyLoadedObjectMetadata;
use crate::storage::PackageObject;
use crate::storage::{BackingPackageStore, InputKey};
use crate::{
    base_types::ObjectID,
    object::{Object, Owner},
};
use move_binary_format::binary_config::BinaryConfig;
use move_binary_format::CompiledModule;
use move_bytecode_utils::module_cache::GetModule;
use move_core_types::language_storage::ModuleId;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::sync::Arc;

pub type WrittenObjects = BTreeMap<ObjectID, Object>;
pub type ObjectMap = BTreeMap<ObjectID, Object>;
pub type TxCoins = (ObjectMap, WrittenObjects);

#[derive(Debug, Clone)]
pub struct InnerTemporaryStore {
    pub input_objects: ObjectMap,
    pub mutable_inputs: BTreeMap<ObjectID, (VersionDigest, Owner)>,
    // All the written objects' sequence number should have been updated to the lamport version.
    pub written: WrittenObjects,
    pub loaded_runtime_objects: BTreeMap<ObjectID, DynamicallyLoadedObjectMetadata>,
    pub events: TransactionEvents,
    pub binary_config: BinaryConfig,
    pub runtime_packages_loaded_from_db: BTreeMap<ObjectID, PackageObject>,
    pub lamport_version: SequenceNumber,
}

impl InnerTemporaryStore {
    pub fn get_output_keys(&self, effects: &TransactionEffects) -> Vec<InputKey> {
        let mut output_keys: Vec<_> = self
            .written
            .iter()
            .map(|(id, obj)| {
                if obj.is_package() {
                    InputKey::Package { id: *id }
                } else {
                    InputKey::VersionedObject {
                        id: *id,
                        version: obj.version(),
                    }
                }
            })
            .collect();

        let deleted: HashMap<_, _> = effects
            .deleted()
            .iter()
            .map(|oref| (oref.0, oref.1))
            .collect();

        // add deleted shared objects to the outputkeys that then get sent to notify_commit
        let deleted_output_keys = deleted
            .iter()
            .filter(|(id, _)| {
                self.input_objects
                    .get(id)
                    .is_some_and(|obj| obj.is_shared())
            })
            .map(|(id, seq)| InputKey::VersionedObject {
                id: *id,
                version: *seq,
            });
        output_keys.extend(deleted_output_keys);

        // For any previously deleted shared objects that appeared mutably in the transaction,
        // synthesize a notification for the next version of the object.
        let smeared_version = self.lamport_version;
        let deleted_accessed_objects = effects.deleted_mutably_accessed_shared_objects();
        for object_id in deleted_accessed_objects.into_iter() {
            let key = InputKey::VersionedObject {
                id: object_id,
                version: smeared_version,
            };
            output_keys.push(key);
        }

        output_keys
    }
}

pub struct TemporaryModuleResolver<'a, R> {
    temp_store: &'a InnerTemporaryStore,
    fallback: R,
}

impl<'a, R> TemporaryModuleResolver<'a, R> {
    pub fn new(temp_store: &'a InnerTemporaryStore, fallback: R) -> Self {
        Self {
            temp_store,
            fallback,
        }
    }
}

impl<R> GetModule for TemporaryModuleResolver<'_, R>
where
    R: GetModule<Item = Arc<CompiledModule>, Error = anyhow::Error>,
{
    type Error = anyhow::Error;
    type Item = Arc<CompiledModule>;

    fn get_module_by_id(&self, id: &ModuleId) -> anyhow::Result<Option<Self::Item>, Self::Error> {
        let obj = self.temp_store.written.get(&ObjectID::from(*id.address()));
        if let Some(o) = obj {
            if let Some(p) = o.data.try_as_package() {
                return Ok(Some(Arc::new(p.deserialize_module(
                    &id.name().into(),
                    &self.temp_store.binary_config,
                )?)));
            }
        }
        self.fallback.get_module_by_id(id)
    }
}

pub struct TemporaryPackageStore<'a, R> {
    temp_store: &'a InnerTemporaryStore,
    fallback: R,
}

impl<'a, R> TemporaryPackageStore<'a, R> {
    pub fn new(temp_store: &'a InnerTemporaryStore, fallback: R) -> Self {
        Self {
            temp_store,
            fallback,
        }
    }
}

impl<R> BackingPackageStore for TemporaryPackageStore<'_, R>
where
    R: BackingPackageStore,
{
    fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
        // We first check the objects in the temporary store it is possible to read packages that are
        // just written in the same transaction.
        if let Some(obj) = self.temp_store.written.get(package_id) {
            Ok(Some(PackageObject::new(obj.clone())))
        } else {
            self.fallback.get_package_object(package_id)
        }
    }
}