sui_adapter_latest/static_programmable_transactions/loading/
translate.rs1use crate::{
5 execution_mode::ExecutionMode,
6 static_programmable_transactions::{
7 env::Env,
8 linkage::resolved_linkage::RootedLinkage,
9 loading::ast as L,
10 metering::{self, translation_meter::TranslationMeter},
11 },
12};
13use move_core_types::{account_address::AccountAddress, language_storage::StructTag, u256::U256};
14use sui_types::{
15 base_types::TxContext,
16 error::ExecutionError,
17 object::Owner,
18 transaction::{self as P, CallArg, FundsWithdrawalArg, ObjectArg, SharedObjectMutability},
19};
20
21pub fn transaction<Mode: ExecutionMode>(
22 meter: &mut TranslationMeter<'_, '_>,
23 env: &Env,
24 tx_context: &TxContext,
25 pt: P::ProgrammableTransaction,
26) -> Result<L::Transaction, ExecutionError> {
27 metering::pre_translation::meter(meter, &pt)?;
28 let P::ProgrammableTransaction { inputs, commands } = pt;
29 let inputs = inputs
30 .into_iter()
31 .map(|arg| input::<Mode>(env, tx_context, arg))
32 .collect::<Result<Vec<_>, _>>()?;
33 let commands = commands
34 .into_iter()
35 .enumerate()
36 .map(|(idx, cmd)| command(env, cmd).map_err(|e| e.with_command_index(idx)))
37 .collect::<Result<Vec<_>, _>>()?;
38 let loaded_tx = L::Transaction { inputs, commands };
39 metering::loading::meter(meter, &loaded_tx)?;
40 Ok(loaded_tx)
41}
42
43fn input<Mode: ExecutionMode>(
44 env: &Env,
45 tx_context: &TxContext,
46 arg: CallArg,
47) -> Result<(L::InputArg, L::InputType), ExecutionError> {
48 Ok(match arg {
49 CallArg::Pure(bytes) => (L::InputArg::Pure(bytes), L::InputType::Bytes),
50 CallArg::Object(ObjectArg::Receiving(oref)) => {
51 (L::InputArg::Receiving(oref), L::InputType::Bytes)
52 }
53 CallArg::Object(ObjectArg::ImmOrOwnedObject(oref)) => {
54 let id = &oref.0;
55 let obj = env.read_object(id)?;
56 let Some(ty) = obj.type_() else {
57 invariant_violation!("Object {:?} has does not have a Move type", id);
58 };
59 let tag: StructTag = ty.clone().into();
60 let ty = env.load_type_from_struct(&tag)?;
61 let arg = match obj.owner {
62 Owner::AddressOwner(_) => L::ObjectArg::OwnedObject(oref),
63 Owner::Immutable => L::ObjectArg::ImmObject(oref),
64 Owner::ObjectOwner(_)
65 | Owner::Shared { .. }
66 | Owner::ConsensusAddressOwner { .. } => {
67 assert_invariant!(
68 Mode::allow_arbitrary_values(),
69 "Unexpected owner for ImmOrOwnedObject: {:?}",
70 obj.owner,
71 );
72 L::ObjectArg::OwnedObject(oref)
73 }
74 };
75 (L::InputArg::Object(arg), L::InputType::Fixed(ty))
76 }
77 CallArg::Object(ObjectArg::SharedObject {
78 id,
79 initial_shared_version,
80 mutability,
81 }) => {
82 let obj = env.read_object(&id)?;
83 let Some(ty) = obj.type_() else {
84 invariant_violation!("Object {:?} has does not have a Move type", id);
85 };
86 let tag: StructTag = ty.clone().into();
87 let ty = env.load_type_from_struct(&tag)?;
88 let kind = match obj.owner {
89 Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => {
90 assert_invariant!(
91 Mode::allow_arbitrary_values(),
92 "Unexpected owner for SharedObject: {:?}",
93 obj.owner
94 );
95 L::SharedObjectKind::Party
96 }
97 Owner::Shared { .. } => L::SharedObjectKind::Legacy,
98 Owner::ConsensusAddressOwner { .. } => L::SharedObjectKind::Party,
99 };
100 (
101 L::InputArg::Object(L::ObjectArg::SharedObject {
102 id,
103 initial_shared_version,
104 mutability: object_mutability(mutability),
105 kind,
106 }),
107 L::InputType::Fixed(ty),
108 )
109 }
110 CallArg::FundsWithdrawal(f) => {
111 let FundsWithdrawalArg {
112 reservation,
113 type_arg,
114 withdraw_from,
115 } = f;
116 let amount = match reservation {
117 P::Reservation::EntireBalance => {
118 invariant_violation!("Entire balance reservation amount is not yet supported")
119 }
120 P::Reservation::MaxAmountU64(u) => U256::from(u),
121 };
124 let funds_ty = match type_arg {
125 P::WithdrawalTypeArg::Balance(inner) => {
126 let inner = env.load_type_input(0, inner)?;
127 env.balance_type(inner)?
128 }
129 };
130 let ty = env.withdrawal_type(funds_ty.clone())?;
131 let owner: AccountAddress = match withdraw_from {
132 P::WithdrawFrom::Sender => tx_context.sender().into(),
133 P::WithdrawFrom::Sponsor => tx_context
134 .sponsor()
135 .ok_or_else(|| {
136 make_invariant_violation!(
137 "A sponsor withdrawal requires a sponsor and should have been \
138 checked at signing"
139 )
140 })?
141 .into(),
142 };
143 (
144 L::InputArg::FundsWithdrawal(L::FundsWithdrawalArg {
145 amount,
146 ty: ty.clone(),
147 owner,
148 }),
149 L::InputType::Fixed(ty),
150 )
151 }
152 })
153}
154
155fn object_mutability(mutability: SharedObjectMutability) -> L::ObjectMutability {
156 match mutability {
157 SharedObjectMutability::Mutable => L::ObjectMutability::Mutable,
158 SharedObjectMutability::NonExclusiveWrite => L::ObjectMutability::NonExclusiveWrite,
159 SharedObjectMutability::Immutable => L::ObjectMutability::Immutable,
160 }
161}
162
163fn command(env: &Env, command: P::Command) -> Result<L::Command, ExecutionError> {
164 Ok(match command {
165 P::Command::MoveCall(pmc) => {
166 let resolved_linkage = env
167 .linkage_analysis
168 .compute_call_linkage(&pmc, env.linkable_store)?;
169 let P::ProgrammableMoveCall {
170 package,
171 module,
172 function: name,
173 type_arguments: ptype_arguments,
174 arguments,
175 } = *pmc;
176 let linkage = RootedLinkage::new(*package, resolved_linkage);
177 let type_arguments = ptype_arguments
178 .into_iter()
179 .enumerate()
180 .map(|(idx, ty)| env.load_type_input(idx, ty))
181 .collect::<Result<Vec<_>, _>>()?;
182 let function = env.load_function(package, module, name, type_arguments, linkage)?;
183 L::Command::MoveCall(Box::new(L::MoveCall {
184 function,
185 arguments,
186 }))
187 }
188 P::Command::MakeMoveVec(ptype_argument, arguments) => {
189 let type_argument = ptype_argument
190 .map(|ty| env.load_type_input(0, ty))
191 .transpose()?;
192 L::Command::MakeMoveVec(type_argument, arguments)
193 }
194 P::Command::TransferObjects(objects, address) => {
195 L::Command::TransferObjects(objects, address)
196 }
197 P::Command::SplitCoins(coin, amounts) => L::Command::SplitCoins(coin, amounts),
198 P::Command::MergeCoins(target, coins) => L::Command::MergeCoins(target, coins),
199 P::Command::Publish(items, object_ids) => {
200 let resolved_linkage = env
201 .linkage_analysis
202 .compute_publication_linkage(&object_ids, env.linkable_store)?;
203 L::Command::Publish(items, object_ids, resolved_linkage)
204 }
205 P::Command::Upgrade(items, object_ids, object_id, argument) => {
206 let resolved_linkage = env
207 .linkage_analysis
208 .compute_publication_linkage(&object_ids, env.linkable_store)?;
209 L::Command::Upgrade(items, object_ids, object_id, argument, resolved_linkage)
210 }
211 })
212}