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