1use crate::{
5    MoveTypeTagTrait, SUI_SYSTEM_ADDRESS,
6    accumulator_event::AccumulatorEvent,
7    base_types::{ObjectID, ObjectRef, SequenceNumber},
8    digests::{ObjectDigest, TransactionDigest},
9    error::SuiError,
10    event::Event,
11    is_system_package,
12    object::{Data, Object, Owner},
13    storage::{BackingPackageStore, ObjectChange},
14    transaction::{Argument, Command, SharedObjectMutability},
15    type_input::TypeInput,
16};
17use move_core_types::{
18    identifier::Identifier,
19    language_storage::{StructTag, TypeTag},
20};
21use serde::{Deserialize, Serialize};
22use std::collections::{BTreeMap, BTreeSet};
23use std::time::Duration;
24
25const SUI_SYSTEM_STATE_INNER_MODULE: &str = "sui_system_state_inner";
26const EXECUTION_TIME_OBSERVATION_CHUNK_KEY_STRUCT: &str = "ExecutionTimeObservationChunkKey";
27
28pub type ConsensusStreamEndedInfo = (
37    ObjectID,
38    SequenceNumber,
39    SharedObjectMutability,
40    TransactionDigest,
41);
42
43pub type ConsensusStreamEndedObjects = Vec<ConsensusStreamEndedInfo>;
45
46#[derive(Clone, Debug, PartialEq, Eq)]
47pub enum SharedInput {
48    Existing(ObjectRef),
49    ConsensusStreamEnded(ConsensusStreamEndedInfo),
50    Cancelled((ObjectID, SequenceNumber)),
51}
52
53#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
54pub struct DynamicallyLoadedObjectMetadata {
55    pub version: SequenceNumber,
56    pub digest: ObjectDigest,
57    pub owner: Owner,
58    pub storage_rebate: u64,
59    pub previous_transaction: TransactionDigest,
60}
61
62pub trait TypeLayoutStore: BackingPackageStore {}
64impl<T> TypeLayoutStore for T where T: BackingPackageStore {}
65
66#[derive(Debug)]
67pub enum ExecutionResults {
68    V1(ExecutionResultsV1),
69    V2(ExecutionResultsV2),
70}
71
72#[derive(Debug)]
73pub struct ExecutionResultsV1 {
74    pub object_changes: BTreeMap<ObjectID, ObjectChange>,
75    pub user_events: Vec<Event>,
76}
77
78#[derive(Debug, Default)]
82pub struct ExecutionResultsV2 {
83    pub written_objects: BTreeMap<ObjectID, Object>,
85    pub modified_objects: BTreeSet<ObjectID>,
88    pub created_object_ids: BTreeSet<ObjectID>,
90    pub deleted_object_ids: BTreeSet<ObjectID>,
93    pub user_events: Vec<Event>,
95    pub accumulator_events: Vec<AccumulatorEvent>,
97
98    pub settlement_input_sui: u64,
104    pub settlement_output_sui: u64,
105}
106
107pub type ExecutionResult = (
108    Vec<(Argument, Vec<u8>, TypeTag)>,
109    Vec<(Vec<u8>, TypeTag)>,
110);
111
112impl ExecutionResultsV2 {
113    pub fn drop_writes(&mut self) {
114        self.written_objects.clear();
115        self.modified_objects.clear();
116        self.created_object_ids.clear();
117        self.deleted_object_ids.clear();
118        self.user_events.clear();
119        self.accumulator_events.clear();
120    }
121
122    pub fn merge_results(&mut self, new_results: Self) {
123        self.written_objects.extend(new_results.written_objects);
124        self.modified_objects.extend(new_results.modified_objects);
125        self.created_object_ids
126            .extend(new_results.created_object_ids);
127        self.deleted_object_ids
128            .extend(new_results.deleted_object_ids);
129        self.user_events.extend(new_results.user_events);
130        self.accumulator_events
131            .extend(new_results.accumulator_events);
132        self.settlement_input_sui += new_results.settlement_input_sui;
133        self.settlement_output_sui += new_results.settlement_output_sui;
134    }
135
136    pub fn update_version_and_previous_tx(
137        &mut self,
138        lamport_version: SequenceNumber,
139        prev_tx: TransactionDigest,
140        input_objects: &BTreeMap<ObjectID, Object>,
141        reshare_at_initial_version: bool,
142    ) {
143        for (id, obj) in self.written_objects.iter_mut() {
144            match &mut obj.data {
149                Data::Move(obj) => {
150                    obj.increment_version_to(lamport_version);
152                }
153
154                Data::Package(pkg) => {
155                    if self.modified_objects.contains(id) {
159                        debug_assert!(is_system_package(*id));
160                        pkg.increment_version();
161                    }
162                }
163            }
164
165            if let Owner::Shared {
169                initial_shared_version,
170            } = &mut obj.owner
171            {
172                if self.created_object_ids.contains(id) {
173                    assert_eq!(
174                        *initial_shared_version,
175                        SequenceNumber::new(),
176                        "Initial version should be blank before this point for {id:?}",
177                    );
178                    *initial_shared_version = lamport_version;
179                }
180
181                if reshare_at_initial_version
183                    && let Some(Owner::Shared {
184                        initial_shared_version: previous_initial_shared_version,
185                    }) = input_objects.get(id).map(|obj| &obj.owner)
186                {
187                    debug_assert!(!self.created_object_ids.contains(id));
188                    debug_assert!(!self.deleted_object_ids.contains(id));
189                    debug_assert!(
190                        *initial_shared_version == SequenceNumber::new()
191                            || *initial_shared_version == *previous_initial_shared_version
192                    );
193
194                    *initial_shared_version = *previous_initial_shared_version;
195                }
196            }
197
198            if let Owner::ConsensusAddressOwner {
200                start_version,
201                owner,
202            } = &mut obj.owner
203            {
204                debug_assert!(!self.deleted_object_ids.contains(id));
205
206                if let Some(Owner::ConsensusAddressOwner {
207                    start_version: previous_start_version,
208                    owner: previous_owner,
209                }) = input_objects.get(id).map(|obj| &obj.owner)
210                {
211                    if owner == previous_owner {
212                        *start_version = *previous_start_version;
215                    } else {
216                        *start_version = lamport_version;
218                    }
219                } else {
220                    *start_version = lamport_version;
223                }
224            }
225
226            obj.previous_transaction = prev_tx;
227        }
228    }
229}
230
231#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Serialize, Deserialize)]
232pub enum ExecutionTimeObservationKey {
233    MoveEntryPoint {
235        package: ObjectID,
237        module: String,
239        function: String,
241        type_arguments: Vec<TypeInput>,
244    },
245    TransferObjects,
246    SplitCoins,
247    MergeCoins,
248    Publish, MakeMoveVec,
250    Upgrade,
251}
252
253impl std::fmt::Display for ExecutionTimeObservationKey {
254    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255        match self {
256            ExecutionTimeObservationKey::MoveEntryPoint {
257                module, function, ..
258            } => {
259                write!(f, "{}:{}", module, function)
260            }
261            ExecutionTimeObservationKey::TransferObjects => write!(f, "TransferObjects"),
262            ExecutionTimeObservationKey::SplitCoins => write!(f, "SplitCoins"),
263            ExecutionTimeObservationKey::MergeCoins => write!(f, "MergeCoins"),
264            ExecutionTimeObservationKey::Publish => write!(f, "Publish"),
265            ExecutionTimeObservationKey::MakeMoveVec => write!(f, "MakeMoveVec"),
266            ExecutionTimeObservationKey::Upgrade => write!(f, "Upgrade"),
267        }
268    }
269}
270
271impl ExecutionTimeObservationKey {
272    pub fn is_move_call(&self) -> bool {
273        matches!(self, ExecutionTimeObservationKey::MoveEntryPoint { .. })
274    }
275
276    pub fn from_command(command: &Command) -> Self {
277        match command {
278            Command::MoveCall(call) => ExecutionTimeObservationKey::MoveEntryPoint {
279                package: call.package,
280                module: call.module.clone(),
281                function: call.function.clone(),
282                type_arguments: vec![],
283            },
284            Command::TransferObjects(_, _) => ExecutionTimeObservationKey::TransferObjects,
285            Command::SplitCoins(_, _) => ExecutionTimeObservationKey::SplitCoins,
286            Command::MergeCoins(_, _) => ExecutionTimeObservationKey::MergeCoins,
287            Command::Publish(_, _) => ExecutionTimeObservationKey::Publish,
288            Command::MakeMoveVec(_, _) => ExecutionTimeObservationKey::MakeMoveVec,
289            Command::Upgrade(_, _, _, _) => ExecutionTimeObservationKey::Upgrade,
290        }
291    }
292
293    pub fn default_duration(&self) -> Duration {
294        match self {
295            ExecutionTimeObservationKey::MoveEntryPoint { .. } => Duration::from_millis(1),
296            ExecutionTimeObservationKey::TransferObjects => Duration::from_millis(1),
297            ExecutionTimeObservationKey::SplitCoins => Duration::from_millis(1),
298            ExecutionTimeObservationKey::MergeCoins => Duration::from_millis(1),
299            ExecutionTimeObservationKey::Publish => Duration::from_millis(3),
300            ExecutionTimeObservationKey::MakeMoveVec => Duration::from_millis(1),
301            ExecutionTimeObservationKey::Upgrade => Duration::from_millis(3),
302        }
303    }
304}
305
306#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Serialize, Deserialize)]
307pub struct ExecutionTimeObservationChunkKey {
308    pub chunk_index: u64,
309}
310
311impl MoveTypeTagTrait for ExecutionTimeObservationChunkKey {
312    fn get_type_tag() -> TypeTag {
313        TypeTag::Struct(Box::new(StructTag {
314            address: SUI_SYSTEM_ADDRESS,
315            module: Identifier::new(SUI_SYSTEM_STATE_INNER_MODULE).unwrap(),
316            name: Identifier::new(EXECUTION_TIME_OBSERVATION_CHUNK_KEY_STRUCT).unwrap(),
317            type_params: vec![],
318        }))
319    }
320}
321
322#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
323pub enum ExecutionTiming {
324    Success(Duration),
325    Abort(Duration),
326}
327
328impl ExecutionTiming {
329    pub fn is_abort(&self) -> bool {
330        matches!(self, ExecutionTiming::Abort(_))
331    }
332
333    pub fn duration(&self) -> Duration {
334        match self {
335            ExecutionTiming::Success(duration) => *duration,
336            ExecutionTiming::Abort(duration) => *duration,
337        }
338    }
339}
340
341pub type ResultWithTimings<R, E> = Result<(R, Vec<ExecutionTiming>), (E, Vec<ExecutionTiming>)>;
342
343pub enum ExecutionOutput<T> {
345    Success(T),
347    EpochEnded,
350    Fatal(SuiError),
352    RetryLater,
356}
357
358impl<T> ExecutionOutput<T> {
359    pub fn unwrap(self) -> T {
362        match self {
363            ExecutionOutput::Success(value) => value,
364            ExecutionOutput::EpochEnded => {
365                panic!("called `ExecutionOutput::unwrap()` on `EpochEnded`")
366            }
367            ExecutionOutput::Fatal(e) => {
368                panic!("called `ExecutionOutput::unwrap()` on `Fatal`: {e}")
369            }
370            ExecutionOutput::RetryLater => {
371                panic!("called `ExecutionOutput::unwrap()` on `RetryLater`")
372            }
373        }
374    }
375
376    pub fn unwrap_err<S>(self) -> ExecutionOutput<S> {
378        match self {
379            Self::Success(_) => {
380                panic!("called `ExecutionOutput::unwrap_err()` on `Success`")
381            }
382            Self::EpochEnded => ExecutionOutput::EpochEnded,
383            Self::Fatal(e) => ExecutionOutput::Fatal(e),
384            Self::RetryLater => ExecutionOutput::RetryLater,
385        }
386    }
387}