1use move_binary_format::file_format::AbilitySet;
5use move_core_types::identifier::IdentStr;
6use move_vm_types::loaded_data::runtime_types::Type;
7use serde::Deserialize;
8use sui_types::{
9 base_types::{ObjectID, SequenceNumber, SuiAddress},
10 coin::Coin,
11 error::{ExecutionError, ExecutionErrorKind},
12 execution_status::CommandArgumentError,
13 object::Owner,
14 storage::{BackingPackageStore, ChildObjectResolver, StorageView},
15 transfer::Receiving,
16};
17
18pub trait SuiResolver: BackingPackageStore {
19 fn as_backing_package_store(&self) -> &dyn BackingPackageStore;
20}
21
22impl<T> SuiResolver for T
23where
24 T: BackingPackageStore,
25{
26 fn as_backing_package_store(&self) -> &dyn BackingPackageStore {
27 self
28 }
29}
30
31pub trait ExecutionState: StorageView + SuiResolver {
33 fn as_sui_resolver(&self) -> &dyn SuiResolver;
34 fn as_child_resolver(&self) -> &dyn ChildObjectResolver;
35}
36
37impl<T> ExecutionState for T
38where
39 T: StorageView,
40 T: SuiResolver,
41{
42 fn as_sui_resolver(&self) -> &dyn SuiResolver {
43 self
44 }
45
46 fn as_child_resolver(&self) -> &dyn ChildObjectResolver {
47 self
48 }
49}
50
51#[derive(Clone, Debug)]
52pub enum InputObjectMetadata {
53 Receiving {
54 id: ObjectID,
55 version: SequenceNumber,
56 },
57 InputObject {
58 id: ObjectID,
59 is_mutable_input: bool,
60 owner: Owner,
61 version: SequenceNumber,
62 },
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum UsageKind {
67 BorrowImm,
68 BorrowMut,
69 ByValue,
70}
71
72#[derive(Clone, Copy)]
73pub enum CommandKind<'a> {
74 MoveCall {
75 package: ObjectID,
76 module: &'a IdentStr,
77 function: &'a IdentStr,
78 },
79 MakeMoveVec,
80 TransferObjects,
81 SplitCoins,
82 MergeCoins,
83 Publish,
84 Upgrade,
85}
86
87#[derive(Clone, Debug)]
88pub struct InputValue {
89 pub object_metadata: Option<InputObjectMetadata>,
91 pub inner: ResultValue,
92}
93
94#[derive(Clone, Debug)]
95pub struct ResultValue {
96 pub last_usage_kind: Option<UsageKind>,
100 pub value: Option<Value>,
101}
102
103#[derive(Debug, Clone)]
104pub enum Value {
105 Object(ObjectValue),
106 Raw(RawValueType, Vec<u8>),
107 Receiving(ObjectID, SequenceNumber, Option<Type>),
108}
109
110#[derive(Debug, Clone)]
111pub struct ObjectValue {
112 pub type_: Type,
113 pub has_public_transfer: bool,
114 pub used_in_non_entry_move_call: bool,
118 pub contents: ObjectContents,
119}
120
121#[derive(Debug, Clone)]
122pub enum ObjectContents {
123 Coin(Coin),
124 Raw(Vec<u8>),
125}
126
127#[derive(Debug, Clone)]
128pub enum RawValueType {
129 Any,
130 Loaded {
131 ty: Type,
132 abilities: AbilitySet,
133 used_in_non_entry_move_call: bool,
134 },
135}
136
137impl InputObjectMetadata {
138 pub fn id(&self) -> ObjectID {
139 match self {
140 InputObjectMetadata::Receiving { id, .. } => *id,
141 InputObjectMetadata::InputObject { id, .. } => *id,
142 }
143 }
144
145 pub fn version(&self) -> SequenceNumber {
146 match self {
147 InputObjectMetadata::Receiving { version, .. } => *version,
148 InputObjectMetadata::InputObject { version, .. } => *version,
149 }
150 }
151}
152
153impl InputValue {
154 pub fn new_object(object_metadata: InputObjectMetadata, value: ObjectValue) -> Self {
155 InputValue {
156 object_metadata: Some(object_metadata),
157 inner: ResultValue::new(Value::Object(value)),
158 }
159 }
160
161 pub fn new_raw(ty: RawValueType, value: Vec<u8>) -> Self {
162 InputValue {
163 object_metadata: None,
164 inner: ResultValue::new(Value::Raw(ty, value)),
165 }
166 }
167
168 pub fn new_receiving_object(id: ObjectID, version: SequenceNumber) -> Self {
169 InputValue {
170 object_metadata: Some(InputObjectMetadata::Receiving { id, version }),
171 inner: ResultValue::new(Value::Receiving(id, version, None)),
172 }
173 }
174}
175
176impl ResultValue {
177 pub fn new(value: Value) -> Self {
178 Self {
179 last_usage_kind: None,
180 value: Some(value),
181 }
182 }
183}
184
185impl Value {
186 pub fn is_copyable(&self) -> bool {
187 match self {
188 Value::Object(_) => false,
189 Value::Raw(RawValueType::Any, _) => true,
190 Value::Raw(RawValueType::Loaded { abilities, .. }, _) => abilities.has_copy(),
191 Value::Receiving(_, _, _) => false,
192 }
193 }
194
195 pub fn write_bcs_bytes(&self, buf: &mut Vec<u8>) {
196 match self {
197 Value::Object(obj_value) => obj_value.write_bcs_bytes(buf),
198 Value::Raw(_, bytes) => buf.extend(bytes),
199 Value::Receiving(id, version, _) => {
200 buf.extend(Receiving::new(*id, *version).to_bcs_bytes())
201 }
202 }
203 }
204
205 pub fn was_used_in_non_entry_move_call(&self) -> bool {
206 match self {
207 Value::Object(obj) => obj.used_in_non_entry_move_call,
208 Value::Raw(RawValueType::Any, _) => false,
211 Value::Raw(
212 RawValueType::Loaded {
213 used_in_non_entry_move_call,
214 ..
215 },
216 _,
217 ) => *used_in_non_entry_move_call,
218 Value::Receiving(_, _, _) => false,
221 }
222 }
223}
224
225impl ObjectValue {
226 pub unsafe fn coin(type_: Type, coin: Coin) -> Self {
229 Self {
230 type_,
231 has_public_transfer: true,
232 used_in_non_entry_move_call: false,
233 contents: ObjectContents::Coin(coin),
234 }
235 }
236
237 pub fn ensure_public_transfer_eligible(&self) -> Result<(), ExecutionError> {
238 if !self.has_public_transfer {
239 return Err(ExecutionErrorKind::InvalidTransferObject.into());
240 }
241 Ok(())
242 }
243
244 pub fn write_bcs_bytes(&self, buf: &mut Vec<u8>) {
245 match &self.contents {
246 ObjectContents::Raw(bytes) => buf.extend(bytes),
247 ObjectContents::Coin(coin) => buf.extend(coin.to_bcs_bytes()),
248 }
249 }
250}
251
252pub trait TryFromValue: Sized {
253 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError>;
254}
255
256impl TryFromValue for Value {
257 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
258 Ok(value)
259 }
260}
261
262impl TryFromValue for ObjectValue {
263 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
264 match value {
265 Value::Object(o) => Ok(o),
266 Value::Raw(RawValueType::Any, _) => Err(CommandArgumentError::TypeMismatch),
267 Value::Raw(RawValueType::Loaded { .. }, _) => Err(CommandArgumentError::TypeMismatch),
268 Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch),
269 }
270 }
271}
272
273impl TryFromValue for SuiAddress {
274 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
275 try_from_value_prim(&value, Type::Address)
276 }
277}
278
279impl TryFromValue for u64 {
280 fn try_from_value(value: Value) -> Result<Self, CommandArgumentError> {
281 try_from_value_prim(&value, Type::U64)
282 }
283}
284
285fn try_from_value_prim<'a, T: Deserialize<'a>>(
286 value: &'a Value,
287 expected_ty: Type,
288) -> Result<T, CommandArgumentError> {
289 match value {
290 Value::Object(_) => Err(CommandArgumentError::TypeMismatch),
291 Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch),
292 Value::Raw(RawValueType::Any, bytes) => {
293 bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes)
294 }
295 Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => {
296 if ty != &expected_ty {
297 return Err(CommandArgumentError::TypeMismatch);
298 }
299 bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes)
300 }
301 }
302}