1use alloy_primitives::U256;
7use arb_primitives::multigas::{MultiGas, ResourceKind};
8
9const WARM: u64 = 100; const COLD_SLOAD: u64 = 2_100; const COLD_ACCOUNT: u64 = 2_600; const SSTORE_SET: u64 = 20_000; const SSTORE_RESET: u64 = 5_000; const NEW_ACCOUNT: u64 = 25_000; const VALUE_TRANSFER: u64 = 9_000; const LOG_TOPIC_HISTORY: u64 = 256; const LOG_DATA: u64 = 8; pub fn state_load(is_cold: bool) -> MultiGas {
21 if is_cold {
22 MultiGas::from_pairs(&[
23 (ResourceKind::StorageAccessRead, COLD_SLOAD - WARM),
24 (ResourceKind::Computation, WARM),
25 ])
26 } else {
27 MultiGas::computation_gas(WARM)
28 }
29}
30
31pub fn state_store(is_cold: bool, original: U256, present: U256, new: U256) -> MultiGas {
34 use ResourceKind::*;
35 let mut pairs = Vec::with_capacity(2);
36 if is_cold {
37 pairs.push((StorageAccessRead, COLD_SLOAD));
38 }
39 if present == new {
40 pairs.push((Computation, WARM));
41 } else if original == present {
42 if original.is_zero() {
43 pairs.push((StorageGrowth, SSTORE_SET));
44 } else {
45 pairs.push((StorageAccessWrite, SSTORE_RESET - COLD_SLOAD));
46 }
47 } else {
48 pairs.push((Computation, WARM));
49 }
50 MultiGas::from_pairs(&pairs)
51}
52
53pub fn account_touch(is_cold: bool, ext_code_cost: u64) -> MultiGas {
56 let read = if is_cold {
57 ext_code_cost + (COLD_ACCOUNT - WARM)
58 } else {
59 ext_code_cost
60 };
61 MultiGas::from_pairs(&[
62 (ResourceKind::StorageAccessRead, read),
63 (ResourceKind::Computation, WARM),
64 ])
65}
66
67pub fn log(num_topics: u64, data_bytes: u64) -> MultiGas {
69 MultiGas::history_growth_gas(LOG_TOPIC_HISTORY * num_topics + LOG_DATA * data_bytes)
70}
71
72pub fn call_cost(is_cold: bool, transfers_value: bool, new_account: bool) -> MultiGas {
76 let computation = WARM + if transfers_value { VALUE_TRANSFER } else { 0 };
77 let read = if is_cold { COLD_ACCOUNT - WARM } else { 0 };
78 let growth = if transfers_value && new_account {
79 NEW_ACCOUNT
80 } else {
81 0
82 };
83 MultiGas::from_pairs(&[
84 (ResourceKind::Computation, computation),
85 (ResourceKind::StorageAccessRead, read),
86 (ResourceKind::StorageGrowth, growth),
87 ])
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 fn dims(mg: &MultiGas) -> (u64, u64, u64, u64, u64) {
95 (
96 mg.get(ResourceKind::Computation),
97 mg.get(ResourceKind::StorageAccessRead),
98 mg.get(ResourceKind::StorageAccessWrite),
99 mg.get(ResourceKind::StorageGrowth),
100 mg.get(ResourceKind::HistoryGrowth),
101 )
102 }
103
104 #[test]
105 fn load_cold_warm() {
106 assert_eq!(dims(&state_load(true)), (100, 2_000, 0, 0, 0));
107 assert_eq!(state_load(true).single_gas(), COLD_SLOAD);
108 assert_eq!(dims(&state_load(false)), (100, 0, 0, 0, 0));
109 }
110
111 #[test]
112 fn store_cold_create() {
113 let mg = state_store(true, U256::ZERO, U256::ZERO, U256::from(1));
114 assert_eq!(dims(&mg), (0, 2_100, 0, 20_000, 0));
115 assert_eq!(mg.single_gas(), COLD_SLOAD + SSTORE_SET);
116 }
117
118 #[test]
119 fn store_warm_write_and_noop_and_dirty() {
120 let write = state_store(false, U256::from(7), U256::from(7), U256::from(9));
121 assert_eq!(dims(&write), (0, 0, 2_900, 0, 0));
122 let noop = state_store(false, U256::from(5), U256::from(5), U256::from(5));
123 assert_eq!(dims(&noop), (100, 0, 0, 0, 0));
124 let dirty = state_store(false, U256::from(1), U256::from(2), U256::from(3));
125 assert_eq!(dims(&dirty), (100, 0, 0, 0, 0));
126 }
127
128 #[test]
129 fn account_cold_warm_and_code() {
130 assert_eq!(dims(&account_touch(true, 0)), (100, 2_500, 0, 0, 0));
131 assert_eq!(dims(&account_touch(false, 0)), (100, 0, 0, 0, 0));
132 assert_eq!(dims(&account_touch(true, 700)), (100, 3_200, 0, 0, 0));
133 assert_eq!(account_touch(true, 700).single_gas(), 700 + COLD_ACCOUNT);
134 }
135
136 #[test]
137 fn log_history_growth() {
138 let mg = log(2, 10);
139 assert_eq!(dims(&mg), (0, 0, 0, 0, 256 * 2 + 8 * 10));
140 }
141
142 #[test]
143 fn call_cost_variants() {
144 assert_eq!(dims(&call_cost(false, false, false)), (100, 0, 0, 0, 0));
145 assert_eq!(dims(&call_cost(true, false, false)), (100, 2_500, 0, 0, 0));
146 assert_eq!(dims(&call_cost(true, true, false)), (9_100, 2_500, 0, 0, 0));
147 assert_eq!(
148 dims(&call_cost(true, true, true)),
149 (9_100, 2_500, 0, 25_000, 0)
150 );
151 assert_eq!(
152 call_cost(true, true, true).single_gas(),
153 100 + 2_500 + 9_000 + 25_000
154 );
155 }
156}