sui_move_natives_v1/
types.rs1use move_binary_format::errors::PartialVMResult;
5use move_core_types::{
6 gas_algebra::InternalGas,
7 language_storage::TypeTag,
8 runtime_value::{MoveStructLayout, MoveTypeLayout},
9};
10use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
11use move_vm_types::{
12 loaded_data::runtime_types::Type, natives::function::NativeResult, values::Value,
13};
14use smallvec::smallvec;
15use std::collections::VecDeque;
16
17use crate::NativesCostTable;
18
19pub(crate) fn is_otw_struct(struct_layout: &MoveStructLayout, type_tag: &TypeTag) -> bool {
20 let has_one_bool_field = matches!(struct_layout.0.as_slice(), [MoveTypeLayout::Bool]);
21
22 matches!(
28 type_tag,
29 TypeTag::Struct(struct_tag) if has_one_bool_field && struct_tag.name.to_string() == struct_tag.module.to_string().to_ascii_uppercase())
30}
31
32#[derive(Clone)]
33pub struct TypesIsOneTimeWitnessCostParams {
34 pub types_is_one_time_witness_cost_base: InternalGas,
35 pub types_is_one_time_witness_type_tag_cost_per_byte: InternalGas,
36 pub types_is_one_time_witness_type_cost_per_byte: InternalGas,
37}
38pub fn is_one_time_witness(
46 context: &mut NativeContext,
47 mut ty_args: Vec<Type>,
48 args: VecDeque<Value>,
49) -> PartialVMResult<NativeResult> {
50 debug_assert!(ty_args.len() == 1);
51 debug_assert!(args.len() == 1);
52
53 let type_is_one_time_witness_cost_params = context
54 .extensions_mut()
55 .get::<NativesCostTable>()
56 .type_is_one_time_witness_cost_params
57 .clone();
58
59 native_charge_gas_early_exit!(
60 context,
61 type_is_one_time_witness_cost_params.types_is_one_time_witness_cost_base
62 );
63
64 let ty = ty_args.pop().unwrap();
66
67 native_charge_gas_early_exit!(
68 context,
69 type_is_one_time_witness_cost_params.types_is_one_time_witness_type_cost_per_byte
70 * u64::from(ty.size()).into()
71 );
72
73 let type_tag = context.type_to_type_tag(&ty)?;
74 native_charge_gas_early_exit!(
75 context,
76 type_is_one_time_witness_cost_params.types_is_one_time_witness_type_tag_cost_per_byte
77 * u64::from(type_tag.abstract_size_for_gas_metering()).into()
78 );
79
80 let type_layout = context.type_to_type_layout(&ty)?;
81
82 let cost = context.gas_used();
83 let Some(MoveTypeLayout::Struct(struct_layout)) = type_layout else {
84 return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
85 };
86
87 let is_otw = is_otw_struct(&struct_layout, &type_tag);
88
89 Ok(NativeResult::ok(cost, smallvec![Value::bool(is_otw)]))
90}