iota_move_natives_latest/
types.rs1use std::collections::VecDeque;
6
7use move_binary_format::errors::PartialVMResult;
8use move_core_types::{
9 gas_algebra::InternalGas,
10 language_storage::TypeTag,
11 runtime_value::{MoveStructLayout, MoveTypeLayout},
12};
13use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
14use move_vm_types::{
15 loaded_data::runtime_types::Type, natives::function::NativeResult, values::Value,
16};
17use smallvec::smallvec;
18
19use crate::NativesCostTable;
20
21pub(crate) fn is_otw_struct(
22 struct_layout: &MoveStructLayout,
23 type_tag: &TypeTag,
24 hardened_check: bool,
25) -> bool {
26 let has_one_bool_field = matches!(struct_layout.0.as_slice(), [MoveTypeLayout::Bool]);
27
28 matches!(
36 type_tag,
37 TypeTag::Struct(struct_tag) if
38 has_one_bool_field &&
39 struct_tag.name.to_string() == struct_tag.module.to_string().to_ascii_uppercase() &&
40 (!hardened_check || struct_tag.type_params.is_empty())
42 )
43}
44
45#[derive(Clone)]
46pub struct TypesIsOneTimeWitnessCostParams {
47 pub types_is_one_time_witness_cost_base: InternalGas,
48 pub types_is_one_time_witness_type_tag_cost_per_byte: InternalGas,
49 pub types_is_one_time_witness_type_cost_per_byte: InternalGas,
50}
51pub fn is_one_time_witness(
64 context: &mut NativeContext,
65 mut ty_args: Vec<Type>,
66 args: VecDeque<Value>,
67) -> PartialVMResult<NativeResult> {
68 debug_assert!(ty_args.len() == 1);
69 debug_assert!(args.len() == 1);
70
71 let type_is_one_time_witness_cost_params = context
72 .extensions_mut()
73 .get::<NativesCostTable>()
74 .type_is_one_time_witness_cost_params
75 .clone();
76
77 native_charge_gas_early_exit!(
78 context,
79 type_is_one_time_witness_cost_params.types_is_one_time_witness_cost_base
80 );
81
82 let ty = ty_args.pop().unwrap();
84
85 native_charge_gas_early_exit!(
86 context,
87 type_is_one_time_witness_cost_params.types_is_one_time_witness_type_cost_per_byte
88 * u64::from(ty.size()).into()
89 );
90
91 let type_tag = context.type_to_type_tag(&ty)?;
92 native_charge_gas_early_exit!(
93 context,
94 type_is_one_time_witness_cost_params.types_is_one_time_witness_type_tag_cost_per_byte
95 * u64::from(type_tag.abstract_size_for_gas_metering()).into()
96 );
97
98 let type_layout = context.type_to_type_layout(&ty)?;
99
100 let cost = context.gas_used();
101 let Some(MoveTypeLayout::Struct(struct_layout)) = type_layout else {
102 return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
103 };
104
105 let hardened_check = context.runtime_limits_config().hardened_otw_check;
106 let is_otw = is_otw_struct(&struct_layout, &type_tag, hardened_check);
107
108 Ok(NativeResult::ok(cost, smallvec![Value::bool(is_otw)]))
109}