1use std::collections::BTreeSet;
5
6use move_binary_format::file_format::AbilitySet;
7use move_core_types::u256::U256;
8use serde::Deserialize;
9use sui_types::{
10 TypeTag,
11 base_types::{ObjectID, SequenceNumber, SuiAddress},
12 coin::Coin,
13 error::ExecutionError,
14 execution_status::{CommandArgumentError, ExecutionErrorKind},
15 funds_accumulator::Withdrawal,
16 object::Owner,
17 storage::{BackingPackageStore, ChildObjectResolver, StorageView},
18 transfer::Receiving,
19};
20
21pub trait SuiResolver: BackingPackageStore {
22 fn as_backing_package_store(&self) -> &dyn BackingPackageStore;
23}
24
25impl<T> SuiResolver for T
26where
27 T: BackingPackageStore,
28{
29 fn as_backing_package_store(&self) -> &dyn BackingPackageStore {
30 self
31 }
32}
33
34pub trait ExecutionState: StorageView + SuiResolver {
36 fn as_sui_resolver(&self) -> &dyn SuiResolver;
37 fn as_child_resolver(&self) -> &dyn ChildObjectResolver;
38}
39
40impl<T> ExecutionState for T
41where
42 T: StorageView,
43 T: SuiResolver,
44{
45 fn as_sui_resolver(&self) -> &dyn SuiResolver {
46 self
47 }
48
49 fn as_child_resolver(&self) -> &dyn ChildObjectResolver {
50 self
51 }
52}
53
54#[derive(Clone, Debug)]
55pub enum Mutability {
56 Mutable,
57 Immutable,
58 NonExclusiveWrite,
59}
60
61#[derive(Clone, Debug)]
62pub enum InputObjectMetadata {
63 Receiving {
64 id: ObjectID,
65 version: SequenceNumber,
66 },
67 InputObject {
68 id: ObjectID,
69 mutability: Mutability,
70 owner: Owner,
71 version: SequenceNumber,
72 },
73}
74
75#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
76pub struct ExecutionType {
77 pub type_: TypeTag,
78 pub abilities: AbilitySet,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum UsageKind {
83 BorrowImm,
84 BorrowMut,
85 ByValue,
86}
87
88#[derive(Clone, Copy)]
89pub enum CommandKind {
90 MoveCall,
91 MakeMoveVec,
92 TransferObjects,
93 SplitCoins,
94 MergeCoins,
95 Publish,
96 Upgrade,
97}
98
99#[derive(Clone, Debug)]
100pub struct InputValue {
101 pub object_metadata: Option<InputObjectMetadata>,
103 pub inner: ResultValue,
104}
105
106#[derive(Clone, Debug)]
107pub struct ResultValue {
108 pub last_usage_kind: Option<UsageKind>,
112 pub value: Option<Value>,
113 pub shared_object_ids: BTreeSet<ObjectID>,
114}
115
116#[derive(Debug, Clone)]
117pub enum Value {
118 Object(ObjectValue),
119 Raw(RawValueType, Vec<u8>),
120 Receiving(ObjectID, SequenceNumber, Option<ExecutionType>),
121}
122
123#[derive(Debug, Clone)]
124pub struct ObjectValue {
125 pub type_: ExecutionType,
126 pub has_public_transfer: bool,
127 pub used_in_non_entry_move_call: bool,
131 pub contents: ObjectContents,
132}
133
134#[derive(Debug, Copy, Clone)]
135pub enum SizeBound {
136 Object(u64),
137 VectorElem(u64),
138 Raw(u64),
139}
140
141#[derive(Debug, Clone)]
142pub enum ObjectContents {
143 Coin(Coin),
144 Raw(Vec<u8>),
145}
146
147#[derive(Debug, Clone)]
148pub enum RawValueType {
149 Any,
150 Loaded {
151 ty: ExecutionType,
152 used_in_non_entry_move_call: bool,
153 },
154}
155
156impl InputObjectMetadata {
157 pub fn id(&self) -> ObjectID {
158 match self {
159 InputObjectMetadata::Receiving { id, .. } => *id,
160 InputObjectMetadata::InputObject { id, .. } => *id,
161 }
162 }
163
164 pub fn version(&self) -> SequenceNumber {
165 match self {
166 InputObjectMetadata::Receiving { version, .. } => *version,
167 InputObjectMetadata::InputObject { version, .. } => *version,
168 }
169 }
170}
171
172impl InputValue {
173 pub fn new_object(object_metadata: InputObjectMetadata, value: ObjectValue) -> Self {
174 let mut inner = ResultValue::new(Value::Object(value));
175 if let InputObjectMetadata::InputObject {
176 id,
177 owner: Owner::Shared { .. },
178 ..
179 } = &object_metadata
180 {
181 inner.shared_object_ids.insert(*id);
182 }
183 InputValue {
184 object_metadata: Some(object_metadata),
185 inner,
186 }
187 }
188
189 pub fn new_raw(ty: RawValueType, value: Vec<u8>) -> Self {
190 InputValue {
191 object_metadata: None,
192 inner: ResultValue::new(Value::Raw(ty, value)),
193 }
194 }
195
196 pub fn new_receiving_object(id: ObjectID, version: SequenceNumber) -> Self {
197 InputValue {
198 object_metadata: Some(InputObjectMetadata::Receiving { id, version }),
199 inner: ResultValue::new(Value::Receiving(id, version, None)),
200 }
201 }
202
203 pub fn withdrawal(withdrawal_ty: RawValueType, owner: SuiAddress, limit: U256) -> Self {
204 let value = Value::Raw(
205 withdrawal_ty,
206 bcs::to_bytes(&Withdrawal::new(owner, limit)).unwrap(),
207 );
208 InputValue {
209 object_metadata: None,
210 inner: ResultValue {
211 last_usage_kind: None,
212 value: Some(value),
213 shared_object_ids: BTreeSet::new(),
214 },
215 }
216 }
217}
218
219impl ResultValue {
220 pub fn new(value: Value) -> Self {
221 Self {
222 last_usage_kind: None,
223 value: Some(value),
224 shared_object_ids: BTreeSet::new(),
225 }
226 }
227}
228
229impl Value {
230 pub fn is_copyable(&self) -> bool {
231 match self {
232 Value::Object(_) => false,
233 Value::Raw(RawValueType::Any, _) => true,
234 Value::Raw(RawValueType::Loaded { ty, .. }, _) => ty.abilities.has_copy(),
235 Value::Receiving(_, _, _) => false,
236 }
237 }
238
239 pub fn write_bcs_bytes(
240 &self,
241 buf: &mut Vec<u8>,
242 bound: Option<SizeBound>,
243 ) -> Result<(), ExecutionError> {
244 match self {
245 Value::Object(obj_value) => obj_value.write_bcs_bytes(buf, bound)?,
246 Value::Raw(_, bytes) => buf.extend(bytes),
247 Value::Receiving(id, version, _) => {
248 buf.extend(Receiving::new(*id, *version).to_bcs_bytes())
249 }
250 }
251 if let Some(bound) = bound {
252 ensure_serialized_size(buf.len() as u64, bound)?;
253 }
254
255 Ok(())
256 }
257
258 pub fn was_used_in_non_entry_move_call(&self) -> bool {
259 match self {
260 Value::Object(obj) => obj.used_in_non_entry_move_call,
261 Value::Raw(RawValueType::Any, _) => false,
264 Value::Raw(
265 RawValueType::Loaded {
266 used_in_non_entry_move_call,
267 ..
268 },
269 _,
270 ) => *used_in_non_entry_move_call,
271 Value::Receiving(_, _, _) => false,
274 }
275 }
276}
277
278impl ObjectValue {
279 pub unsafe fn coin(type_: ExecutionType, coin: Coin) -> Self {
282 Self {
283 type_,
284 has_public_transfer: true,
285 used_in_non_entry_move_call: false,
286 contents: ObjectContents::Coin(coin),
287 }
288 }
289
290 pub fn ensure_public_transfer_eligible(&self) -> Result<(), ExecutionError> {
291 if !self.has_public_transfer {
292 return Err(ExecutionErrorKind::InvalidTransferObject.into());
293 }
294 Ok(())
295 }
296
297 pub fn write_bcs_bytes(
298 &self,
299 buf: &mut Vec<u8>,
300 bound: Option<SizeBound>,
301 ) -> Result<(), ExecutionError> {
302 match &self.contents {
303 ObjectContents::Raw(bytes) => buf.extend(bytes),
304 ObjectContents::Coin(coin) => buf.extend(coin.to_bcs_bytes()),
305 }
306 if let Some(bound) = bound {
307 ensure_serialized_size(buf.len() as u64, bound)?;
308 }
309 Ok(())
310 }
311}
312
313pub fn ensure_serialized_size(size: u64, bound: SizeBound) -> Result<(), ExecutionError> {
314 let bound_size = match bound {
315 SizeBound::Object(bound_size)
316 | SizeBound::VectorElem(bound_size)
317 | SizeBound::Raw(bound_size) => bound_size,
318 };
319 if size > bound_size {
320 let e = match bound {
321 SizeBound::Object(_) => ExecutionErrorKind::MoveObjectTooBig {
322 object_size: size,
323 max_object_size: bound_size,
324 },
325 SizeBound::VectorElem(_) => ExecutionErrorKind::MoveVectorElemTooBig {
326 value_size: size,
327 max_scaled_size: bound_size,
328 },
329 SizeBound::Raw(_) => ExecutionErrorKind::MoveRawValueTooBig {
330 value_size: size,
331 max_scaled_size: bound_size,
332 },
333 };
334 let msg = "Serialized bytes of value too large".to_owned();
335 return Err(ExecutionError::new_with_source(e, msg));
336 }
337 Ok(())
338}
339
340pub trait TryFromValue: Sized {
341 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError>;
342}
343
344impl TryFromValue for Value {
345 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
346 Ok(value)
347 }
348}
349
350impl TryFromValue for ObjectValue {
351 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
352 match value {
353 Value::Object(o) => Ok(o),
354 Value::Raw(RawValueType::Any, _) => Err(CommandArgumentError::TypeMismatch),
355 Value::Raw(RawValueType::Loaded { .. }, _) => Err(CommandArgumentError::TypeMismatch),
356 Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch),
357 }
358 }
359}
360
361impl TryFromValue for SuiAddress {
362 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
363 try_from_value_prim(&value, TypeTag::Address)
364 }
365}
366
367impl TryFromValue for u64 {
368 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
369 try_from_value_prim(&value, TypeTag::U64)
370 }
371}
372
373fn try_from_value_prim<'a, T: Deserialize<'a>>(
374 value: &'a Value,
375 expected_ty: TypeTag,
376) -> Result<T, CommandArgumentError> {
377 match value {
378 Value::Object(_) => Err(CommandArgumentError::TypeMismatch),
379 Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch),
380 Value::Raw(RawValueType::Any, bytes) => {
381 bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes)
382 }
383 Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => {
384 if ty.type_ != expected_ty {
385 return Err(CommandArgumentError::TypeMismatch);
386 }
387 bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes)
388 }
389 }
390}