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