1use crate::{
5 gas_charger::GasPayment,
6 static_programmable_transactions::linkage::resolved_linkage::{
7 ExecutableLinkage, ResolvedLinkage,
8 },
9};
10use indexmap::IndexSet;
11use move_binary_format::file_format::{
12 AbilitySet, CodeOffset, FunctionDefinitionIndex, Visibility,
13};
14use move_core_types::{
15 account_address::AccountAddress,
16 identifier::IdentStr,
17 language_storage::{ModuleId, StructTag},
18 u256::U256,
19};
20use std::rc::Rc;
21use sui_types::{
22 Identifier, TypeTag,
23 base_types::{ObjectID, ObjectRef, RESOLVED_TX_CONTEXT, SequenceNumber, TxContextKind},
24};
25
26#[derive(Debug)]
31pub struct Transaction {
32 pub gas_payment: Option<GasPayment>,
33 pub inputs: Inputs,
34 pub original_command_len: usize,
37 pub commands: Commands,
38}
39
40pub type Inputs = Vec<(InputArg, InputType)>;
41
42pub type Commands = Vec<Command>;
43
44#[derive(Debug)]
45#[cfg_attr(debug_assertions, derive(Clone))]
46pub enum InputArg {
47 Pure(Vec<u8>),
48 Receiving(ObjectRef),
49 Object(ObjectArg),
50 FundsWithdrawal(FundsWithdrawalArg),
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum SharedObjectKind {
55 Legacy,
56 Party,
57}
58
59#[derive(Debug)]
60#[cfg_attr(debug_assertions, derive(Clone))]
61pub enum ObjectArg {
62 ImmObject(ObjectRef),
63 OwnedObject(ObjectRef),
64 SharedObject {
65 id: ObjectID,
66 initial_shared_version: SequenceNumber,
67 mutability: ObjectMutability,
68 kind: SharedObjectKind,
69 },
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum ObjectMutability {
74 Mutable,
75 Immutable,
76 NonExclusiveWrite,
77}
78
79#[derive(Debug)]
80#[cfg_attr(debug_assertions, derive(Clone))]
81pub struct FundsWithdrawalArg {
82 pub from_compatibility_object: bool,
84 pub ty: Type,
86 pub owner: AccountAddress,
87 pub amount: U256,
89}
90
91#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
92pub enum Type {
93 Bool,
94 U8,
95 U16,
96 U32,
97 U64,
98 U128,
99 U256,
100 Address,
101 Signer,
102 Vector(Rc<Vector>),
103 Datatype(Rc<Datatype>),
104 Reference(bool, Rc<Type>),
105}
106
107#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct Vector {
109 pub abilities: AbilitySet,
110 pub element_type: Type,
111}
112
113#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct Datatype {
115 pub abilities: AbilitySet,
116 pub module: ModuleId,
117 pub name: Identifier,
118 pub type_arguments: Vec<Type>,
119}
120
121#[derive(Debug, Clone)]
122pub enum InputType {
123 Bytes,
124 Fixed(Type),
125}
126
127#[derive(Debug)]
128pub enum Command {
129 MoveCall(Box<MoveCall>),
130 TransferObjects(Vec<Argument>, Argument),
131 SplitCoins(Argument, Vec<Argument>),
132 MergeCoins(Argument, Vec<Argument>),
133 MakeMoveVec(Option<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
144#[derive(Debug)]
145pub struct LoadedFunctionInstantiation {
146 pub parameters: Vec<Type>,
147 pub return_: Vec<Type>,
148}
149
150#[derive(Debug)]
151pub struct LoadedFunction {
152 pub version_mid: ModuleId,
153 pub original_mid: ModuleId,
154 pub name: Identifier,
155 pub type_arguments: Vec<Type>,
156 pub signature: LoadedFunctionInstantiation,
157 pub linkage: ExecutableLinkage,
158 pub instruction_length: CodeOffset,
159 pub definition_index: FunctionDefinitionIndex,
160 pub visibility: Visibility,
161 pub is_entry: bool,
162 pub is_native: bool,
163}
164
165#[derive(Debug)]
166pub struct MoveCall {
167 pub function: LoadedFunction,
168 pub arguments: Vec<Argument>,
169}
170
171pub use sui_types::transaction::Argument;
172
173impl ObjectArg {
178 pub fn id(&self) -> ObjectID {
179 match self {
180 ObjectArg::ImmObject(oref) | ObjectArg::OwnedObject(oref) => oref.0,
181 ObjectArg::SharedObject { id, .. } => *id,
182 }
183 }
184
185 pub fn mutability(&self) -> ObjectMutability {
186 match self {
187 ObjectArg::ImmObject(_) => ObjectMutability::Immutable,
188 ObjectArg::OwnedObject(_) => ObjectMutability::Mutable,
189 ObjectArg::SharedObject { mutability, .. } => *mutability,
190 }
191 }
192}
193
194impl Type {
195 pub fn abilities(&self) -> AbilitySet {
196 match self {
197 Type::Bool
198 | Type::U8
199 | Type::U16
200 | Type::U32
201 | Type::U64
202 | Type::U128
203 | Type::U256
204 | Type::Address => AbilitySet::PRIMITIVES,
205 Type::Signer => AbilitySet::SIGNER,
206 Type::Reference(_, _) => AbilitySet::REFERENCES,
207 Type::Vector(v) => v.abilities,
208 Type::Datatype(dt) => dt.abilities,
209 }
210 }
211
212 pub fn is_tx_context(&self) -> TxContextKind {
213 let (is_mut, inner) = match self {
214 Type::Reference(is_mut, inner) => (*is_mut, inner),
215 _ => return TxContextKind::None,
216 };
217 let Type::Datatype(dt) = &**inner else {
218 return TxContextKind::None;
219 };
220 if dt.qualified_ident() == RESOLVED_TX_CONTEXT {
221 if is_mut {
222 TxContextKind::Mutable
223 } else {
224 TxContextKind::Immutable
225 }
226 } else {
227 TxContextKind::None
228 }
229 }
230 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
231 match self {
232 Type::Bool
233 | Type::U8
234 | Type::U16
235 | Type::U32
236 | Type::U64
237 | Type::U128
238 | Type::U256
239 | Type::Address
240 | Type::Signer => IndexSet::new(),
241 Type::Vector(v) => v.element_type.all_addresses(),
242 Type::Reference(_, inner) => inner.all_addresses(),
243 Type::Datatype(dt) => dt.all_addresses(),
244 }
245 }
246
247 pub fn node_count(&self) -> u64 {
248 use Type::*;
249 let mut total = 0u64;
250 let mut stack = vec![self];
251
252 while let Some(ty) = stack.pop() {
253 total = total.saturating_add(1);
254 match ty {
255 Bool | U8 | U16 | U32 | U64 | U128 | U256 | Address | Signer => {}
256 Vector(v) => stack.push(&v.element_type),
257 Reference(_, inner) => stack.push(inner),
258 Datatype(dt) => {
259 stack.extend(&dt.type_arguments);
260 }
261 }
262 }
263
264 total
265 }
266
267 pub fn is_reference(&self) -> bool {
268 match self {
269 Type::Bool
270 | Type::U8
271 | Type::U16
272 | Type::U32
273 | Type::U64
274 | Type::U128
275 | Type::U256
276 | Type::Address
277 | Type::Signer
278 | Type::Vector(_)
279 | Type::Datatype(_) => false,
280 Type::Reference(_, _) => true,
281 }
282 }
283}
284
285impl Datatype {
286 pub fn qualified_ident(&self) -> (&AccountAddress, &IdentStr, &IdentStr) {
287 (
288 self.module.address(),
289 self.module.name(),
290 self.name.as_ident_str(),
291 )
292 }
293
294 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
295 let mut addresses = IndexSet::new();
296 addresses.insert(*self.module.address());
297 for arg in &self.type_arguments {
298 addresses.extend(arg.all_addresses());
299 }
300 addresses
301 }
302}
303
304impl Command {
305 pub fn arguments_mut(&mut self) -> Box<dyn Iterator<Item = &mut Argument> + '_> {
306 match self {
307 Command::MoveCall(mc) => Box::new(mc.arguments.iter_mut()),
308 Command::TransferObjects(objs, recipient) => {
309 Box::new(objs.iter_mut().chain(std::iter::once(recipient)))
310 }
311 Command::SplitCoins(coin, amounts) => {
312 Box::new(std::iter::once(coin).chain(amounts.iter_mut()))
313 }
314 Command::MergeCoins(coin, coins) => {
315 Box::new(std::iter::once(coin).chain(coins.iter_mut()))
316 }
317 Command::MakeMoveVec(_, elements) => Box::new(elements.iter_mut()),
318 Command::Publish(_, _, _) => Box::new(std::iter::empty()),
319 Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
320 }
321 }
322
323 pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
324 match self {
325 Command::MoveCall(mc) => Box::new(mc.arguments.iter()),
326 Command::TransferObjects(objs, recipient) => {
327 Box::new(objs.iter().chain(std::iter::once(recipient)))
328 }
329 Command::SplitCoins(coin, amounts) => {
330 Box::new(std::iter::once(coin).chain(amounts.iter()))
331 }
332 Command::MergeCoins(coin, coins) => Box::new(std::iter::once(coin).chain(coins.iter())),
333 Command::MakeMoveVec(_, elements) => Box::new(elements.iter()),
334 Command::Publish(_, _, _) => Box::new(std::iter::empty()),
335 Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
336 }
337 }
338}
339
340impl TryFrom<Type> for TypeTag {
345 type Error = &'static str;
346 fn try_from(ty: Type) -> Result<Self, Self::Error> {
347 Ok(match ty {
348 Type::Bool => TypeTag::Bool,
349 Type::U8 => TypeTag::U8,
350 Type::U16 => TypeTag::U16,
351 Type::U32 => TypeTag::U32,
352 Type::U64 => TypeTag::U64,
353 Type::U128 => TypeTag::U128,
354 Type::U256 => TypeTag::U256,
355 Type::Address => TypeTag::Address,
356 Type::Signer => TypeTag::Signer,
357 Type::Vector(inner) => {
358 let Vector { element_type, .. } = &*inner;
359 TypeTag::Vector(Box::new(element_type.clone().try_into()?))
360 }
361 Type::Datatype(dt) => {
362 let dt: &Datatype = &dt;
363 TypeTag::Struct(Box::new(dt.try_into()?))
364 }
365 Type::Reference(_, _) => return Err("unexpected reference type"),
366 })
367 }
368}
369
370impl TryFrom<&Datatype> for StructTag {
371 type Error = &'static str;
372
373 fn try_from(dt: &Datatype) -> Result<Self, Self::Error> {
374 let Datatype {
375 module,
376 name,
377 type_arguments,
378 ..
379 } = dt;
380 Ok(StructTag {
381 address: *module.address(),
382 module: module.name().to_owned(),
383 name: name.to_owned(),
384 type_params: type_arguments
385 .iter()
386 .map(|t| t.clone().try_into())
387 .collect::<Result<Vec<TypeTag>, _>>()?,
388 })
389 }
390}
391
392#[test]
397fn enum_size() {
398 assert_eq!(std::mem::size_of::<Type>(), 16);
399}