sui_adapter_v3/static_programmable_transactions/typing/verify/
move_functions.rs1use crate::execution_mode::ExecutionMode;
5use crate::programmable_transactions::execution::check_private_generics_v2;
6use crate::sp;
7use crate::static_programmable_transactions::{env::Env, loading::ast::Type, typing::ast as T};
8use move_binary_format::{CompiledModule, file_format::Visibility};
9use sui_types::error::ExecutionError;
10use sui_types::execution_status::ExecutionErrorKind;
11
12pub fn verify<Mode: ExecutionMode>(env: &Env, txn: &T::Transaction) -> Result<(), ExecutionError> {
20 for c in &txn.commands {
21 command::<Mode>(env, c).map_err(|e| e.with_command_index(c.idx as usize))?;
22 }
23 Ok(())
24}
25
26fn command<Mode: ExecutionMode>(env: &Env, sp!(_, c): &T::Command) -> Result<(), ExecutionError> {
27 let T::Command_ {
28 command,
29 result_type: _,
30 drop_values: _,
31 consumed_shared_objects: _,
32 } = c;
33 match command {
34 T::Command__::MoveCall(call) => move_call::<Mode>(env, call)?,
35 T::Command__::TransferObjects(_, _)
36 | T::Command__::SplitCoins(_, _, _)
37 | T::Command__::MergeCoins(_, _, _)
38 | T::Command__::MakeMoveVec(_, _)
39 | T::Command__::Publish(_, _, _)
40 | T::Command__::Upgrade(_, _, _, _, _) => (),
41 }
42 Ok(())
43}
44
45fn move_call<Mode: ExecutionMode>(env: &Env, call: &T::MoveCall) -> Result<(), ExecutionError> {
50 let T::MoveCall {
51 function,
52 arguments: _,
53 } = call;
54 check_signature::<Mode>(env, function)?;
55 check_private_generics_v2(&function.runtime_id, function.name.as_ident_str())?;
56 check_visibility::<Mode>(env, function)?;
57 Ok(())
58}
59
60fn check_signature<Mode: ExecutionMode>(
61 env: &Env,
62 function: &T::LoadedFunction,
63) -> Result<(), ExecutionError> {
64 fn check_return_type<Mode: ExecutionMode>(
65 idx: usize,
66 return_type: &T::Type,
67 ) -> Result<(), ExecutionError> {
68 if let Type::Reference(_, _) = return_type
69 && !Mode::allow_arbitrary_values()
70 {
71 return Err(ExecutionError::from_kind(
72 ExecutionErrorKind::InvalidPublicFunctionReturnType {
73 idx: checked_as!(idx, u16)?,
74 },
75 ));
76 }
77 Ok(())
78 }
79
80 if env.protocol_config.allow_references_in_ptbs() {
81 return Ok(());
82 }
83
84 for (idx, ty) in function.signature.return_.iter().enumerate() {
85 check_return_type::<Mode>(idx, ty)?;
86 }
87 Ok(())
88}
89
90fn check_visibility<Mode: ExecutionMode>(
91 env: &Env,
92 function: &T::LoadedFunction,
93) -> Result<(), ExecutionError> {
94 let module = env.module_definition(&function.runtime_id, &function.linkage)?;
95 let module: &CompiledModule = module.as_ref();
96 let Some((_index, fdef)) = module.find_function_def_by_name(function.name.as_str()) else {
97 invariant_violation!(
98 "Could not resolve function '{}' in module {}. \
99 This should have been checked when linking",
100 &function.name,
101 module.self_id(),
102 );
103 };
104 let visibility = fdef.visibility;
105 let is_entry = fdef.is_entry;
106 match (visibility, is_entry) {
107 (Visibility::Private | Visibility::Friend, true) => (),
109 (Visibility::Public, true) => (),
111 (Visibility::Public, false) => (),
113 (Visibility::Private | Visibility::Friend, false) => {
115 if !Mode::allow_arbitrary_function_calls() {
116 return Err(ExecutionError::new_with_source(
117 ExecutionErrorKind::NonEntryFunctionInvoked,
118 "Can only call `entry` or `public` functions",
119 ));
120 }
121 }
122 };
123 Ok(())
124}