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