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