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