sui_adapter_latest/static_programmable_transactions/typing/
ast.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::static_programmable_transactions::{
5    linkage::resolved_linkage::ResolvedLinkage, loading::ast as L, spanned::Spanned,
6};
7use indexmap::IndexSet;
8use move_core_types::{account_address::AccountAddress, u256::U256};
9use move_vm_types::values::VectorSpecialization;
10use std::cell::OnceCell;
11use sui_types::base_types::{ObjectID, ObjectRef};
12
13//**************************************************************************************************
14// AST Nodes
15//**************************************************************************************************
16
17#[derive(Debug)]
18pub struct Transaction {
19    /// Gathered BCS bytes from Pure inputs
20    pub bytes: IndexSet<Vec<u8>>,
21    // All input objects
22    pub objects: Vec<ObjectInput>,
23    /// All Withdrawal inputs
24    pub withdrawals: Vec<WithdrawalInput>,
25    /// All pure inputs
26    pub pure: Vec<PureInput>,
27    /// All receiving inputs
28    pub receiving: Vec<ReceivingInput>,
29    pub commands: Commands,
30}
31
32/// The original index into the `input` vector of the transaction, before the inputs were split
33/// into their respective categories (objects, pure, or receiving).
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub struct InputIndex(pub u16);
36
37#[derive(Debug)]
38pub struct ObjectInput {
39    pub original_input_index: InputIndex,
40    pub arg: ObjectArg,
41    pub ty: Type,
42}
43
44pub type ByteIndex = usize;
45
46#[derive(Debug)]
47pub struct PureInput {
48    pub original_input_index: InputIndex,
49    // A index into `byte` table of BCS bytes
50    pub byte_index: ByteIndex,
51    // the type that the BCS bytes will be deserialized into
52    pub ty: Type,
53    // Information about where this constraint came from
54    pub constraint: BytesConstraint,
55}
56
57#[derive(Debug)]
58pub struct ReceivingInput {
59    pub original_input_index: InputIndex,
60    pub object_ref: ObjectRef,
61    pub ty: Type,
62    // Information about where this constraint came from
63    pub constraint: BytesConstraint,
64}
65
66#[derive(Debug)]
67pub struct WithdrawalInput {
68    pub original_input_index: InputIndex,
69    /// The full type `sui::funds_accumulator::Withdrawal<T>`
70    pub ty: Type,
71    pub owner: AccountAddress,
72    /// This amount is verified to be <= the max for the type described by the `T` in `ty`
73    pub amount: U256,
74}
75
76pub type Commands = Vec<Command>;
77
78pub type ObjectArg = L::ObjectArg;
79
80pub type Type = L::Type;
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83/// Information for a given constraint for input bytes
84pub struct BytesConstraint {
85    /// The command that first added this constraint
86    pub command: u16,
87    /// The argument in that command
88    pub argument: u16,
89}
90
91pub type ResultType = Vec<Type>;
92
93pub type Command = Spanned<Command_>;
94
95#[derive(Debug)]
96pub struct Command_ {
97    /// The command
98    pub command: Command__,
99    /// The type of the return values of the command
100    pub result_type: ResultType,
101    /// Markers to drop unused results from the command. These are inferred based on any usage
102    /// of the given result `Result(i,j)` after this command. This is leveraged by the borrow
103    /// checker to remove unused references to allow potentially reuse of parent references.
104    /// The value at result `j` is unused and can be dropped if `drop_value[j]` is true.
105    pub drop_values: Vec</* drop value */ bool>,
106    /// The set of object shared object IDs that are consumed by this command.
107    /// After this command is executed, these objects must be either reshared or deleted.
108    pub consumed_shared_objects: Vec<ObjectID>,
109}
110
111#[derive(Debug)]
112pub enum Command__ {
113    MoveCall(Box<MoveCall>),
114    TransferObjects(Vec<Argument>, Argument),
115    SplitCoins(/* Coin<T> */ Type, Argument, Vec<Argument>),
116    MergeCoins(/* Coin<T> */ Type, Argument, Vec<Argument>),
117    MakeMoveVec(/* T for vector<T> */ Type, Vec<Argument>),
118    Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
119    Upgrade(
120        Vec<Vec<u8>>,
121        Vec<ObjectID>,
122        ObjectID,
123        Argument,
124        ResolvedLinkage,
125    ),
126}
127
128pub type LoadedFunctionInstantiation = L::LoadedFunctionInstantiation;
129
130pub type LoadedFunction = L::LoadedFunction;
131
132#[derive(Debug)]
133pub struct MoveCall {
134    pub function: LoadedFunction,
135    pub arguments: Vec<Argument>,
136}
137
138#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
139pub enum Location {
140    TxContext,
141    GasCoin,
142    ObjectInput(u16),
143    WithdrawalInput(u16),
144    PureInput(u16),
145    ReceivingInput(u16),
146    Result(u16, u16),
147}
148
149// Non borrowing usage of locations, moving or copying
150#[derive(Clone, Debug)]
151pub enum Usage {
152    Move(Location),
153    Copy {
154        location: Location,
155        /// Was this location borrowed at the time of copying?
156        /// Initially empty and populated by `memory_safety`
157        borrowed: OnceCell<bool>,
158    },
159}
160
161pub type Argument = Spanned<Argument_>;
162pub type Argument_ = (Argument__, Type);
163
164#[derive(Clone, Debug)]
165pub enum Argument__ {
166    /// Move or copy a value
167    Use(Usage),
168    /// Borrow a value, i.e. `&x` or `&mut x`
169    Borrow(/* mut */ bool, Location),
170    /// Read a value from a reference, i.e. `*&x`
171    Read(Usage),
172    /// Freeze a mutable reference, making an `&t` from `&mut t`
173    Freeze(Usage),
174}
175
176//**************************************************************************************************
177// impl
178//**************************************************************************************************
179
180impl Transaction {
181    pub fn types(&self) -> impl Iterator<Item = &Type> {
182        let pure_types = self.pure.iter().map(|p| &p.ty);
183        let object_types = self.objects.iter().map(|o| &o.ty);
184        let receiving_types = self.receiving.iter().map(|r| &r.ty);
185        let command_types = self.commands.iter().flat_map(command_types);
186        pure_types
187            .chain(object_types)
188            .chain(receiving_types)
189            .chain(command_types)
190    }
191}
192
193impl Usage {
194    pub fn new_move(location: Location) -> Usage {
195        Usage::Move(location)
196    }
197
198    pub fn new_copy(location: Location) -> Usage {
199        Usage::Copy {
200            location,
201            borrowed: OnceCell::new(),
202        }
203    }
204
205    pub fn location(&self) -> Location {
206        match self {
207            Usage::Move(location) => *location,
208            Usage::Copy { location, .. } => *location,
209        }
210    }
211}
212
213impl Argument__ {
214    pub fn new_move(location: Location) -> Self {
215        Self::Use(Usage::new_move(location))
216    }
217
218    pub fn new_copy(location: Location) -> Self {
219        Self::Use(Usage::new_copy(location))
220    }
221
222    pub fn location(&self) -> Location {
223        match self {
224            Self::Use(usage) | Self::Read(usage) => usage.location(),
225            Self::Borrow(_, location) => *location,
226            Self::Freeze(usage) => usage.location(),
227        }
228    }
229}
230
231impl Command__ {
232    pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
233        match self {
234            Command__::MoveCall(mc) => Box::new(mc.arguments.iter()),
235            Command__::TransferObjects(objs, addr) => {
236                Box::new(objs.iter().chain(std::iter::once(addr)))
237            }
238            Command__::SplitCoins(_, coin, amounts) => {
239                Box::new(std::iter::once(coin).chain(amounts))
240            }
241            Command__::MergeCoins(_, target, sources) => {
242                Box::new(std::iter::once(target).chain(sources))
243            }
244            Command__::MakeMoveVec(_, elems) => Box::new(elems.iter()),
245            Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
246            Command__::Upgrade(_, _, _, arg, _) => Box::new(std::iter::once(arg)),
247        }
248    }
249
250    pub fn types(&self) -> Box<dyn Iterator<Item = &Type> + '_> {
251        match self {
252            Command__::TransferObjects(args, arg) => {
253                Box::new(std::iter::once(arg).chain(args.iter()).map(argument_type))
254            }
255            Command__::SplitCoins(ty, arg, args) | Command__::MergeCoins(ty, arg, args) => {
256                Box::new(
257                    std::iter::once(arg)
258                        .chain(args.iter())
259                        .map(argument_type)
260                        .chain(std::iter::once(ty)),
261                )
262            }
263            Command__::MakeMoveVec(ty, args) => {
264                Box::new(args.iter().map(argument_type).chain(std::iter::once(ty)))
265            }
266            Command__::MoveCall(call) => Box::new(
267                call.arguments
268                    .iter()
269                    .map(argument_type)
270                    .chain(call.function.type_arguments.iter())
271                    .chain(call.function.signature.parameters.iter())
272                    .chain(call.function.signature.return_.iter()),
273            ),
274            Command__::Upgrade(_, _, _, arg, _) => {
275                Box::new(std::iter::once(arg).map(argument_type))
276            }
277            Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
278        }
279    }
280
281    pub fn arguments_len(&self) -> usize {
282        let n = match self {
283            Command__::MoveCall(mc) => mc.arguments.len(),
284            Command__::TransferObjects(objs, _) => objs.len().saturating_add(1),
285            Command__::SplitCoins(_, _, amounts) => amounts.len().saturating_add(1),
286            Command__::MergeCoins(_, _, sources) => sources.len().saturating_add(1),
287            Command__::MakeMoveVec(_, elems) => elems.len(),
288            Command__::Publish(_, _, _) => 0,
289            Command__::Upgrade(_, _, _, _, _) => 1,
290        };
291        debug_assert_eq!(self.arguments().count(), n);
292        n
293    }
294}
295
296//**************************************************************************************************
297// Standalone functions
298//**************************************************************************************************
299
300pub fn command_types(cmd: &Command) -> impl Iterator<Item = &Type> {
301    let result_types = cmd.value.result_type.iter();
302    let command_types = cmd.value.command.types();
303    result_types.chain(command_types)
304}
305
306pub fn argument_type(arg: &Argument) -> &Type {
307    &arg.value.1
308}
309
310//**************************************************************************************************
311// traits
312//**************************************************************************************************
313
314impl TryFrom<Type> for VectorSpecialization {
315    type Error = &'static str;
316
317    fn try_from(value: Type) -> Result<Self, Self::Error> {
318        Ok(match value {
319            Type::U8 => VectorSpecialization::U8,
320            Type::U16 => VectorSpecialization::U16,
321            Type::U32 => VectorSpecialization::U32,
322            Type::U64 => VectorSpecialization::U64,
323            Type::U128 => VectorSpecialization::U128,
324            Type::U256 => VectorSpecialization::U256,
325            Type::Address => VectorSpecialization::Address,
326            Type::Bool => VectorSpecialization::Bool,
327            Type::Signer | Type::Vector(_) | Type::Datatype(_) => VectorSpecialization::Container,
328            Type::Reference(_, _) => return Err("unexpected reference in vector specialization"),
329        })
330    }
331}