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::static_programmable_transactions::{
5    env::Env,
6    linkage::resolved_linkage::RootedLinkage,
7    loading::ast as L,
8    metering::{self, translation_meter::TranslationMeter},
9};
10use move_core_types::language_storage::StructTag;
11use sui_types::{
12    error::ExecutionError,
13    object::Owner,
14    transaction::{self as P, CallArg, ObjectArg, SharedObjectMutability},
15};
16
17pub fn transaction(
18    meter: &mut TranslationMeter<'_, '_>,
19    env: &Env,
20    pt: P::ProgrammableTransaction,
21) -> Result<L::Transaction, ExecutionError> {
22    metering::pre_translation::meter(meter, &pt)?;
23    let P::ProgrammableTransaction { inputs, commands } = pt;
24    let inputs = inputs
25        .into_iter()
26        .map(|arg| input(env, arg))
27        .collect::<Result<Vec<_>, _>>()?;
28    let commands = commands
29        .into_iter()
30        .enumerate()
31        .map(|(idx, cmd)| command(env, cmd).map_err(|e| e.with_command_index(idx)))
32        .collect::<Result<Vec<_>, _>>()?;
33    let loaded_tx = L::Transaction { inputs, commands };
34    metering::loading::meter(meter, &loaded_tx)?;
35    Ok(loaded_tx)
36}
37
38fn input(env: &Env, arg: CallArg) -> Result<(L::InputArg, L::InputType), ExecutionError> {
39    Ok(match arg {
40        CallArg::Pure(bytes) => (L::InputArg::Pure(bytes), L::InputType::Bytes),
41        CallArg::Object(ObjectArg::Receiving(oref)) => {
42            (L::InputArg::Receiving(oref), L::InputType::Bytes)
43        }
44        CallArg::Object(ObjectArg::ImmOrOwnedObject(oref)) => {
45            let id = &oref.0;
46            let obj = env.read_object(id)?;
47            let Some(ty) = obj.type_() else {
48                invariant_violation!("Object {:?} has does not have a Move type", id);
49            };
50            let tag: StructTag = ty.clone().into();
51            let ty = env.load_type_from_struct(&tag)?;
52            let arg = match obj.owner {
53                Owner::AddressOwner(_) => L::ObjectArg::OwnedObject(oref),
54                Owner::Immutable => L::ObjectArg::ImmObject(oref),
55                Owner::ObjectOwner(_)
56                | Owner::Shared { .. }
57                | Owner::ConsensusAddressOwner { .. } => {
58                    invariant_violation!("Unexpected owner for ImmOrOwnedObject: {:?}", obj.owner);
59                }
60            };
61            (L::InputArg::Object(arg), L::InputType::Fixed(ty))
62        }
63        CallArg::Object(ObjectArg::SharedObject {
64            id,
65            initial_shared_version,
66            mutability,
67        }) => {
68            let obj = env.read_object(&id)?;
69            let Some(ty) = obj.type_() else {
70                invariant_violation!("Object {:?} has does not have a Move type", id);
71            };
72            let tag: StructTag = ty.clone().into();
73            let ty = env.load_type_from_struct(&tag)?;
74            let kind = match obj.owner {
75                Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => {
76                    invariant_violation!("Unexpected owner for SharedObject: {:?}", obj.owner)
77                }
78                Owner::Shared { .. } => L::SharedObjectKind::Legacy,
79                Owner::ConsensusAddressOwner { .. } => L::SharedObjectKind::Party,
80            };
81            (
82                L::InputArg::Object(L::ObjectArg::SharedObject {
83                    id,
84                    initial_shared_version,
85                    mutability: object_mutability(mutability),
86                    kind,
87                }),
88                L::InputType::Fixed(ty),
89            )
90        }
91        CallArg::FundsWithdrawal(_) => {
92            // TODO(address-balances): Add support for balance withdraws.
93            todo!("Load balance withdraw call arg")
94        }
95    })
96}
97
98fn object_mutability(mutability: SharedObjectMutability) -> L::ObjectMutability {
99    match mutability {
100        SharedObjectMutability::Mutable => L::ObjectMutability::Mutable,
101        SharedObjectMutability::NonExclusiveWrite => L::ObjectMutability::NonExclusiveWrite,
102        SharedObjectMutability::Immutable => L::ObjectMutability::Immutable,
103    }
104}
105
106fn command(env: &Env, command: P::Command) -> Result<L::Command, ExecutionError> {
107    Ok(match command {
108        P::Command::MoveCall(pmc) => {
109            let resolved_linkage = env
110                .linkage_analysis
111                .compute_call_linkage(&pmc, env.linkable_store)?;
112            let P::ProgrammableMoveCall {
113                package,
114                module,
115                function: name,
116                type_arguments: ptype_arguments,
117                arguments,
118            } = *pmc;
119            let linkage = RootedLinkage::new(*package, resolved_linkage);
120            let type_arguments = ptype_arguments
121                .into_iter()
122                .enumerate()
123                .map(|(idx, ty)| env.load_type_input(idx, ty))
124                .collect::<Result<Vec<_>, _>>()?;
125            let function = env.load_function(package, module, name, type_arguments, linkage)?;
126            L::Command::MoveCall(Box::new(L::MoveCall {
127                function,
128                arguments,
129            }))
130        }
131        P::Command::MakeMoveVec(ptype_argument, arguments) => {
132            let type_argument = ptype_argument
133                .map(|ty| env.load_type_input(0, ty))
134                .transpose()?;
135            L::Command::MakeMoveVec(type_argument, arguments)
136        }
137        P::Command::TransferObjects(objects, address) => {
138            L::Command::TransferObjects(objects, address)
139        }
140        P::Command::SplitCoins(coin, amounts) => L::Command::SplitCoins(coin, amounts),
141        P::Command::MergeCoins(target, coins) => L::Command::MergeCoins(target, coins),
142        P::Command::Publish(items, object_ids) => {
143            let resolved_linkage = env
144                .linkage_analysis
145                .compute_publication_linkage(&object_ids, env.linkable_store)?;
146            L::Command::Publish(items, object_ids, resolved_linkage)
147        }
148        P::Command::Upgrade(items, object_ids, object_id, argument) => {
149            let resolved_linkage = env
150                .linkage_analysis
151                .compute_publication_linkage(&object_ids, env.linkable_store)?;
152            L::Command::Upgrade(items, object_ids, object_id, argument, resolved_linkage)
153        }
154    })
155}