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