sui_adapter_latest/static_programmable_transactions/metering/
translation_meter.rs1use crate::gas_charger::GasCharger;
5use sui_protocol_config::ProtocolConfig;
6use sui_types::error::{ExecutionError, ExecutionErrorKind};
7
8pub struct TranslationMeter<'pc, 'gas> {
15 protocol_config: &'pc ProtocolConfig,
16 charger: &'gas mut GasCharger,
17 charged: u64,
18}
19
20impl<'pc, 'gas> TranslationMeter<'pc, 'gas> {
21 pub fn new(
22 protocol_config: &'pc ProtocolConfig,
23 gas_charger: &'gas mut GasCharger,
24 ) -> TranslationMeter<'pc, 'gas> {
25 TranslationMeter {
26 protocol_config,
27 charger: gas_charger,
28 charged: 0,
29 }
30 }
31
32 pub fn charge_base_inputs(&mut self, num_inputs: usize) -> Result<(), ExecutionError> {
33 let amount = (num_inputs as u64)
34 .max(1)
35 .saturating_mul(self.protocol_config.translation_per_input_base_charge());
36 self.charge(amount)
37 }
38
39 pub fn charge_pure_input_bytes(&mut self, num_bytes: usize) -> Result<(), ExecutionError> {
40 let amount = (num_bytes as u64).max(1).saturating_mul(
41 self.protocol_config
42 .translation_pure_input_per_byte_charge(),
43 );
44 self.charge(amount)
45 }
46
47 pub fn charge_base_command(&mut self, num_args: usize) -> Result<(), ExecutionError> {
48 let amount = (num_args as u64)
49 .max(1)
50 .saturating_mul(self.protocol_config.translation_per_command_base_charge());
51 self.charge(amount)
52 }
53
54 pub fn charge_num_type_nodes(&mut self, num_type_nodes: u64) -> Result<(), ExecutionError> {
58 let amount = num_type_nodes
59 .max(1)
60 .saturating_mul(self.protocol_config.translation_per_type_node_charge());
61 self.charge(amount)
62 }
63
64 pub fn charge_num_type_references(
65 &mut self,
66 num_type_references: u64,
67 ) -> Result<(), ExecutionError> {
68 let amount = self.reference_cost_formula(num_type_references.max(1));
69 let amount =
70 amount.saturating_mul(self.protocol_config.translation_per_reference_node_charge());
71 self.charge(amount)
72 }
73
74 pub fn charge_num_linkage_entries(
75 &mut self,
76 num_linkage_entries: usize,
77 ) -> Result<(), ExecutionError> {
78 let amount = (num_linkage_entries as u64)
79 .saturating_mul(self.protocol_config.translation_per_linkage_entry_charge())
80 .max(1);
81 self.charge(amount)
82 }
83
84 fn reference_cost_formula(&self, n: u64) -> u64 {
90 (n.saturating_mul(n + 1)) / 2
91 }
92
93 fn charge(&mut self, amount: u64) -> Result<(), ExecutionError> {
96 debug_assert!(amount > 0);
97 let scaled_charge = self.calculate_point_charge(amount);
98 self.charger
99 .move_gas_status_mut()
100 .deduct_gas(scaled_charge.into())
101 .map_err(Self::gas_error)
102 }
103
104 fn calculate_point_charge(&mut self, amount: u64) -> u64 {
112 debug_assert!(self.protocol_config.translation_metering_step_resolution() > 0);
113 let point_multiplier = self
114 .charged
115 .saturating_div(self.protocol_config.translation_metering_step_resolution())
116 .max(1);
117 debug_assert!(point_multiplier > 0);
118 debug_assert!(amount > 0);
119 let point_charge = point_multiplier
120 .saturating_mul(point_multiplier)
121 .saturating_mul(amount);
122 self.charged = self.charged.saturating_add(point_charge);
123 point_charge
124 }
125
126 fn gas_error<E>(e: E) -> ExecutionError
127 where
128 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
129 {
130 ExecutionError::new_with_source(ExecutionErrorKind::InsufficientGas, e)
131 }
132}