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}