sui_adapter_latest/static_programmable_transactions/loading/
translate.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use 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                // TODO when types other than u64 are supported, we must check that this is a
122                // valid amount for the type
123            };
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}