sui_adapter_latest/static_programmable_transactions/loading/
ast.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    gas_charger::GasPayment,
6    static_programmable_transactions::linkage::resolved_linkage::{
7        ExecutableLinkage, ResolvedLinkage,
8    },
9};
10use indexmap::IndexSet;
11use move_binary_format::file_format::{
12    AbilitySet, CodeOffset, FunctionDefinitionIndex, Visibility,
13};
14use move_core_types::{
15    account_address::AccountAddress,
16    identifier::IdentStr,
17    language_storage::{ModuleId, StructTag},
18    u256::U256,
19};
20use std::rc::Rc;
21use sui_types::{
22    Identifier, TypeTag,
23    base_types::{ObjectID, ObjectRef, RESOLVED_TX_CONTEXT, SequenceNumber, TxContextKind},
24};
25
26//**************************************************************************************************
27// AST Nodes
28//**************************************************************************************************
29
30#[derive(Debug)]
31pub struct Transaction {
32    pub gas_payment: Option<GasPayment>,
33    pub inputs: Inputs,
34    /// Original number of commands in the transaction. After typing, Spanned indices in the AST
35    /// should be < `original_command_len`
36    pub original_command_len: usize,
37    pub commands: Commands,
38}
39
40pub type Inputs = Vec<(InputArg, InputType)>;
41
42pub type Commands = Vec<Command>;
43
44#[derive(Debug)]
45#[cfg_attr(debug_assertions, derive(Clone))]
46pub enum InputArg {
47    Pure(Vec<u8>),
48    Receiving(ObjectRef),
49    Object(ObjectArg),
50    FundsWithdrawal(FundsWithdrawalArg),
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum SharedObjectKind {
55    Legacy,
56    Party,
57}
58
59#[derive(Debug)]
60#[cfg_attr(debug_assertions, derive(Clone))]
61pub enum ObjectArg {
62    ImmObject(ObjectRef),
63    OwnedObject(ObjectRef),
64    SharedObject {
65        id: ObjectID,
66        initial_shared_version: SequenceNumber,
67        mutability: ObjectMutability,
68        kind: SharedObjectKind,
69    },
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum ObjectMutability {
74    Mutable,
75    Immutable,
76    NonExclusiveWrite,
77}
78
79#[derive(Debug)]
80#[cfg_attr(debug_assertions, derive(Clone))]
81pub struct FundsWithdrawalArg {
82    // if true, it was from a compatibility object input, not a intentional withdrawal argument
83    pub from_compatibility_object: bool,
84    /// The full type `sui::funds_accumulator::Withdrawal<T>`
85    pub ty: Type,
86    pub owner: AccountAddress,
87    /// This amount is verified to be <= the max for the type described by the `T` in `ty`
88    pub amount: U256,
89}
90
91#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
92pub enum Type {
93    Bool,
94    U8,
95    U16,
96    U32,
97    U64,
98    U128,
99    U256,
100    Address,
101    Signer,
102    Vector(Rc<Vector>),
103    Datatype(Rc<Datatype>),
104    Reference(/* is mut */ bool, Rc<Type>),
105}
106
107#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct Vector {
109    pub abilities: AbilitySet,
110    pub element_type: Type,
111}
112
113#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct Datatype {
115    pub abilities: AbilitySet,
116    pub module: ModuleId,
117    pub name: Identifier,
118    pub type_arguments: Vec<Type>,
119}
120
121#[derive(Debug, Clone)]
122pub enum InputType {
123    Bytes,
124    Fixed(Type),
125}
126
127#[derive(Debug)]
128pub enum Command {
129    MoveCall(Box<MoveCall>),
130    TransferObjects(Vec<Argument>, Argument),
131    SplitCoins(Argument, Vec<Argument>),
132    MergeCoins(Argument, Vec<Argument>),
133    MakeMoveVec(/* T for vector<T> */ Option<Type>, Vec<Argument>),
134    Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
135    Upgrade(
136        Vec<Vec<u8>>,
137        Vec<ObjectID>,
138        ObjectID,
139        Argument,
140        ResolvedLinkage,
141    ),
142}
143
144#[derive(Debug)]
145pub struct LoadedFunctionInstantiation {
146    pub parameters: Vec<Type>,
147    pub return_: Vec<Type>,
148}
149
150#[derive(Debug)]
151pub struct LoadedFunction {
152    pub version_mid: ModuleId,
153    pub original_mid: ModuleId,
154    pub name: Identifier,
155    pub type_arguments: Vec<Type>,
156    pub signature: LoadedFunctionInstantiation,
157    pub linkage: ExecutableLinkage,
158    pub instruction_length: CodeOffset,
159    pub definition_index: FunctionDefinitionIndex,
160    pub visibility: Visibility,
161    pub is_entry: bool,
162    pub is_native: bool,
163}
164
165#[derive(Debug)]
166pub struct MoveCall {
167    pub function: LoadedFunction,
168    pub arguments: Vec<Argument>,
169}
170
171pub use sui_types::transaction::Argument;
172
173//**************************************************************************************************
174// impl
175//**************************************************************************************************
176
177impl ObjectArg {
178    pub fn id(&self) -> ObjectID {
179        match self {
180            ObjectArg::ImmObject(oref) | ObjectArg::OwnedObject(oref) => oref.0,
181            ObjectArg::SharedObject { id, .. } => *id,
182        }
183    }
184
185    pub fn mutability(&self) -> ObjectMutability {
186        match self {
187            ObjectArg::ImmObject(_) => ObjectMutability::Immutable,
188            ObjectArg::OwnedObject(_) => ObjectMutability::Mutable,
189            ObjectArg::SharedObject { mutability, .. } => *mutability,
190        }
191    }
192}
193
194impl Type {
195    pub fn abilities(&self) -> AbilitySet {
196        match self {
197            Type::Bool
198            | Type::U8
199            | Type::U16
200            | Type::U32
201            | Type::U64
202            | Type::U128
203            | Type::U256
204            | Type::Address => AbilitySet::PRIMITIVES,
205            Type::Signer => AbilitySet::SIGNER,
206            Type::Reference(_, _) => AbilitySet::REFERENCES,
207            Type::Vector(v) => v.abilities,
208            Type::Datatype(dt) => dt.abilities,
209        }
210    }
211
212    pub fn is_tx_context(&self) -> TxContextKind {
213        let (is_mut, inner) = match self {
214            Type::Reference(is_mut, inner) => (*is_mut, inner),
215            _ => return TxContextKind::None,
216        };
217        let Type::Datatype(dt) = &**inner else {
218            return TxContextKind::None;
219        };
220        if dt.qualified_ident() == RESOLVED_TX_CONTEXT {
221            if is_mut {
222                TxContextKind::Mutable
223            } else {
224                TxContextKind::Immutable
225            }
226        } else {
227            TxContextKind::None
228        }
229    }
230    pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
231        match self {
232            Type::Bool
233            | Type::U8
234            | Type::U16
235            | Type::U32
236            | Type::U64
237            | Type::U128
238            | Type::U256
239            | Type::Address
240            | Type::Signer => IndexSet::new(),
241            Type::Vector(v) => v.element_type.all_addresses(),
242            Type::Reference(_, inner) => inner.all_addresses(),
243            Type::Datatype(dt) => dt.all_addresses(),
244        }
245    }
246
247    pub fn node_count(&self) -> u64 {
248        use Type::*;
249        let mut total = 0u64;
250        let mut stack = vec![self];
251
252        while let Some(ty) = stack.pop() {
253            total = total.saturating_add(1);
254            match ty {
255                Bool | U8 | U16 | U32 | U64 | U128 | U256 | Address | Signer => {}
256                Vector(v) => stack.push(&v.element_type),
257                Reference(_, inner) => stack.push(inner),
258                Datatype(dt) => {
259                    stack.extend(&dt.type_arguments);
260                }
261            }
262        }
263
264        total
265    }
266
267    pub fn is_reference(&self) -> bool {
268        match self {
269            Type::Bool
270            | Type::U8
271            | Type::U16
272            | Type::U32
273            | Type::U64
274            | Type::U128
275            | Type::U256
276            | Type::Address
277            | Type::Signer
278            | Type::Vector(_)
279            | Type::Datatype(_) => false,
280            Type::Reference(_, _) => true,
281        }
282    }
283}
284
285impl Datatype {
286    pub fn qualified_ident(&self) -> (&AccountAddress, &IdentStr, &IdentStr) {
287        (
288            self.module.address(),
289            self.module.name(),
290            self.name.as_ident_str(),
291        )
292    }
293
294    pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
295        let mut addresses = IndexSet::new();
296        addresses.insert(*self.module.address());
297        for arg in &self.type_arguments {
298            addresses.extend(arg.all_addresses());
299        }
300        addresses
301    }
302}
303
304impl Command {
305    pub fn arguments_mut(&mut self) -> Box<dyn Iterator<Item = &mut Argument> + '_> {
306        match self {
307            Command::MoveCall(mc) => Box::new(mc.arguments.iter_mut()),
308            Command::TransferObjects(objs, recipient) => {
309                Box::new(objs.iter_mut().chain(std::iter::once(recipient)))
310            }
311            Command::SplitCoins(coin, amounts) => {
312                Box::new(std::iter::once(coin).chain(amounts.iter_mut()))
313            }
314            Command::MergeCoins(coin, coins) => {
315                Box::new(std::iter::once(coin).chain(coins.iter_mut()))
316            }
317            Command::MakeMoveVec(_, elements) => Box::new(elements.iter_mut()),
318            Command::Publish(_, _, _) => Box::new(std::iter::empty()),
319            Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
320        }
321    }
322
323    pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
324        match self {
325            Command::MoveCall(mc) => Box::new(mc.arguments.iter()),
326            Command::TransferObjects(objs, recipient) => {
327                Box::new(objs.iter().chain(std::iter::once(recipient)))
328            }
329            Command::SplitCoins(coin, amounts) => {
330                Box::new(std::iter::once(coin).chain(amounts.iter()))
331            }
332            Command::MergeCoins(coin, coins) => Box::new(std::iter::once(coin).chain(coins.iter())),
333            Command::MakeMoveVec(_, elements) => Box::new(elements.iter()),
334            Command::Publish(_, _, _) => Box::new(std::iter::empty()),
335            Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
336        }
337    }
338}
339
340//**************************************************************************************************
341// Traits
342//**************************************************************************************************
343
344impl TryFrom<Type> for TypeTag {
345    type Error = &'static str;
346    fn try_from(ty: Type) -> Result<Self, Self::Error> {
347        Ok(match ty {
348            Type::Bool => TypeTag::Bool,
349            Type::U8 => TypeTag::U8,
350            Type::U16 => TypeTag::U16,
351            Type::U32 => TypeTag::U32,
352            Type::U64 => TypeTag::U64,
353            Type::U128 => TypeTag::U128,
354            Type::U256 => TypeTag::U256,
355            Type::Address => TypeTag::Address,
356            Type::Signer => TypeTag::Signer,
357            Type::Vector(inner) => {
358                let Vector { element_type, .. } = &*inner;
359                TypeTag::Vector(Box::new(element_type.clone().try_into()?))
360            }
361            Type::Datatype(dt) => {
362                let dt: &Datatype = &dt;
363                TypeTag::Struct(Box::new(dt.try_into()?))
364            }
365            Type::Reference(_, _) => return Err("unexpected reference type"),
366        })
367    }
368}
369
370impl TryFrom<&Datatype> for StructTag {
371    type Error = &'static str;
372
373    fn try_from(dt: &Datatype) -> Result<Self, Self::Error> {
374        let Datatype {
375            module,
376            name,
377            type_arguments,
378            ..
379        } = dt;
380        Ok(StructTag {
381            address: *module.address(),
382            module: module.name().to_owned(),
383            name: name.to_owned(),
384            type_params: type_arguments
385                .iter()
386                .map(|t| t.clone().try_into())
387                .collect::<Result<Vec<TypeTag>, _>>()?,
388        })
389    }
390}
391
392//**************************************************************************************************
393// Tests
394//**************************************************************************************************
395
396#[test]
397fn enum_size() {
398    assert_eq!(std::mem::size_of::<Type>(), 16);
399}