iota_types/gas_model/
units_types.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    collections::BTreeMap,
7    ops::{Add, Bound},
8};
9
10use move_core_types::gas_algebra::{
11    GasQuantity, InternalGas, InternalGasUnit, ToUnit, ToUnitFractional,
12};
13use serde::{Deserialize, Serialize};
14
15pub enum GasUnit {}
16
17pub type Gas = GasQuantity<GasUnit>;
18
19impl ToUnit<InternalGasUnit> for GasUnit {
20    const MULTIPLIER: u64 = 1000;
21}
22
23impl ToUnitFractional<GasUnit> for InternalGasUnit {
24    const NOMINATOR: u64 = 1;
25    const DENOMINATOR: u64 = 1000;
26}
27
28pub const INSTRUCTION_TIER_DEFAULT: u64 = 1;
29
30pub const STACK_HEIGHT_TIER_DEFAULT: u64 = 1;
31pub const STACK_SIZE_TIER_DEFAULT: u64 = 1;
32
33// The cost table holds the tiers and curves for instruction costs.
34#[derive(Clone, Debug, Serialize, PartialEq, Eq, Deserialize)]
35pub struct CostTable {
36    pub instruction_tiers: BTreeMap<u64, u64>,
37    pub stack_height_tiers: BTreeMap<u64, u64>,
38    pub stack_size_tiers: BTreeMap<u64, u64>,
39}
40
41impl CostTable {
42    fn get_current_and_future_tier(
43        tiers: &BTreeMap<u64, u64>,
44        current: u64,
45        default: u64,
46    ) -> (u64, Option<u64>) {
47        let current_cost = tiers
48            .get(&current)
49            .or_else(|| tiers.range(..current).next_back().map(|(_, v)| v))
50            .unwrap_or(&default);
51        let next_tier_start = tiers
52            .range::<u64, _>((Bound::Excluded(current), Bound::Unbounded))
53            .next()
54            .map(|(next_tier_start, _)| *next_tier_start);
55        (*current_cost, next_tier_start)
56    }
57
58    pub fn instruction_tier(&self, instr_count: u64) -> (u64, Option<u64>) {
59        Self::get_current_and_future_tier(
60            &self.instruction_tiers,
61            instr_count,
62            INSTRUCTION_TIER_DEFAULT,
63        )
64    }
65
66    pub fn stack_height_tier(&self, stack_height: u64) -> (u64, Option<u64>) {
67        Self::get_current_and_future_tier(
68            &self.stack_height_tiers,
69            stack_height,
70            STACK_HEIGHT_TIER_DEFAULT,
71        )
72    }
73
74    pub fn stack_size_tier(&self, stack_size: u64) -> (u64, Option<u64>) {
75        Self::get_current_and_future_tier(
76            &self.stack_size_tiers,
77            stack_size,
78            STACK_SIZE_TIER_DEFAULT,
79        )
80    }
81}
82
83/// The  `GasCost` tracks:
84/// - instruction cost: how much time/computational power is needed to perform
85///   the instruction
86/// - memory cost: how much memory is required for the instruction, and storage
87///   overhead
88/// - stack height: how high is the stack growing (regardless of size in bytes)
89#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
90pub struct GasCost {
91    pub instruction_gas: u64,
92    pub memory_gas: u64,
93    pub stack_height_gas: u64,
94}
95
96impl GasCost {
97    pub fn new(instruction_gas: u64, memory_gas: u64, stack_height_gas: u64) -> Self {
98        Self {
99            instruction_gas,
100            memory_gas,
101            stack_height_gas,
102        }
103    }
104
105    /// Convert a GasCost to a total gas charge in `InternalGas`.
106    #[inline]
107    pub fn total(&self) -> u64 {
108        self.instruction_gas
109            .add(self.memory_gas)
110            .add(self.stack_height_gas)
111    }
112
113    #[inline]
114    pub fn total_internal(&self) -> InternalGas {
115        GasQuantity::new(
116            self.instruction_gas
117                .add(self.memory_gas)
118                .add(self.stack_height_gas),
119        )
120    }
121}