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 consumed_shared_objects: Vec<ObjectID>,
125}
126
127#[derive(Debug)]
128pub enum Command__ {
129 MoveCall(Box<MoveCall>),
130 TransferObjects(Vec<Argument>, Argument),
131 SplitCoins(Type, Argument, Vec<Argument>),
132 MergeCoins(Type, Argument, Vec<Argument>),
133 MakeMoveVec(Type, Vec<Argument>),
134 Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
135 Upgrade(
136 Vec<Vec<u8>>,
137 Vec<ObjectID>,
138 ObjectID,
139 Argument,
140 ResolvedLinkage,
141 ),
142}
143
144pub type LoadedFunctionInstantiation = L::LoadedFunctionInstantiation;
145
146pub type LoadedFunction = L::LoadedFunction;
147
148#[derive(Debug)]
149pub struct MoveCall {
150 pub function: LoadedFunction,
151 pub arguments: Vec<Argument>,
152}
153
154#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
155pub enum Location {
156 TxContext,
157 GasCoin,
158 ObjectInput(u16),
159 WithdrawalInput(u16),
160 PureInput(u16),
161 ReceivingInput(u16),
162 Result(u16, u16),
163}
164
165#[derive(Clone, Debug)]
167pub enum Usage {
168 Move(Location),
169 Copy {
170 location: Location,
171 borrowed: OnceCell<bool>,
174 },
175}
176
177pub type Argument = Spanned<Argument_>;
178pub type Argument_ = (Argument__, Type);
179
180#[derive(Clone, Debug)]
181pub enum Argument__ {
182 Use(Usage),
184 Borrow(bool, Location),
186 Read(Usage),
188 Freeze(Usage),
190}
191
192impl Transaction {
197 pub fn types(&self) -> impl Iterator<Item = &Type> {
198 let pure_types = self.pure.iter().map(|p| &p.ty);
199 let object_types = self.objects.iter().map(|o| &o.ty);
200 let receiving_types = self.receiving.iter().map(|r| &r.ty);
201 let command_types = self.commands.iter().flat_map(command_types);
202 pure_types
203 .chain(object_types)
204 .chain(receiving_types)
205 .chain(command_types)
206 }
207}
208
209impl Usage {
210 pub fn new_move(location: Location) -> Usage {
211 Usage::Move(location)
212 }
213
214 pub fn new_copy(location: Location) -> Usage {
215 Usage::Copy {
216 location,
217 borrowed: OnceCell::new(),
218 }
219 }
220
221 pub fn location(&self) -> Location {
222 match self {
223 Usage::Move(location) => *location,
224 Usage::Copy { location, .. } => *location,
225 }
226 }
227}
228
229impl Argument__ {
230 pub fn new_move(location: Location) -> Self {
231 Self::Use(Usage::new_move(location))
232 }
233
234 pub fn new_copy(location: Location) -> Self {
235 Self::Use(Usage::new_copy(location))
236 }
237
238 pub fn location(&self) -> Location {
239 match self {
240 Self::Use(usage) | Self::Read(usage) => usage.location(),
241 Self::Borrow(_, location) => *location,
242 Self::Freeze(usage) => usage.location(),
243 }
244 }
245}
246
247impl Command__ {
248 pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
249 match self {
250 Command__::MoveCall(mc) => Box::new(mc.arguments.iter()),
251 Command__::TransferObjects(objs, addr) => {
252 Box::new(objs.iter().chain(std::iter::once(addr)))
253 }
254 Command__::SplitCoins(_, coin, amounts) => {
255 Box::new(std::iter::once(coin).chain(amounts))
256 }
257 Command__::MergeCoins(_, target, sources) => {
258 Box::new(std::iter::once(target).chain(sources))
259 }
260 Command__::MakeMoveVec(_, elems) => Box::new(elems.iter()),
261 Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
262 Command__::Upgrade(_, _, _, arg, _) => Box::new(std::iter::once(arg)),
263 }
264 }
265
266 pub fn types(&self) -> Box<dyn Iterator<Item = &Type> + '_> {
267 match self {
268 Command__::TransferObjects(args, arg) => {
269 Box::new(std::iter::once(arg).chain(args.iter()).map(argument_type))
270 }
271 Command__::SplitCoins(ty, arg, args) | Command__::MergeCoins(ty, arg, args) => {
272 Box::new(
273 std::iter::once(arg)
274 .chain(args.iter())
275 .map(argument_type)
276 .chain(std::iter::once(ty)),
277 )
278 }
279 Command__::MakeMoveVec(ty, args) => {
280 Box::new(args.iter().map(argument_type).chain(std::iter::once(ty)))
281 }
282 Command__::MoveCall(call) => Box::new(
283 call.arguments
284 .iter()
285 .map(argument_type)
286 .chain(call.function.type_arguments.iter())
287 .chain(call.function.signature.parameters.iter())
288 .chain(call.function.signature.return_.iter()),
289 ),
290 Command__::Upgrade(_, _, _, arg, _) => {
291 Box::new(std::iter::once(arg).map(argument_type))
292 }
293 Command__::Publish(_, _, _) => Box::new(std::iter::empty()),
294 }
295 }
296
297 pub fn arguments_len(&self) -> usize {
298 let n = match self {
299 Command__::MoveCall(mc) => mc.arguments.len(),
300 Command__::TransferObjects(objs, _) => objs.len().saturating_add(1),
301 Command__::SplitCoins(_, _, amounts) => amounts.len().saturating_add(1),
302 Command__::MergeCoins(_, _, sources) => sources.len().saturating_add(1),
303 Command__::MakeMoveVec(_, elems) => elems.len(),
304 Command__::Publish(_, _, _) => 0,
305 Command__::Upgrade(_, _, _, _, _) => 1,
306 };
307 debug_assert_eq!(self.arguments().count(), n);
308 n
309 }
310}
311
312pub fn command_types(cmd: &Command) -> impl Iterator<Item = &Type> {
317 let result_types = cmd.value.result_type.iter();
318 let command_types = cmd.value.command.types();
319 result_types.chain(command_types)
320}
321
322pub fn argument_type(arg: &Argument) -> &Type {
323 &arg.value.1
324}
325
326impl TryFrom<Type> for VectorSpecialization {
331 type Error = &'static str;
332
333 fn try_from(value: Type) -> Result<Self, Self::Error> {
334 Ok(match value {
335 Type::U8 => VectorSpecialization::U8,
336 Type::U16 => VectorSpecialization::U16,
337 Type::U32 => VectorSpecialization::U32,
338 Type::U64 => VectorSpecialization::U64,
339 Type::U128 => VectorSpecialization::U128,
340 Type::U256 => VectorSpecialization::U256,
341 Type::Address => VectorSpecialization::Address,
342 Type::Bool => VectorSpecialization::Bool,
343 Type::Signer | Type::Vector(_) | Type::Datatype(_) => VectorSpecialization::Container,
344 Type::Reference(_, _) => return Err("unexpected reference in vector specialization"),
345 })
346 }
347}