Skip to content

Commit

Permalink
refactor: reintroduce structure for storing RuntimeConfigs (#4779)
Browse files Browse the repository at this point in the history
* Introduce structure for storing RuntimeConfigs

* remove accidentially added files

* remove file

* temporary fix

* fix config store

* put store to nightshade runtime

* remove comment

* minor fix

* minor fix

* minor fix

* minor fix

* minor fix

* minor fix

* minor fix

* minor fix

* minor fix

* fix

* add readme

* compilation fix

* add hash test

* fix

* fix

* temporary fix

* create test store

* fix

* fix

* fix initializing

* set default impl

* improve test

* fix TestEnv

* minor fix

* remove not compatible and useless test

* fix account names according to restriction

* address suggestion

* Initialize config store using chain id

* update store for state-viewer

* add comment

* minor fix

* apply suggestions

* minor fixes

* update comment

* mark as deprecated

* test

* fix deprecation
  • Loading branch information
Longarithm committed Sep 6, 2021
1 parent 9abfeed commit b84b3fc
Show file tree
Hide file tree
Showing 28 changed files with 672 additions and 314 deletions.
4 changes: 4 additions & 0 deletions core/primitives/src/runtime/config.rs
Expand Up @@ -55,6 +55,8 @@ impl RuntimeConfig {
/// but i) may have it’s `max_gas_burnt_view` limit adjusted and ii) provides
/// a method which returns configuration with adjustments done through protocol
/// version upgrades.
/// TODO #4649: deprecated after RuntimeConfigStore creation, remove it
#[deprecated(since = "#4779", note = "All usages should be replaced with RuntimeConfigStore")]
pub struct ActualRuntimeConfig {
/// The runtime configuration taken from the genesis file but with possibly
/// modified `max_gas_burnt_view` limit.
Expand All @@ -64,6 +66,7 @@ pub struct ActualRuntimeConfig {
with_lower_storage_cost: Arc<RuntimeConfig>,
}

#[allow(deprecated)]
impl ActualRuntimeConfig {
/// Constructs a new object from specified genesis runtime config.
///
Expand Down Expand Up @@ -132,6 +135,7 @@ mod tests {
fn test_lower_cost() {
let config = RuntimeConfig::default();
let default_amount = config.storage_amount_per_byte;
#[allow(deprecated)]
let config = ActualRuntimeConfig::new(config);
let base_cfg = config.for_protocol_version(0);
let new_cfg = config.for_protocol_version(ProtocolVersion::MAX);
Expand Down
153 changes: 153 additions & 0 deletions core/primitives/src/runtime/config_store.rs
@@ -0,0 +1,153 @@
use crate::runtime::config::RuntimeConfig;
use crate::types::ProtocolVersion;
use std::collections::BTreeMap;
use std::iter::FromIterator;
use std::ops::Bound;
use std::sync::Arc;

macro_rules! include_config {
($file:expr) => {
include_bytes!(concat!("../../../../nearcore/res/runtime_configs/", $file))
};
}

/// Stores pairs of protocol versions for which runtime config was updated and
/// the new runtime config in bytes.
/// Protocol versions are given in increasing order. First one is always 0, so that each version is
/// mapped to some config.
static CONFIGS: [(ProtocolVersion, &[u8]); 2] =
[(0, include_config!("29.json")), (42, include_config!("42.json"))];

/// Stores runtime config for each protocol version where it was updated.
#[derive(Debug)]
pub struct RuntimeConfigStore {
/// Maps protocol version to the config.
store: BTreeMap<ProtocolVersion, Arc<RuntimeConfig>>,
}

impl RuntimeConfigStore {
/// Constructs a new store.
///
/// If genesis_runtime_config is Some, configs for protocol versions 0 and 42 are overridden by
/// this config and config with lowered storage cost, respectively.
/// This is done to preserve compatibility with previous implementation, where we updated
/// runtime config by sequential modifications to the genesis runtime config.
/// TODO #4775: introduce new protocol version to have the same runtime config for all chains
pub fn new(genesis_runtime_config: Option<&RuntimeConfig>) -> Self {
let mut store =
BTreeMap::from_iter(CONFIGS.iter().cloned().map(|(protocol_version, config_bytes)| {
(protocol_version, Arc::new(serde_json::from_slice(config_bytes).unwrap()))
}));

if let Some(runtime_config) = genesis_runtime_config {
let mut config = runtime_config.clone();
store.insert(0, Arc::new(config.clone()));

config.storage_amount_per_byte = 10u128.pow(19);
store.insert(42, Arc::new(config.clone()));
}

Self { store }
}

/// Constructs test store.
pub fn test() -> Self {
Self {
store: BTreeMap::from_iter([(0, Arc::new(RuntimeConfig::default()))].iter().cloned()),
}
}

/// Constructs store with a single config with zero costs.
pub fn free() -> Self {
Self { store: BTreeMap::from_iter([(0, Arc::new(RuntimeConfig::free()))].iter().cloned()) }
}

/// Returns a `RuntimeConfig` for the corresponding protocol version.
pub fn get_config(&self, protocol_version: ProtocolVersion) -> &Arc<RuntimeConfig> {
self.store
.range((Bound::Unbounded, Bound::Included(protocol_version)))
.next_back()
.unwrap_or_else(|| {
panic!("Not found RuntimeConfig for protocol version {}", protocol_version)
})
.1
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::serialize::to_base;
use crate::version::ProtocolFeature::LowerStorageCost;
use near_primitives_core::hash::hash;

const GENESIS_PROTOCOL_VERSION: ProtocolVersion = 29;
const RECEIPTS_DEPTH: u64 = 63;

fn check_config(protocol_version: ProtocolVersion, config_bytes: &[u8]) {
assert_eq!(
RuntimeConfigStore::new(None).get_config(protocol_version).as_ref(),
&serde_json::from_slice::<RuntimeConfig>(config_bytes).unwrap()
);
}

#[test]
fn test_get_config() {
check_config(0, CONFIGS[0].1);
check_config(GENESIS_PROTOCOL_VERSION - 1, CONFIGS[0].1);
check_config(GENESIS_PROTOCOL_VERSION, CONFIGS[0].1);
// First non-trivial version for which runtime config was updated.
check_config(LowerStorageCost.protocol_version(), CONFIGS[1].1);
check_config(ProtocolVersion::MAX, CONFIGS.last().unwrap().1);
}

#[test]
fn test_runtime_config_data() {
let expected_hashes = vec![
"9T3VNaNdGTiZZvuWiymSxtPdwWKNoJmqoTAaZ4JkuSoL",
"E82ThZS7KFjpdKmogbMGPwv8nTztxqgSbuCTPRH73XFh",
];
for (i, (_, config_bytes)) in CONFIGS.iter().enumerate() {
assert_eq!(to_base(&hash(config_bytes)), expected_hashes[i]);
}
}

#[test]
fn test_max_prepaid_gas() {
let store = RuntimeConfigStore::new(None);
for (protocol_version, config) in store.store.iter() {
assert!(
config.wasm_config.limit_config.max_total_prepaid_gas
/ config.transaction_costs.min_receipt_with_function_call_gas()
<= 63,
"The maximum desired depth of receipts for protocol version {} should be at most {}",
protocol_version,
RECEIPTS_DEPTH
);
}
}

#[test]
fn test_lower_cost() {
let store = RuntimeConfigStore::new(None);
let base_cfg = store.get_config(GENESIS_PROTOCOL_VERSION);
let new_cfg = store.get_config(LowerStorageCost.protocol_version());
assert!(base_cfg.storage_amount_per_byte > new_cfg.storage_amount_per_byte);
}

#[test]
fn test_override_account_length() {
// Check that default value is 32.
let base_store = RuntimeConfigStore::new(None);
let base_cfg = base_store.get_config(GENESIS_PROTOCOL_VERSION);
assert_eq!(base_cfg.account_creation_config.min_allowed_top_level_account_length, 32);

let mut cfg = base_cfg.as_ref().clone();
cfg.account_creation_config.min_allowed_top_level_account_length = 0;

// Check that length was changed.
let new_store = RuntimeConfigStore::new(Some(&cfg));
let new_cfg = new_store.get_config(GENESIS_PROTOCOL_VERSION);
assert_eq!(new_cfg.account_creation_config.min_allowed_top_level_account_length, 0);
}
}
6 changes: 4 additions & 2 deletions core/primitives/src/runtime/mod.rs
@@ -1,11 +1,13 @@
pub use near_primitives_core::runtime::fees;
pub use near_primitives_core::runtime::*;

use crate::account::Account;
use crate::runtime::config::RuntimeConfig;
use crate::types::Balance;

pub use near_primitives_core::runtime::*;
pub mod apply_state;
pub mod config;
pub use near_primitives_core::runtime::fees;
pub mod config_store;
pub mod migration_data;

/// Checks if given account has enough balance for storage stake, and returns:
Expand Down
2 changes: 2 additions & 0 deletions genesis-tools/genesis-populate/src/lib.rs
Expand Up @@ -18,6 +18,7 @@ use near_primitives::account::{AccessKey, Account};
use near_primitives::block::{genesis_chunks, Tip};
use near_primitives::contract::ContractCode;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::runtime::config_store::RuntimeConfigStore;
use near_primitives::shard_layout::{account_id_to_shard_id, ShardUId};
use near_primitives::state_record::StateRecord;
use near_primitives::types::chunk_extra::ChunkExtra;
Expand Down Expand Up @@ -70,6 +71,7 @@ impl GenesisBuilder {
vec![],
None,
None,
RuntimeConfigStore::new(Some(&genesis.config.runtime_config)),
);
Self {
home_dir: home_dir.to_path_buf(),
Expand Down
25 changes: 21 additions & 4 deletions integration-tests/src/genesis_helpers.rs
Expand Up @@ -6,6 +6,7 @@ use near_chain::{Chain, ChainGenesis, DoomslugThresholdMode};
use near_chain_configs::Genesis;
use near_primitives::block::{Block, BlockHeader};
use near_primitives::hash::CryptoHash;
use near_primitives::runtime::config_store::RuntimeConfigStore;
use near_store::test_utils::create_test_store;
use nearcore::NightshadeRuntime;

Expand All @@ -19,8 +20,16 @@ pub fn genesis_header(genesis: &Genesis) -> BlockHeader {
let dir = tempdir().unwrap();
let store = create_test_store();
let chain_genesis = ChainGenesis::from(genesis);
let runtime =
Arc::new(NightshadeRuntime::new(dir.path(), store, genesis, vec![], vec![], None, None));
let runtime = Arc::new(NightshadeRuntime::new(
dir.path(),
store,
genesis,
vec![],
vec![],
None,
None,
RuntimeConfigStore::test(),
));
let chain = Chain::new(runtime, &chain_genesis, DoomslugThresholdMode::TwoThirds).unwrap();
chain.genesis().clone()
}
Expand All @@ -30,8 +39,16 @@ pub fn genesis_block(genesis: &Genesis) -> Block {
let dir = tempdir().unwrap();
let store = create_test_store();
let chain_genesis = ChainGenesis::from(genesis);
let runtime =
Arc::new(NightshadeRuntime::new(dir.path(), store, genesis, vec![], vec![], None, None));
let runtime = Arc::new(NightshadeRuntime::new(
dir.path(),
store,
genesis,
vec![],
vec![],
None,
None,
RuntimeConfigStore::test(),
));
let mut chain = Chain::new(runtime, &chain_genesis, DoomslugThresholdMode::TwoThirds).unwrap();
chain.get_block(&chain.genesis().hash().clone()).unwrap().clone()
}
5 changes: 5 additions & 0 deletions integration-tests/tests/client/challenges.rs
Expand Up @@ -24,6 +24,7 @@ use near_primitives::hash::CryptoHash;
use near_primitives::merkle::{merklize, MerklePath, PartialMerkleTree};
use near_primitives::num_rational::Rational;
use near_primitives::receipt::Receipt;
use near_primitives::runtime::config_store::RuntimeConfigStore;
use near_primitives::serialize::BaseDecode;
use near_primitives::sharding::{EncodedShardChunk, ReedSolomonWrapper};
use near_primitives::transaction::SignedTransaction;
Expand Down Expand Up @@ -279,6 +280,7 @@ fn test_verify_chunk_invalid_state_challenge() {
vec![],
None,
None,
RuntimeConfigStore::test(),
))];
let mut env = TestEnv::new_with_runtime(ChainGenesis::test(), 1, 1, runtimes);
let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0");
Expand Down Expand Up @@ -581,6 +583,7 @@ fn test_fishermen_challenge() {
vec![],
None,
None,
RuntimeConfigStore::test(),
))
};
let runtime1 = create_runtime();
Expand Down Expand Up @@ -644,6 +647,7 @@ fn test_challenge_in_different_epoch() {
vec![],
None,
None,
RuntimeConfigStore::test(),
));
let runtime2 = Arc::new(nearcore::NightshadeRuntime::new(
Path::new("."),
Expand All @@ -653,6 +657,7 @@ fn test_challenge_in_different_epoch() {
vec![],
None,
None,
RuntimeConfigStore::test(),
));
let runtimes: Vec<Arc<dyn RuntimeAdapter>> = vec![runtime1, runtime2];
let networks = vec![network_adapter.clone(), network_adapter.clone()];
Expand Down
7 changes: 7 additions & 0 deletions integration-tests/tests/client/process_blocks.rs
Expand Up @@ -41,6 +41,7 @@ use near_primitives::errors::TxExecutionError;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::merkle::verify_hash;
use near_primitives::receipt::DelayedReceiptIndices;
use near_primitives::runtime::config_store::RuntimeConfigStore;
#[cfg(feature = "protocol_feature_simple_nightshade")]
use near_primitives::shard_layout::ShardLayout;
use near_primitives::shard_layout::ShardUId;
Expand Down Expand Up @@ -95,6 +96,7 @@ pub fn create_nightshade_runtimes(genesis: &Genesis, n: usize) -> Vec<Arc<dyn Ru
vec![],
None,
None,
RuntimeConfigStore::test(),
)) as Arc<dyn RuntimeAdapter>
})
.collect()
Expand Down Expand Up @@ -1892,6 +1894,7 @@ fn test_incorrect_validator_key_produce_block() {
vec![],
None,
None,
RuntimeConfigStore::test(),
));
let signer = Arc::new(InMemoryValidatorSigner::from_seed(
"test0".parse().unwrap(),
Expand Down Expand Up @@ -3270,6 +3273,7 @@ mod protocol_feature_restore_receipts_after_fix_tests {
vec![],
None,
None,
RuntimeConfigStore::test(),
);
// TODO #4305: get directly from NightshadeRuntime
let migration_data = load_migration_data(&genesis.config.chain_id);
Expand Down Expand Up @@ -3567,6 +3571,7 @@ mod contract_precompilation_tests {
vec![],
None,
None,
RuntimeConfigStore::test(),
))
})
.collect();
Expand Down Expand Up @@ -3669,6 +3674,7 @@ mod contract_precompilation_tests {
vec![],
None,
None,
RuntimeConfigStore::test(),
))
})
.collect();
Expand Down Expand Up @@ -3750,6 +3756,7 @@ mod contract_precompilation_tests {
vec![],
None,
None,
RuntimeConfigStore::test(),
))
})
.collect();
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/tests/client/runtimes.rs
Expand Up @@ -19,6 +19,7 @@ use near_primitives::block::{Approval, ApprovalInner};
use near_primitives::block_header::ApprovalType;
use near_primitives::hash::hash;
use near_primitives::network::PeerId;
use near_primitives::runtime::config_store::RuntimeConfigStore;
#[cfg(feature = "protocol_feature_block_header_v3")]
use near_primitives::sharding::ShardChunkHeaderInner;
use near_primitives::sharding::{PartialEncodedChunk, ShardChunkHeader};
Expand All @@ -40,6 +41,7 @@ pub fn create_nightshade_runtimes(genesis: &Genesis, n: usize) -> Vec<Arc<dyn Ru
vec![],
None,
None,
RuntimeConfigStore::test(),
)) as Arc<dyn RuntimeAdapter>
})
.collect()
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/tests/client/sandbox.rs
Expand Up @@ -6,6 +6,7 @@ use near_chain_configs::Genesis;
use near_client::test_utils::TestEnv;
use near_crypto::{InMemorySigner, KeyType};
use near_primitives::account::Account;
use near_primitives::runtime::config_store::RuntimeConfigStore;
use near_primitives::serialize::{from_base64, to_base64};
use near_primitives::state_record::StateRecord;
use near_primitives::transaction::{
Expand All @@ -31,6 +32,7 @@ fn test_setup() -> (TestEnv, InMemorySigner) {
vec![],
None,
None,
RuntimeConfigStore::test(),
)) as Arc<dyn RuntimeAdapter>],
);
let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0");
Expand Down

0 comments on commit b84b3fc

Please sign in to comment.