1use 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#[derive(Debug)]
18pub struct Transaction {
19 pub gas_coin: Option<ObjectID>,
20 pub bytes: IndexSet<Vec<u8>>,
22 pub objects: Vec<ObjectInput>,
24 pub withdrawals: Vec<WithdrawalInput>,
26 pub pure: Vec<PureInput>,
28 pub receiving: Vec<ReceivingInput>,
30 pub withdrawal_compatibility_conversions: IndexMap<Location, WithdrawalCompatibilityConversion>,
31 pub commands: Commands,
32}
33
34#[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 pub byte_index: ByteIndex,
53 pub ty: Type,
55 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 pub constraint: BytesConstraint,
66}
67
68#[derive(Debug)]
69pub struct WithdrawalInput {
70 pub original_input_index: InputIndex,
71 pub ty: Type,
73 pub owner: AccountAddress,
74 pub amount: U256,
76}
77
78#[derive(Debug, Clone, Copy)]
79pub struct WithdrawalCompatibilityConversion {
80 pub owner: Location,
82 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)]
93pub struct BytesConstraint {
95 pub command: u16,
97 pub argument: u16,
99}
100
101pub type ResultType = Vec<Type>;
102
103pub type Command = Spanned<Command_>;
104
105#[derive(Debug)]
106pub struct Command_ {
107 pub command: Command__,
109 pub result_type: ResultType,
111 pub drop_values: Vec<bool>,
116 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(Type, Argument, Vec<Argument>),
126 MergeCoins(Type, Argument, Vec<Argument>),
127 MakeMoveVec(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#[derive(Clone, Debug)]
161pub enum Usage {
162 Move(Location),
163 Copy {
164 location: Location,
165 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 Use(Usage),
178 Borrow(bool, Location),
180 Read(Usage),
182 Freeze(Usage),
184}
185
186impl 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
306pub 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
320impl 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}