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