1use 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#[derive(Debug)]
21pub struct Transaction {
22 pub gas_payment: Option<GasPayment>,
23 pub bytes: IndexSet<Vec<u8>>,
25 pub objects: Vec<ObjectInput>,
27 pub withdrawals: Vec<WithdrawalInput>,
29 pub pure: Vec<PureInput>,
31 pub receiving: Vec<ReceivingInput>,
33 pub withdrawal_compatibility_conversions: IndexMap<Location, WithdrawalCompatibilityConversion>,
34 pub commands: Commands,
35}
36
37#[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 pub byte_index: ByteIndex,
56 pub ty: Type,
58 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 pub constraint: BytesConstraint,
69}
70
71#[derive(Debug)]
72pub struct WithdrawalInput {
73 pub original_input_index: InputIndex,
74 pub ty: Type,
76 pub owner: AccountAddress,
77 pub amount: U256,
79}
80
81#[derive(Debug, Clone, Copy)]
82pub struct WithdrawalCompatibilityConversion {
83 pub owner: Location,
85 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)]
96pub struct BytesConstraint {
98 pub command: u16,
100 pub argument: u16,
102}
103
104pub type ResultType = Vec<Type>;
105
106pub type Command = Spanned<Command_>;
107
108#[derive(Debug)]
109pub struct Command_ {
110 pub command: Command__,
112 pub result_type: ResultType,
114 pub drop_values: Vec<bool>,
119 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(Type, Argument, Vec<Argument>),
129 MergeCoins(Type, Argument, Vec<Argument>),
130 MakeMoveVec(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#[derive(Clone, Debug)]
164pub enum Usage {
165 Move(Location),
166 Copy {
167 location: Location,
168 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 Use(Usage),
181 Borrow(bool, Location),
183 Read(Usage),
185 Freeze(Usage),
187}
188
189impl 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
309pub 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
323impl 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}