Skip to main content

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