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