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}