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