near_runtime_fees/
lib.rs

1//! Describes the various costs incurred by creating receipts.
2//! We use the following abbreviation for readability:
3//! * sir -- sender is receiver. Receipts that are directed by an account to itself are guaranteed
4//!   to not be cross-shard which is cheaper than cross-shard. Conversely, when sender is not a
5//!   receiver it might or might not be a cross-shard communication.
6use num_rational::Rational;
7use serde::{Deserialize, Serialize};
8
9pub type Gas = u64;
10
11/// Costs associated with an object that can only be sent over the network (and executed
12/// by the receiver).
13/// NOTE: `send_sir` or `send_not_sir` fees are usually burned when the item is being created.
14/// And `execution` fee is burned when the item is being executed.
15#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
16pub struct Fee {
17    /// Fee for sending an object from the sender to itself, guaranteeing that it does not leave
18    /// the shard.
19    pub send_sir: Gas,
20    /// Fee for sending an object potentially across the shards.
21    pub send_not_sir: Gas,
22    /// Fee for executing the object.
23    pub execution: Gas,
24}
25
26impl Fee {
27    #[inline]
28    pub fn send_fee(&self, sir: bool) -> Gas {
29        if sir {
30            self.send_sir
31        } else {
32            self.send_not_sir
33        }
34    }
35
36    pub fn exec_fee(&self) -> Gas {
37        self.execution
38    }
39
40    /// The minimum fee to send and execute.
41    fn min_send_and_exec_fee(&self) -> Gas {
42        std::cmp::min(self.send_sir, self.send_not_sir) + self.execution
43    }
44}
45
46#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
47pub struct RuntimeFeesConfig {
48    /// Describes the cost of creating an action receipt, `ActionReceipt`, excluding the actual cost
49    /// of actions.
50    /// - `send` cost is burned when a receipt is created using `promise_create` or
51    ///     `promise_batch_create`
52    /// - `exec` cost is burned when the receipt is being executed.
53    pub action_receipt_creation_config: Fee,
54    /// Describes the cost of creating a data receipt, `DataReceipt`.
55    pub data_receipt_creation_config: DataReceiptCreationConfig,
56    /// Describes the cost of creating a certain action, `Action`. Includes all variants.
57    pub action_creation_config: ActionCreationConfig,
58    /// Describes fees for storage.
59    pub storage_usage_config: StorageUsageConfig,
60
61    /// Fraction of the burnt gas to reward to the contract account for execution.
62    pub burnt_gas_reward: Rational,
63
64    /// Pessimistic gas price inflation ratio.
65    pub pessimistic_gas_price_inflation_ratio: Rational,
66}
67
68/// Describes the cost of creating a data receipt, `DataReceipt`.
69#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
70pub struct DataReceiptCreationConfig {
71    /// Base cost of creating a data receipt.
72    /// Both `send` and `exec` costs are burned when a new receipt has input dependencies. The gas
73    /// is charged for each input dependency. The dependencies are specified when a receipt is
74    /// created using `promise_then` and `promise_batch_then`.
75    /// NOTE: Any receipt with output dependencies will produce data receipts. Even if it fails.
76    /// Even if the last action is not a function call (in case of success it will return empty
77    /// value).
78    pub base_cost: Fee,
79    /// Additional cost per byte sent.
80    /// Both `send` and `exec` costs are burned when a function call finishes execution and returns
81    /// `N` bytes of data to every output dependency. For each output dependency the cost is
82    /// `(send(sir) + exec()) * N`.
83    pub cost_per_byte: Fee,
84}
85
86/// Describes the cost of creating a specific action, `Action`. Includes all variants.
87#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
88pub struct ActionCreationConfig {
89    /// Base cost of creating an account.
90    pub create_account_cost: Fee,
91
92    /// Base cost of deploying a contract.
93    pub deploy_contract_cost: Fee,
94    /// Cost per byte of deploying a contract.
95    pub deploy_contract_cost_per_byte: Fee,
96
97    /// Base cost of calling a function.
98    pub function_call_cost: Fee,
99    /// Cost per byte of method name and arguments of calling a function.
100    pub function_call_cost_per_byte: Fee,
101
102    /// Base cost of making a transfer.
103    pub transfer_cost: Fee,
104
105    /// Base cost of staking.
106    pub stake_cost: Fee,
107
108    /// Base cost of adding a key.
109    pub add_key_cost: AccessKeyCreationConfig,
110
111    /// Base cost of deleting a key.
112    pub delete_key_cost: Fee,
113
114    /// Base cost of deleting an account.
115    pub delete_account_cost: Fee,
116}
117
118/// Describes the cost of creating an access key.
119#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
120pub struct AccessKeyCreationConfig {
121    /// Base cost of creating a full access access-key.
122    pub full_access_cost: Fee,
123    /// Base cost of creating an access-key restricted to specific functions.
124    pub function_call_cost: Fee,
125    /// Cost per byte of method_names of creating a restricted access-key.
126    pub function_call_cost_per_byte: Fee,
127}
128
129/// Describes cost of storage per block
130#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
131pub struct StorageUsageConfig {
132    /// Number of bytes for an account record, including rounding up for account id.
133    pub num_bytes_account: u64,
134    /// Additional number of bytes for a k/v record
135    pub num_extra_bytes_record: u64,
136}
137
138impl Default for RuntimeFeesConfig {
139    fn default() -> Self {
140        #[allow(clippy::unreadable_literal)]
141        Self {
142            action_receipt_creation_config: Fee {
143                send_sir: 108059500000,
144                send_not_sir: 108059500000,
145                execution: 108059500000,
146            },
147            data_receipt_creation_config: DataReceiptCreationConfig {
148                base_cost: Fee {
149                    send_sir: 4697339419375,
150                    send_not_sir: 4697339419375,
151                    execution: 4697339419375,
152                },
153                cost_per_byte: Fee {
154                    send_sir: 59357464,
155                    send_not_sir: 59357464,
156                    execution: 59357464,
157                },
158            },
159            action_creation_config: ActionCreationConfig {
160                create_account_cost: Fee {
161                    send_sir: 99607375000,
162                    send_not_sir: 99607375000,
163                    execution: 99607375000,
164                },
165                deploy_contract_cost: Fee {
166                    send_sir: 184765750000,
167                    send_not_sir: 184765750000,
168                    execution: 184765750000,
169                },
170                deploy_contract_cost_per_byte: Fee {
171                    send_sir: 6812999,
172                    send_not_sir: 6812999,
173                    execution: 6812999,
174                },
175                function_call_cost: Fee {
176                    send_sir: 2319861500000,
177                    send_not_sir: 2319861500000,
178                    execution: 2319861500000,
179                },
180                function_call_cost_per_byte: Fee {
181                    send_sir: 2235934,
182                    send_not_sir: 2235934,
183                    execution: 2235934,
184                },
185                transfer_cost: Fee {
186                    send_sir: 115123062500,
187                    send_not_sir: 115123062500,
188                    execution: 115123062500,
189                },
190                stake_cost: Fee {
191                    send_sir: 141715687500,
192                    send_not_sir: 141715687500,
193                    execution: 102217625000,
194                },
195                add_key_cost: AccessKeyCreationConfig {
196                    full_access_cost: Fee {
197                        send_sir: 101765125000,
198                        send_not_sir: 101765125000,
199                        execution: 101765125000,
200                    },
201                    function_call_cost: Fee {
202                        send_sir: 102217625000,
203                        send_not_sir: 102217625000,
204                        execution: 102217625000,
205                    },
206                    function_call_cost_per_byte: Fee {
207                        send_sir: 1925331,
208                        send_not_sir: 1925331,
209                        execution: 1925331,
210                    },
211                },
212                delete_key_cost: Fee {
213                    send_sir: 94946625000,
214                    send_not_sir: 94946625000,
215                    execution: 94946625000,
216                },
217                delete_account_cost: Fee {
218                    send_sir: 147489000000,
219                    send_not_sir: 147489000000,
220                    execution: 147489000000,
221                },
222            },
223            storage_usage_config: StorageUsageConfig {
224                // See Account in core/primitives/src/account.rs for the data structure.
225                // TODO(2291): figure out value for the MainNet.
226                num_bytes_account: 100,
227                num_extra_bytes_record: 40,
228            },
229            burnt_gas_reward: Rational::new(3, 10),
230            pessimistic_gas_price_inflation_ratio: Rational::new(103, 100),
231        }
232    }
233}
234
235impl RuntimeFeesConfig {
236    pub fn free() -> Self {
237        let free = Fee { send_sir: 0, send_not_sir: 0, execution: 0 };
238        RuntimeFeesConfig {
239            action_receipt_creation_config: free.clone(),
240            data_receipt_creation_config: DataReceiptCreationConfig {
241                base_cost: free.clone(),
242                cost_per_byte: free.clone(),
243            },
244            action_creation_config: ActionCreationConfig {
245                create_account_cost: free.clone(),
246                deploy_contract_cost: free.clone(),
247                deploy_contract_cost_per_byte: free.clone(),
248                function_call_cost: free.clone(),
249                function_call_cost_per_byte: free.clone(),
250                transfer_cost: free.clone(),
251                stake_cost: free.clone(),
252                add_key_cost: AccessKeyCreationConfig {
253                    full_access_cost: free.clone(),
254                    function_call_cost: free.clone(),
255                    function_call_cost_per_byte: free.clone(),
256                },
257                delete_key_cost: free.clone(),
258                delete_account_cost: free,
259            },
260            storage_usage_config: StorageUsageConfig {
261                num_bytes_account: 0,
262                num_extra_bytes_record: 0,
263            },
264            burnt_gas_reward: Rational::from_integer(0),
265            pessimistic_gas_price_inflation_ratio: Rational::from_integer(0),
266        }
267    }
268
269    /// The minimum amount of gas required to create and execute a new receipt with a function call
270    /// action.
271    /// This amount is used to determine how many receipts can be created, send and executed for
272    /// some amount of prepaid gas using function calls.
273    pub fn min_receipt_with_function_call_gas(&self) -> Gas {
274        self.action_receipt_creation_config.min_send_and_exec_fee()
275            + self.action_creation_config.function_call_cost.min_send_and_exec_fee()
276    }
277}
278
279#[cfg(test)]
280mod tests {
281    use super::*;
282
283    #[test]
284    fn test_data_roundtrip_is_more_expensive() {
285        // We have an assumption that the deepest receipts we can create is by creating recursive
286        // function call promises (calling function call from a function call).
287        // If the cost of a data receipt is cheaper than the cost of a function call, then it's
288        // possible to create a promise with a dependency which will be executed in two blocks that
289        // is cheaper than just two recursive function calls.
290        // That's why we need to enforce that the cost of the data receipt is not less than a
291        // function call. Otherwise we'd have to modify the way we compute the maximum depth.
292        let transaction_costs = RuntimeFeesConfig::default();
293        assert!(
294            transaction_costs.data_receipt_creation_config.base_cost.min_send_and_exec_fee()
295                >= transaction_costs.min_receipt_with_function_call_gas(),
296            "The data receipt cost can't be larger than the cost of a receipt with a function call"
297        );
298    }
299}