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