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 original_command_len: usize,
37 pub commands: Commands,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub struct InputIndex(pub u16);
44
45#[derive(Debug)]
46pub struct ObjectInput {
47 pub original_input_index: InputIndex,
48 pub arg: ObjectArg,
49 pub ty: Type,
50}
51
52pub type ByteIndex = usize;
53
54#[derive(Debug)]
55pub struct PureInput {
56 pub original_input_index: InputIndex,
57 pub byte_index: ByteIndex,
59 pub ty: Type,
61 pub constraint: BytesConstraint,
63}
64
65#[derive(Debug)]
66pub struct ReceivingInput {
67 pub original_input_index: InputIndex,
68 pub object_ref: ObjectRef,
69 pub ty: Type,
70 pub constraint: BytesConstraint,
72}
73
74#[derive(Debug)]
75pub struct WithdrawalInput {
76 pub original_input_index: InputIndex,
77 pub ty: Type,
79 pub owner: AccountAddress,
80 pub amount: U256,
82}
83
84#[derive(Debug, Clone, Copy)]
85pub struct WithdrawalCompatibilityConversion {
86 pub owner: Location,
88 pub conversion_result: u16,
90}
91
92pub type Commands = Vec<Command>;
93
94pub type ObjectArg = L::ObjectArg;
95
96pub type Type = L::Type;
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub struct BytesConstraint {
101 pub command: u16,
103 pub argument: u16,
105}
106
107pub type ResultType = Vec<Type>;
108
109pub type Command = Spanned<Command_>;
110
111#[derive(Debug)]
112pub struct Command_ {
113 pub command: Command__,
115 pub result_type: ResultType,
117 pub drop_values: Vec<bool>,
122 pub incurs_post_execution_checks: bool,
126}
127
128#[derive(Debug)]
129pub enum Command__ {
130 MoveCall(Box<MoveCall>),
131 TransferObjects(Vec<Argument>, Argument),
132 SplitCoins(Type, Argument, Vec<Argument>),
133 MergeCoins(Type, Argument, Vec<Argument>),
134 MakeMoveVec(Type, Vec<Argument>),
135 Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
136 Upgrade(
137 Vec<Vec<u8>>,
138 Vec<ObjectID>,
139 ObjectID,
140 Argument,
141 ResolvedLinkage,
142 ),
143}
144
145pub type LoadedFunctionInstantiation = L::LoadedFunctionInstantiation;
146
147pub type LoadedFunction = L::LoadedFunction;
148
149#[derive(Debug)]
150pub struct MoveCall {
151 pub function: LoadedFunction,
152 pub arguments: Vec<Argument>,
153}
154
155#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
156pub enum Location {
157 TxContext,
158 GasCoin,
159 ObjectInput(u16),
160 WithdrawalInput(u16),
161 PureInput(u16),
162 ReceivingInput(u16),
163 Result(u16, u16),
164}
165
166#[derive(Clone, Debug)]
168pub enum Usage {
169 Move(Location),
170 Copy {
171 location: Location,
172 borrowed: OnceCell<bool>,
175 },
176}
177
178pub type Argument = Spanned<Argument_>;
179pub type Argument_ = (Argument__, Type);
180
181#[derive(Clone, Debug)]
182pub enum Argument__ {
183 Use(Usage),
185 Borrow(bool, Location),
187 Read(Usage),
189 Freeze(Usage),
191}
192
193impl Transaction {
198 pub fn types(&self) -> impl Iterator<Item = &Type> {
199 let pure_types = self.pure.iter().map(|p| &p.ty);
200 let object_types = self.objects.iter().map(|o| &o.ty);
201 let receiving_types = self.receiving.iter().map(|r| &r.ty);
202 let command_types = self.commands.iter().flat_map(command_types);
203 pure_types
204 .chain(object_types)
205 .chain(receiving_types)
206 .chain(command_types)
207 }
208}
209
210impl Usage {
211 pub fn new_move(location: Location) -> Usage {
212 Usage::Move(location)
213 }
214
215 pub fn new_copy(location: Location) -> Usage {
216 Usage::Copy {
217 location,
218 borrowed: OnceCell::new(),
219 }
220 }
221
222 pub fn location(&self) -> Location {
223 match self {
224 Usage::Move(location) => *location,
225 Usage::Copy { location, .. } => *location,
226 }
227 }
228}
229
230impl Argument__ {
231 pub fn new_move(location: Location) -> Self {
232 Self::Use(Usage::new_move(location))
233 }
234
235 pub fn new_copy(location: Location) -> Self {
236 Self::Use(Usage::new_copy(location))
237 }
238
239 pub fn location(&self) -> Location {
240 match self {
241 Self::Use(usage) | Self::Read(usage) => usage.location(),
242 Self::Borrow(_, location) => *location,
243 Self::Freeze(usage) => usage.location(),
244 }
245 }
246}
247
248impl Command__ {
249 pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
250 match self {
251 Command__::MoveCall(mc) => Box::new(mc.arguments.iter()),
252 Command__::TransferObjects(objs, addr) => {
253 Box::new(objs.iter().chain(std::iter::once(addr)))
254 }
255 Command__::SplitCoins(_, coin, amounts) => {
256 Box::new(std::iter::once(coin).chain(amounts))
257 }
258 Command__::MergeCoins(_, target, sources) => {
259 Box::new(std::iter::once(target).chain(sources))
260 }
261 Command__::MakeMoveVec(_, elems) => Box::new(elems.iter()),
262 Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
263 Command__::Upgrade(_, _, _, arg, _) => Box::new(std::iter::once(arg)),
264 }
265 }
266
267 pub fn types(&self) -> Box<dyn Iterator<Item = &Type> + '_> {
268 match self {
269 Command__::TransferObjects(args, arg) => {
270 Box::new(std::iter::once(arg).chain(args.iter()).map(argument_type))
271 }
272 Command__::SplitCoins(ty, arg, args) | Command__::MergeCoins(ty, arg, args) => {
273 Box::new(
274 std::iter::once(arg)
275 .chain(args.iter())
276 .map(argument_type)
277 .chain(std::iter::once(ty)),
278 )
279 }
280 Command__::MakeMoveVec(ty, args) => {
281 Box::new(args.iter().map(argument_type).chain(std::iter::once(ty)))
282 }
283 Command__::MoveCall(call) => Box::new(
284 call.arguments
285 .iter()
286 .map(argument_type)
287 .chain(call.function.type_arguments.iter())
288 .chain(call.function.signature.parameters.iter())
289 .chain(call.function.signature.return_.iter()),
290 ),
291 Command__::Upgrade(_, _, _, arg, _) => {
292 Box::new(std::iter::once(arg).map(argument_type))
293 }
294 Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
295 }
296 }
297
298 pub fn arguments_len(&self) -> usize {
299 let n = match self {
300 Command__::MoveCall(mc) => mc.arguments.len(),
301 Command__::TransferObjects(objs, _) => objs.len().saturating_add(1),
302 Command__::SplitCoins(_, _, amounts) => amounts.len().saturating_add(1),
303 Command__::MergeCoins(_, _, sources) => sources.len().saturating_add(1),
304 Command__::MakeMoveVec(_, elems) => elems.len(),
305 Command__::Publish(_, _, _) => 0,
306 Command__::Upgrade(_, _, _, _, _) => 1,
307 };
308 debug_assert_eq!(self.arguments().count(), n);
309 n
310 }
311}
312
313pub fn command_types(cmd: &Command) -> impl Iterator<Item = &Type> {
318 let result_types = cmd.value.result_type.iter();
319 let command_types = cmd.value.command.types();
320 result_types.chain(command_types)
321}
322
323pub fn argument_type(arg: &Argument) -> &Type {
324 &arg.value.1
325}
326
327impl TryFrom<Type> for VectorSpecialization {
332 type Error = &'static str;
333
334 fn try_from(value: Type) -> Result<Self, Self::Error> {
335 Ok(match value {
336 Type::U8 => VectorSpecialization::U8,
337 Type::U16 => VectorSpecialization::U16,
338 Type::U32 => VectorSpecialization::U32,
339 Type::U64 => VectorSpecialization::U64,
340 Type::U128 => VectorSpecialization::U128,
341 Type::U256 => VectorSpecialization::U256,
342 Type::Address => VectorSpecialization::Address,
343 Type::Bool => VectorSpecialization::Bool,
344 Type::Signer | Type::Vector(_) | Type::Datatype(_) => VectorSpecialization::Container,
345 Type::Reference(_, _) => return Err("unexpected reference in vector specialization"),
346 })
347 }
348}