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::{
12 CompiledModule,
13 file_format::{AbilitySet, CodeOffset, FunctionDefinitionIndex, Visibility},
14};
15use move_core_types::{
16 account_address::AccountAddress,
17 identifier::IdentStr,
18 language_storage::{ModuleId, StructTag},
19 u256::U256,
20};
21use std::rc::Rc;
22use sui_types::{
23 Identifier, TypeTag,
24 base_types::{ObjectID, ObjectRef, RESOLVED_TX_CONTEXT, SequenceNumber, TxContextKind},
25 object::ObjectPermissions,
26};
27
28#[derive(Debug)]
33pub struct Transaction {
34 pub gas_payment: Option<GasPayment>,
35 pub inputs: Inputs,
36 pub original_command_len: usize,
39 pub commands: Commands,
40}
41
42pub type Inputs = Vec<(InputArg, InputType)>;
43
44pub type Commands = Vec<Command>;
45
46#[derive(Debug)]
47#[cfg_attr(debug_assertions, derive(Clone))]
48pub enum InputArg {
49 Pure(Vec<u8>),
50 Receiving(ObjectRef),
51 Object(ObjectArg),
52 FundsWithdrawal(FundsWithdrawalArg),
53}
54
55#[derive(Debug)]
56#[cfg_attr(debug_assertions, derive(Clone))]
57pub enum ObjectArgKind {
58 ImmObject(ObjectRef),
59 OwnedObject(ObjectRef),
60 ConsensusObject {
61 id: ObjectID,
62 initial_shared_version: SequenceNumber,
63 },
64}
65
66#[derive(Debug)]
67#[cfg_attr(debug_assertions, derive(Clone))]
68pub struct ObjectArg {
69 pub kind: ObjectArgKind,
70 pub refined_permissions: ObjectPermissions,
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(PackagePayload, Vec<ObjectID>, ResolvedLinkage),
132 Upgrade(
133 PackagePayload,
134 Vec<ObjectID>,
135 ObjectID,
136 Argument,
137 ResolvedLinkage,
138 ),
139}
140
141#[derive(Debug, Clone)]
142pub enum PackagePayload {
143 Serialized(Vec<Vec<u8>>),
144 Deserialized(DeserializedPackage),
145}
146
147#[derive(Debug, Clone)]
149pub struct DeserializedPackage {
150 pub deserialized_modules: Vec<CompiledModule>,
152 pub total_bytes: usize,
154 pub computed_digest: [u8; 32],
157}
158
159#[derive(Debug)]
160pub struct LoadedFunctionInstantiation {
161 pub parameters: Vec<Type>,
162 pub return_: Vec<Type>,
163}
164
165#[derive(Debug)]
166pub struct LoadedFunction {
167 pub version_mid: ModuleId,
168 pub original_mid: ModuleId,
169 pub name: Identifier,
170 pub type_arguments: Vec<Type>,
171 pub signature: LoadedFunctionInstantiation,
172 pub linkage: ExecutableLinkage,
173 pub instruction_length: CodeOffset,
174 pub definition_index: FunctionDefinitionIndex,
175 pub visibility: Visibility,
176 pub is_entry: bool,
177 pub is_native: bool,
178}
179
180#[derive(Debug)]
181pub struct MoveCall {
182 pub function: LoadedFunction,
183 pub arguments: Vec<Argument>,
184}
185
186pub use sui_types::transaction::Argument;
187
188impl ObjectArg {
193 pub fn id(&self) -> ObjectID {
194 self.kind.id()
195 }
196}
197
198impl ObjectArgKind {
199 pub fn id(&self) -> ObjectID {
200 match self {
201 Self::ImmObject(oref) | Self::OwnedObject(oref) => oref.0,
202 Self::ConsensusObject { id, .. } => *id,
203 }
204 }
205}
206
207impl Type {
208 pub fn abilities(&self) -> AbilitySet {
209 match self {
210 Type::Bool
211 | Type::U8
212 | Type::U16
213 | Type::U32
214 | Type::U64
215 | Type::U128
216 | Type::U256
217 | Type::Address => AbilitySet::PRIMITIVES,
218 Type::Signer => AbilitySet::SIGNER,
219 Type::Reference(_, _) => AbilitySet::REFERENCES,
220 Type::Vector(v) => v.abilities,
221 Type::Datatype(dt) => dt.abilities,
222 }
223 }
224
225 pub fn is_tx_context(&self) -> TxContextKind {
226 let (is_mut, inner) = match self {
227 Type::Reference(is_mut, inner) => (*is_mut, inner),
228 _ => return TxContextKind::None,
229 };
230 let Type::Datatype(dt) = &**inner else {
231 return TxContextKind::None;
232 };
233 if dt.qualified_ident() == RESOLVED_TX_CONTEXT {
234 if is_mut {
235 TxContextKind::Mutable
236 } else {
237 TxContextKind::Immutable
238 }
239 } else {
240 TxContextKind::None
241 }
242 }
243 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
244 match self {
245 Type::Bool
246 | Type::U8
247 | Type::U16
248 | Type::U32
249 | Type::U64
250 | Type::U128
251 | Type::U256
252 | Type::Address
253 | Type::Signer => IndexSet::new(),
254 Type::Vector(v) => v.element_type.all_addresses(),
255 Type::Reference(_, inner) => inner.all_addresses(),
256 Type::Datatype(dt) => dt.all_addresses(),
257 }
258 }
259
260 pub fn node_count(&self) -> u64 {
261 use Type::*;
262 let mut total = 0u64;
263 let mut stack = vec![self];
264
265 while let Some(ty) = stack.pop() {
266 total = total.saturating_add(1);
267 match ty {
268 Bool | U8 | U16 | U32 | U64 | U128 | U256 | Address | Signer => {}
269 Vector(v) => stack.push(&v.element_type),
270 Reference(_, inner) => stack.push(inner),
271 Datatype(dt) => {
272 stack.extend(&dt.type_arguments);
273 }
274 }
275 }
276
277 total
278 }
279
280 pub fn is_reference(&self) -> bool {
281 match self {
282 Type::Bool
283 | Type::U8
284 | Type::U16
285 | Type::U32
286 | Type::U64
287 | Type::U128
288 | Type::U256
289 | Type::Address
290 | Type::Signer
291 | Type::Vector(_)
292 | Type::Datatype(_) => false,
293 Type::Reference(_, _) => true,
294 }
295 }
296}
297
298impl Datatype {
299 pub fn qualified_ident(&self) -> (&AccountAddress, &IdentStr, &IdentStr) {
300 (
301 self.module.address(),
302 self.module.name(),
303 self.name.as_ident_str(),
304 )
305 }
306
307 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
308 let mut addresses = IndexSet::new();
309 addresses.insert(*self.module.address());
310 for arg in &self.type_arguments {
311 addresses.extend(arg.all_addresses());
312 }
313 addresses
314 }
315}
316
317impl Command {
318 pub fn arguments_mut(&mut self) -> Box<dyn Iterator<Item = &mut Argument> + '_> {
319 match self {
320 Command::MoveCall(mc) => Box::new(mc.arguments.iter_mut()),
321 Command::TransferObjects(objs, recipient) => {
322 Box::new(objs.iter_mut().chain(std::iter::once(recipient)))
323 }
324 Command::SplitCoins(coin, amounts) => {
325 Box::new(std::iter::once(coin).chain(amounts.iter_mut()))
326 }
327 Command::MergeCoins(coin, coins) => {
328 Box::new(std::iter::once(coin).chain(coins.iter_mut()))
329 }
330 Command::MakeMoveVec(_, elements) => Box::new(elements.iter_mut()),
331 Command::Publish(_, _, _) => Box::new(std::iter::empty()),
332 Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
333 }
334 }
335
336 pub fn arguments(&self) -> Box<dyn Iterator<Item = &Argument> + '_> {
337 match self {
338 Command::MoveCall(mc) => Box::new(mc.arguments.iter()),
339 Command::TransferObjects(objs, recipient) => {
340 Box::new(objs.iter().chain(std::iter::once(recipient)))
341 }
342 Command::SplitCoins(coin, amounts) => {
343 Box::new(std::iter::once(coin).chain(amounts.iter()))
344 }
345 Command::MergeCoins(coin, coins) => Box::new(std::iter::once(coin).chain(coins.iter())),
346 Command::MakeMoveVec(_, elements) => Box::new(elements.iter()),
347 Command::Publish(_, _, _) => Box::new(std::iter::empty()),
348 Command::Upgrade(_, _, _, obj, _) => Box::new(std::iter::once(obj)),
349 }
350 }
351}
352
353impl TryFrom<Type> for TypeTag {
358 type Error = &'static str;
359 fn try_from(ty: Type) -> Result<Self, Self::Error> {
360 Ok(match ty {
361 Type::Bool => TypeTag::Bool,
362 Type::U8 => TypeTag::U8,
363 Type::U16 => TypeTag::U16,
364 Type::U32 => TypeTag::U32,
365 Type::U64 => TypeTag::U64,
366 Type::U128 => TypeTag::U128,
367 Type::U256 => TypeTag::U256,
368 Type::Address => TypeTag::Address,
369 Type::Signer => TypeTag::Signer,
370 Type::Vector(inner) => {
371 let Vector { element_type, .. } = &*inner;
372 TypeTag::Vector(Box::new(element_type.clone().try_into()?))
373 }
374 Type::Datatype(dt) => {
375 let dt: &Datatype = &dt;
376 TypeTag::Struct(Box::new(dt.try_into()?))
377 }
378 Type::Reference(_, _) => return Err("unexpected reference type"),
379 })
380 }
381}
382
383impl TryFrom<&Datatype> for StructTag {
384 type Error = &'static str;
385
386 fn try_from(dt: &Datatype) -> Result<Self, Self::Error> {
387 let Datatype {
388 module,
389 name,
390 type_arguments,
391 ..
392 } = dt;
393 Ok(StructTag {
394 address: *module.address(),
395 module: module.name().to_owned(),
396 name: name.to_owned(),
397 type_params: type_arguments
398 .iter()
399 .map(|t| t.clone().try_into())
400 .collect::<Result<Vec<TypeTag>, _>>()?,
401 })
402 }
403}
404
405#[test]
410fn enum_size() {
411 assert_eq!(std::mem::size_of::<Type>(), 16);
412}