1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
//! Settings of the parameters of the runtime.
use super::parameter_table::InvalidConfigError;
use crate::config_store::INITIAL_TESTNET_CONFIG;
use crate::cost::RuntimeFeesConfig;
use crate::parameter_table::ParameterTable;
use near_account_id::AccountId;
use near_primitives_core::types::{Balance, Gas, ProtocolVersion};
use near_primitives_core::version::PROTOCOL_VERSION;
use std::sync::Arc;
// Lowered promise yield timeout length used in integration tests.
// The resharding tests for yield timeouts take too long to run otherwise.
pub const TEST_CONFIG_YIELD_TIMEOUT_LENGTH: u64 = 10;
/// The structure that holds the parameters of the runtime, mostly economics.
#[derive(Debug, Clone, PartialEq)]
pub struct RuntimeConfig {
/// Action gas costs, storage fees, and economic constants around them.
///
/// This contains parameters that are required by the WASM runtime and the
/// transaction runtime.
pub fees: Arc<RuntimeFeesConfig>,
/// Config of wasm operations, also includes wasm gas costs.
///
/// This contains all the configuration parameters that are only required by
/// the WASM runtime.
pub wasm_config: Arc<crate::vm::Config>,
/// Config that defines rules for account creation.
pub account_creation_config: AccountCreationConfig,
/// The configuration for congestion control.
pub congestion_control_config: CongestionControlConfig,
/// Configuration specific to ChunkStateWitness.
pub witness_config: WitnessConfig,
/// Configuration specific to BandwidthScheduler.
pub bandwidth_scheduler_config: BandwidthSchedulerConfig,
/// Whether receipts should be stored as [StateStoredReceipt].
pub use_state_stored_receipt: bool,
}
impl RuntimeConfig {
pub(crate) fn new(params: &ParameterTable) -> Result<Self, InvalidConfigError> {
RuntimeConfig::try_from(params)
}
pub fn initial_testnet_config() -> RuntimeConfig {
INITIAL_TESTNET_CONFIG
.parse()
.and_then(|params| RuntimeConfig::new(¶ms))
.expect("Failed parsing initial testnet config")
}
pub fn test() -> Self {
Self::test_protocol_version(PROTOCOL_VERSION)
}
pub fn test_protocol_version(protocol_version: ProtocolVersion) -> Self {
let config_store = super::config_store::RuntimeConfigStore::new(None);
let runtime_config = config_store.get_config(protocol_version);
let mut wasm_config = crate::vm::Config::clone(&runtime_config.wasm_config);
// Lower the yield timeout length so that we can observe timeouts in integration tests.
wasm_config.limit_config.yield_timeout_length_in_blocks = TEST_CONFIG_YIELD_TIMEOUT_LENGTH;
RuntimeConfig {
fees: Arc::new(RuntimeFeesConfig::test()),
wasm_config: Arc::new(wasm_config),
account_creation_config: AccountCreationConfig::default(),
congestion_control_config: runtime_config.congestion_control_config,
witness_config: runtime_config.witness_config,
bandwidth_scheduler_config: runtime_config.bandwidth_scheduler_config,
use_state_stored_receipt: runtime_config.use_state_stored_receipt,
}
}
pub fn free() -> Self {
let config_store = super::config_store::RuntimeConfigStore::new(None);
let runtime_config = config_store.get_config(PROTOCOL_VERSION);
let mut wasm_config = crate::vm::Config::clone(&runtime_config.wasm_config);
wasm_config.make_free();
Self {
fees: Arc::new(RuntimeFeesConfig::free()),
wasm_config: Arc::new(wasm_config),
account_creation_config: AccountCreationConfig::default(),
congestion_control_config: runtime_config.congestion_control_config,
witness_config: runtime_config.witness_config,
bandwidth_scheduler_config: runtime_config.bandwidth_scheduler_config,
use_state_stored_receipt: runtime_config.use_state_stored_receipt,
}
}
pub fn storage_amount_per_byte(&self) -> Balance {
self.fees.storage_usage_config.storage_amount_per_byte
}
}
/// The structure describes configuration for creation of new accounts.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountCreationConfig {
/// The minimum length of the top-level account ID that is allowed to be created by any account.
pub min_allowed_top_level_account_length: u8,
/// The account ID of the account registrar. This account ID allowed to create top-level
/// accounts of any valid length.
pub registrar_account_id: AccountId,
}
impl Default for AccountCreationConfig {
fn default() -> Self {
Self {
min_allowed_top_level_account_length: 0,
registrar_account_id: "registrar".parse().unwrap(),
}
}
}
/// The configuration for congestion control.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CongestionControlConfig {
/// How much gas in delayed receipts of a shard is 100% incoming congestion.
///
/// Based on incoming congestion levels, a shard reduces the gas it spends on
/// accepting new transactions instead of working on incoming receipts. Plus,
/// incoming congestion contributes to overall congestion, which reduces how
/// much other shards are allowed to forward to this shard.
pub max_congestion_incoming_gas: Gas,
/// How much gas in outgoing buffered receipts of a shard is 100% congested.
///
/// Outgoing congestion contributes to overall congestion, which reduces how
/// much other shards are allowed to forward to this shard.
pub max_congestion_outgoing_gas: Gas,
/// How much memory space of all delayed and buffered receipts in a shard is
/// considered 100% congested.
///
/// Memory congestion contributes to overall congestion, which reduces how much
/// other shards are allowed to forward to this shard.
///
/// This threshold limits memory requirements of validators to a degree but it
/// is not a hard guarantee.
pub max_congestion_memory_consumption: u64,
/// How many missed chunks in a row in a shard is considered 100% congested.
pub max_congestion_missed_chunks: u64,
/// The maximum amount of gas attached to receipts a shard can forward to
/// another shard per chunk.
///
/// The actual gas forwarding allowance is a linear interpolation between
/// [MIN_OUTGOING_GAS](CongestionControlConfig::min_outgoing_gas) and
/// [MAX_OUTGOING_GAS](CongestionControlConfig::max_outgoing_gas), or 0 if the receiver is
/// fully congested.
pub max_outgoing_gas: Gas,
/// The minimum gas each shard can send to a shard that is not fully congested.
///
/// The actual gas forwarding allowance is a linear interpolation between
/// [MIN_OUTGOING_GAS](CongestionControlConfig::min_outgoing_gas) and
/// [MAX_OUTGOING_GAS](CongestionControlConfig::max_outgoing_gas), or 0 if the receiver is
/// fully congested.
pub min_outgoing_gas: Gas,
/// How much gas the chosen allowed shard can send to a 100% congested shard.
///
/// This amount is the absolute minimum of new workload a congested shard has to
/// accept every round. It ensures deadlocks are provably impossible. But in
/// ideal conditions, the gradual reduction of new workload entering the system
/// combined with gradually limited forwarding to congested shards should
/// prevent shards from becoming 100% congested in the first place.
pub allowed_shard_outgoing_gas: Gas,
/// The maximum amount of gas in a chunk spent on converting new transactions to
/// receipts.
///
/// The actual gas forwarding allowance is a linear interpolation between
/// [MIN_OUTGOING_GAS](CongestionControlConfig::min_outgoing_gas) and
/// [MAX_OUTGOING_GAS](CongestionControlConfig::max_outgoing_gas),
/// based on the incoming congestion of the local shard.
/// Additionally, transactions can be rejected if the receiving
/// remote shard is congested more than
/// [REJECT_TX_CONGESTION_THRESHOLD](CongestionControlConfig::reject_tx_congestion_threshold)
/// based on their general congestion level.
pub max_tx_gas: Gas,
/// The minimum amount of gas in a chunk spent on converting new transactions
/// to receipts, as long as the receiving shard is not congested.
///
/// The actual gas forwarding allowance is a linear interpolation between
/// [MIN_OUTGOING_GAS](CongestionControlConfig::min_outgoing_gas) and
/// [MAX_OUTGOING_GAS](CongestionControlConfig::max_outgoing_gas),
/// based on the incoming congestion of the local shard.
/// Additionally, transactions can be rejected if the receiving
/// remote shard is congested more than
/// [REJECT_TX_CONGESTION_THRESHOLD](CongestionControlConfig::reject_tx_congestion_threshold)
/// based on their general congestion level.
pub min_tx_gas: Gas,
/// How much congestion a shard can tolerate before it stops all shards from
/// accepting new transactions with the receiver set to the congested shard.
pub reject_tx_congestion_threshold: f64,
/// The standard size limit for outgoing receipts aimed at a single shard.
/// This limit is pretty small to keep the size of source_receipt_proofs under control.
/// It limits the total sum of outgoing receipts, not individual receipts.
pub outgoing_receipts_usual_size_limit: u64,
/// Large size limit for outgoing receipts to a shard, used when it's safe
/// to send a lot of receipts without making the state witness too large.
/// It limits the total sum of outgoing receipts, not individual receipts.
pub outgoing_receipts_big_size_limit: u64,
}
// The Eq cannot be automatically derived for this class because it contains a
// f64 field. The f64 type does not implement the Eq trait because it's possible
// that NaN != NaN. In the CongestionControlConfig the field should never be NaN
// so it is okay for us to add the Eq trait to it manually.
impl Eq for CongestionControlConfig {}
impl CongestionControlConfig {
/// Creates a config where congestion control is disabled. This config can
/// be used for tests. It can be useful e.g. in tests with missing chunks
/// where we still want to process all transactions.
pub fn test_disabled() -> Self {
let max_value = u64::MAX;
Self {
max_congestion_incoming_gas: Gas::from_gas(max_value),
max_congestion_outgoing_gas: Gas::from_gas(max_value),
max_congestion_memory_consumption: max_value,
max_congestion_missed_chunks: max_value,
max_outgoing_gas: Gas::from_gas(max_value),
min_outgoing_gas: Gas::from_gas(max_value),
allowed_shard_outgoing_gas: Gas::from_gas(max_value),
max_tx_gas: Gas::from_gas(max_value),
min_tx_gas: Gas::from_gas(max_value),
reject_tx_congestion_threshold: 2.0,
outgoing_receipts_usual_size_limit: max_value,
outgoing_receipts_big_size_limit: max_value,
}
}
}
/// Configuration specific to ChunkStateWitness.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct WitnessConfig {
/// Size limit for storage proof generated while executing receipts in a chunk.
/// After this limit is reached we defer execution of any new receipts.
pub main_storage_proof_size_soft_limit: u64,
/// Maximum size of transactions contained inside ChunkStateWitness.
///
/// A witness contains transactions from both the previous chunk and the current one.
/// This parameter limits the sum of sizes of transactions from both of those chunks.
pub combined_transactions_size_limit: usize,
/// Size limit of storage proof used to validate new transactions in ChunkStateWitness.
pub new_transactions_validation_state_size_soft_limit: u64,
}
impl WitnessConfig {
/// Creates a config that effectively disables ChunkStateWitness related limits by setting them
/// to max values. This can be useful for tests and benchmarks.
pub fn test_disabled() -> Self {
Self {
main_storage_proof_size_soft_limit: u64::MAX,
combined_transactions_size_limit: usize::MAX,
new_transactions_validation_state_size_soft_limit: u64::MAX,
}
}
}
/// Configuration specific to BandwidthScheduler
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct BandwidthSchedulerConfig {
/// The maximum amount of data that a shard can send or receive at a single height.
pub max_shard_bandwidth: u64,
/// The maximum amount of bandwidth that can be granted on a single link.
/// Should be at least as big as `max_receipt_size`.
pub max_single_grant: u64,
/// Maximum bandwidth allowance that a link can accumulate.
pub max_allowance: u64,
/// Max value of `base_bandwidth` that is granted on all links by default.
pub max_base_bandwidth: u64,
}
impl BandwidthSchedulerConfig {
/// Creates a config that effectively disables BandwidthScheduler related limits by setting them
/// to max values. This can be useful for tests and benchmarks.
pub fn test_disabled() -> Self {
// Using `u64::MAX` would lead to overflows as these numbers are used in additions and
// multiplications. The values below are still high enough to effectively disable limits.
let one_tb = 1_000_000_000_000;
Self {
max_shard_bandwidth: 100 * one_tb,
max_single_grant: one_tb,
max_allowance: one_tb,
max_base_bandwidth: one_tb,
}
}
}