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