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