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