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