sui_types/gas_model/
units_types.rs

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