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    /// The set of object shared object IDs that are consumed by this command.
123    /// After this command is executed, these objects must be either reshared or deleted.
124    pub consumed_shared_objects: Vec<ObjectID>,
125}
126
127#[derive(Debug)]
128pub enum Command__ {
129    MoveCall(Box<MoveCall>),
130    TransferObjects(Vec<Argument>, Argument),
131    SplitCoins(/* Coin<T> */ Type, Argument, Vec<Argument>),
132    MergeCoins(/* Coin<T> */ Type, Argument, Vec<Argument>),
133    MakeMoveVec(/* T for vector<T> */ Type, Vec<Argument>),
134    Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
135    Upgrade(
136        Vec<Vec<u8>>,
137        Vec<ObjectID>,
138        ObjectID,
139        Argument,
140        ResolvedLinkage,
141    ),
142}
143
144pub type LoadedFunctionInstantiation = L::LoadedFunctionInstantiation;
145
146pub type LoadedFunction = L::LoadedFunction;
147
148#[derive(Debug)]
149pub struct MoveCall {
150    pub function: LoadedFunction,
151    pub arguments: Vec<Argument>,
152}
153
154#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
155pub enum Location {
156    TxContext,
157    GasCoin,
158    ObjectInput(u16),
159    WithdrawalInput(u16),
160    PureInput(u16),
161    ReceivingInput(u16),
162    Result(u16, u16),
163}
164
165// Non borrowing usage of locations, moving or copying
166#[derive(Clone, Debug)]
167pub enum Usage {
168    Move(Location),
169    Copy {
170        location: Location,
171        /// Was this location borrowed at the time of copying?
172        /// Initially empty and populated by `memory_safety`
173        borrowed: OnceCell<bool>,
174    },
175}
176
177pub type Argument = Spanned<Argument_>;
178pub type Argument_ = (Argument__, Type);
179
180#[derive(Clone, Debug)]
181pub enum Argument__ {
182    /// Move or copy a value
183    Use(Usage),
184    /// Borrow a value, i.e. `&x` or `&mut x`
185    Borrow(/* mut */ bool, Location),
186    /// Read a value from a reference, i.e. `*&x`
187    Read(Usage),
188    /// Freeze a mutable reference, making an `&t` from `&mut t`
189    Freeze(Usage),
190}
191
192//**************************************************************************************************
193// impl
194//**************************************************************************************************
195
196impl Transaction {
197    pub fn types(&self) -> impl Iterator<Item = &Type> {
198        let pure_types = self.pure.iter().map(|p| &p.ty);
199        let object_types = self.objects.iter().map(|o| &o.ty);
200        let receiving_types = self.receiving.iter().map(|r| &r.ty);
201        let command_types = self.commands.iter().flat_map(command_types);
202        pure_types
203            .chain(object_types)
204            .chain(receiving_types)
205            .chain(command_types)
206    }
207}
208
209impl Usage {
210    pub fn new_move(location: Location) -> Usage {
211        Usage::Move(location)
212    }
213
214    pub fn new_copy(location: Location) -> Usage {
215        Usage::Copy {
216            location,
217            borrowed: OnceCell::new(),
218        }
219    }
220
221    pub fn location(&self) -> Location {
222        match self {
223            Usage::Move(location) => *location,
224            Usage::Copy { location, .. } => *location,
225        }
226    }
227}
228
229impl Argument__ {
230    pub fn new_move(location: Location) -> Self {
231        Self::Use(Usage::new_move(location))
232    }
233
234    pub fn new_copy(location: Location) -> Self {
235        Self::Use(Usage::new_copy(location))
236    }
237
238    pub fn location(&self) -> Location {
239        match self {
240            Self::Use(usage) | Self::Read(usage) => usage.location(),
241            Self::Borrow(_, location) => *location,
242            Self::Freeze(usage) => usage.location(),
243        }
244    }
245}
246
247impl Command__ {
248    pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
249        match self {
250            Command__::MoveCall(mc) => Box::new(mc.arguments.iter()),
251            Command__::TransferObjects(objs, addr) => {
252                Box::new(objs.iter().chain(std::iter::once(addr)))
253            }
254            Command__::SplitCoins(_, coin, amounts) => {
255                Box::new(std::iter::once(coin).chain(amounts))
256            }
257            Command__::MergeCoins(_, target, sources) => {
258                Box::new(std::iter::once(target).chain(sources))
259            }
260            Command__::MakeMoveVec(_, elems) => Box::new(elems.iter()),
261            Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
262            Command__::Upgrade(_, _, _, arg, _) => Box::new(std::iter::once(arg)),
263        }
264    }
265
266    pub fn types(&self) -> Box<dyn Iterator<Item = &Type> + '_> {
267        match self {
268            Command__::TransferObjects(args, arg) => {
269                Box::new(std::iter::once(arg).chain(args.iter()).map(argument_type))
270            }
271            Command__::SplitCoins(ty, arg, args) | Command__::MergeCoins(ty, arg, args) => {
272                Box::new(
273                    std::iter::once(arg)
274                        .chain(args.iter())
275                        .map(argument_type)
276                        .chain(std::iter::once(ty)),
277                )
278            }
279            Command__::MakeMoveVec(ty, args) => {
280                Box::new(args.iter().map(argument_type).chain(std::iter::once(ty)))
281            }
282            Command__::MoveCall(call) => Box::new(
283                call.arguments
284                    .iter()
285                    .map(argument_type)
286                    .chain(call.function.type_arguments.iter())
287                    .chain(call.function.signature.parameters.iter())
288                    .chain(call.function.signature.return_.iter()),
289            ),
290            Command__::Upgrade(_, _, _, arg, _) => {
291                Box::new(std::iter::once(arg).map(argument_type))
292            }
293            Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
294        }
295    }
296
297    pub fn arguments_len(&self) -> usize {
298        let n = match self {
299            Command__::MoveCall(mc) => mc.arguments.len(),
300            Command__::TransferObjects(objs, _) => objs.len().saturating_add(1),
301            Command__::SplitCoins(_, _, amounts) => amounts.len().saturating_add(1),
302            Command__::MergeCoins(_, _, sources) => sources.len().saturating_add(1),
303            Command__::MakeMoveVec(_, elems) => elems.len(),
304            Command__::Publish(_, _, _) => 0,
305            Command__::Upgrade(_, _, _, _, _) => 1,
306        };
307        debug_assert_eq!(self.arguments().count(), n);
308        n
309    }
310}
311
312//**************************************************************************************************
313// Standalone functions
314//**************************************************************************************************
315
316pub fn command_types(cmd: &Command) -> impl Iterator<Item = &Type> {
317    let result_types = cmd.value.result_type.iter();
318    let command_types = cmd.value.command.types();
319    result_types.chain(command_types)
320}
321
322pub fn argument_type(arg: &Argument) -> &Type {
323    &arg.value.1
324}
325
326//**************************************************************************************************
327// traits
328//**************************************************************************************************
329
330impl TryFrom<Type> for VectorSpecialization {
331    type Error = &'static str;
332
333    fn try_from(value: Type) -> Result<Self, Self::Error> {
334        Ok(match value {
335            Type::U8 => VectorSpecialization::U8,
336            Type::U16 => VectorSpecialization::U16,
337            Type::U32 => VectorSpecialization::U32,
338            Type::U64 => VectorSpecialization::U64,
339            Type::U128 => VectorSpecialization::U128,
340            Type::U256 => VectorSpecialization::U256,
341            Type::Address => VectorSpecialization::Address,
342            Type::Bool => VectorSpecialization::Bool,
343            Type::Signer | Type::Vector(_) | Type::Datatype(_) => VectorSpecialization::Container,
344            Type::Reference(_, _) => return Err("unexpected reference in vector specialization"),
345        })
346    }
347}