Skip to content

Commit

Permalink
Fixing small issues when running staking testnet (#1002)
Browse files Browse the repository at this point in the history
* Fix actually using config for consensus params, reduce the lenght of epoch to 60 block to allow fast staking on testnet, fixed issue with validator rotation not propagating properly

* Remove usage of deprecate description(), switch to 60 epoch length in local testnets, remove extra print

* Fix broken test

* Fix runtime: verify correct block producer singature

* Fix client: when going from 2 validators to 1 got underflow

* Fix validator manager: proposals apply for both odd and even epochs

* Remove commented code

* Initial ops changes: docker and run script

* Make sure tests don't wait for sync

* Revise readme for running nodes (#1006)

* Make sure that empty boot nodes still works

* Add an option to initialize testnet with faster block production for dev/test purposes. Modified start_near to initialize testdir/ instead of using default home in cast default home is already used for something.

* Move fast mode constants into constants
  • Loading branch information
ilblackdragon authored Jun 21, 2019
1 parent 629fc27 commit 12d9ef3
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 299 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ target
/tests/hello.wasm
/tests/hello/package-lock.json
/chain/client/tmp_bench
testdir/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Expand Down
12 changes: 6 additions & 6 deletions chain/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//! Block production is done in done in this actor as well (at the moment).
use std::collections::HashMap;
use std::error::Error as StdError;
use std::ops::Sub;
use std::sync::{Arc, RwLock};
use std::time::Instant;
Expand Down Expand Up @@ -391,10 +390,11 @@ impl ClientActor {
let total_validators = validators.len();
let prev_same_bp = self
.runtime_adapter
.get_block_proposer(next_height - 1)
.get_block_proposer(last_height)
.map_err(|err| Error::Other(err.to_string()))?
== block_producer.account_id.clone();
let total_approvals = total_validators - if prev_same_bp { 1 } else { 2 };
// If epoch changed, and before there was 2 validators and now there is 1 - prev_same_bp is false, but total validators right now is 1.
let total_approvals = total_validators - if prev_same_bp || total_validators < 2 { 1 } else { 2 };
if self.approvals.len() < total_approvals
&& self.last_block_processed.elapsed() < self.config.max_block_production_delay
{
Expand Down Expand Up @@ -471,11 +471,11 @@ impl ClientActor {
if was_requested { near_chain::Provenance::SYNC } else { near_chain::Provenance::NONE };
match self.process_block(ctx, block, provenance) {
Ok(_) => NetworkClientResponses::NoResponse,
Err(ref e) if e.is_bad_data() => {
Err(ref err) if err.is_bad_data() => {
NetworkClientResponses::Ban { ban_reason: ReasonForBan::BadBlock }
}
Err(ref e) if e.is_error() => {
error!(target: "client", "Error on receival of block: {}", e.description());
Err(ref err) if err.is_error() => {
error!(target: "client", "Error on receival of block: {}", err);
NetworkClientResponses::NoResponse
}
Err(e) => match e.kind() {
Expand Down
2 changes: 1 addition & 1 deletion chain/network/src/peer_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ impl Actor for PeerManagerActor {
if let Some(server_addr) = self.config.addr {
// TODO: for now crashes if server didn't start.
let listener = TcpListener::bind(&server_addr).unwrap();
info!(target: "network", "Server listening at {}@{}", self.peer_id, server_addr);
info!(target: "info", "Server listening at {}@{}", self.peer_id, server_addr);
ctx.add_message_stream(listener.incoming().map_err(|_| ()).map(InboundTcpConnect::new));
}

Expand Down
2 changes: 1 addition & 1 deletion core/primitives/src/crypto/aggregate_signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ impl Error for LengthError {

impl fmt::Display for LengthError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}, expected {}, got {}", self.description(), self.0, self.1)
write!(f, "{}, expected {}, got {}", self, self.0, self.1)
}
}

Expand Down
89 changes: 0 additions & 89 deletions core/primitives/src/crypto/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,95 +268,6 @@ impl fmt::Display for Signature {
write!(f, "{}", String::from(self))
}
}
//
//pub mod bs64_pub_key_format {
// use std::convert::TryInto;
//
// use serde::{de::Error, Deserialize, Deserializer, Serializer};
//
// use super::PublicKey;
//
// pub fn serialize<S>(public_key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
// where
// S: Serializer,
// {
// serializer.serialize_str(String::from(public_key).as_str())
// }
//
// pub fn deserialize<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
// where
// D: Deserializer<'de>,
// {
// String::deserialize(deserializer)?.as_str().try_into().map_err(Error::custom)
// }
//}
//
//pub mod bs64_secret_key_format {
// use std::convert::TryInto;
//
// use serde::{de::Error, Deserialize, Deserializer, Serializer};
//
// use super::SecretKey;
//
// pub fn serialize<S>(secret_key: &SecretKey, serializer: S) -> Result<S::Ok, S::Error>
// where
// S: Serializer,
// {
// serializer.serialize_str(String::from(secret_key).as_str())
// }
//
// pub fn deserialize<'de, D>(deserializer: D) -> Result<SecretKey, D::Error>
// where
// D: Deserializer<'de>,
// {
// String::deserialize(deserializer)?.as_str().try_into().map_err(Error::custom)
// }
//}
//
//pub mod bs64_signature_format {
// use std::convert::TryInto;
//
// use serde::{de::Error, Deserialize, Deserializer, Serializer};
//
// use super::Signature;
//
// pub fn serialize<S>(signature: &Signature, serializer: S) -> Result<S::Ok, S::Error>
// where
// S: Serializer,
// {
// serializer.serialize_str(String::from(signature).as_str())
// }
//
// pub fn deserialize<'de, D>(deserializer: D) -> Result<Signature, D::Error>
// where
// D: Deserializer<'de>,
// {
// String::deserialize(deserializer)?.as_str().try_into().map_err(Error::custom)
// }
//}
//
//pub mod bs64_serializer {
// use serde::{Deserialize, Deserializer, Serializer};
//
// use crate::serialize::BaseEncoded;
//
// pub fn serialize<T, S>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
// where
// T: BaseEncoded,
// S: Serializer,
// {
// serializer.serialize_str(&t.to_base())
// }
//
// pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
// where
// T: BaseEncoded,
// D: Deserializer<'de>,
// {
// let s = String::deserialize(deserializer)?;
// Ok(T::from_base(&s).unwrap())
// }
//}

#[cfg(test)]
mod tests {
Expand Down
50 changes: 35 additions & 15 deletions near/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ pub const NEAR_TOKEN: Balance = 1_000_000_000_000_000_000;
/// Initial token supply.
pub const INITIAL_TOKEN_SUPPLY: Balance = 1_000_000_000 * NEAR_TOKEN;

/// Expected block production time in secs.
pub const MIN_BLOCK_PRODUCTION_DELAY: u64 = 1;

/// Maximum time to delay block production until skip.
pub const MAX_BLOCK_PRODUCTION_DELAY: u64 = 6;

/// Expected epoch length.
pub const EXPECTED_EPOCH_LENGTH: BlockIndex = (60 * 60 * 12) / MIN_BLOCK_PRODUCTION_DELAY;

/// Fast mode constants for testing/developing.
pub const FAST_MIN_BLOCK_PRODUCTION_DELAY: u64 = 10;
pub const FAST_MAX_BLOCK_PRODUCTION_DELAY: u64 = 100;
pub const FAST_EPOCH_LENGTH: u64 = 10;

pub const CONFIG_FILENAME: &str = "config.json";
pub const GENESIS_CONFIG_FILENAME: &str = "genesis.json";
pub const NODE_KEY_FILE: &str = "node_key.json";
Expand Down Expand Up @@ -90,8 +104,8 @@ impl Default for Consensus {
fn default() -> Self {
Consensus {
min_num_peers: 3,
min_block_production_delay: Duration::from_secs(1),
max_block_production_delay: Duration::from_secs(6),
min_block_production_delay: Duration::from_secs(MIN_BLOCK_PRODUCTION_DELAY),
max_block_production_delay: Duration::from_secs(MAX_BLOCK_PRODUCTION_DELAY),
produce_empty_blocks: true,
}
}
Expand Down Expand Up @@ -165,15 +179,15 @@ impl NearConfig {
client_config: ClientConfig {
chain_id: genesis_config.chain_id.clone(),
rpc_addr: config.rpc.addr.clone(),
min_block_production_delay: Duration::from_millis(100),
max_block_production_delay: Duration::from_millis(2000),
min_block_production_delay: config.consensus.min_block_production_delay,
max_block_production_delay: config.consensus.max_block_production_delay,
block_expected_weight: 1000,
skip_sync_wait: config.network.skip_sync_wait,
sync_check_period: Duration::from_secs(10),
sync_step_period: Duration::from_millis(10),
sync_weight_threshold: 0,
sync_height_threshold: 1,
min_num_peers: 1,
min_num_peers: config.consensus.min_num_peers,
fetch_info_period: Duration::from_millis(100),
log_summary_period: Duration::from_secs(10),
produce_empty_blocks: config.consensus.produce_empty_blocks,
Expand All @@ -195,7 +209,7 @@ impl NearConfig {
.network
.boot_nodes
.split(",")
.map(|chunk| chunk.try_into().unwrap())
.map(|chunk| chunk.try_into().expect("Failed to parse PeerInfo"))
.collect()
},
handshake_timeout: config.network.handshake_timeout,
Expand Down Expand Up @@ -300,7 +314,7 @@ impl GenesisConfig {
block_producers_per_shard: vec![num_validators],
avg_fisherman_per_shard: vec![0],
dynamic_resharding: false,
epoch_length: 10,
epoch_length: FAST_EPOCH_LENGTH,
validators,
accounts,
contracts,
Expand Down Expand Up @@ -338,7 +352,7 @@ impl GenesisConfig {
block_producers_per_shard: vec![num_validators],
avg_fisherman_per_shard: vec![0],
dynamic_resharding: false,
epoch_length: 10,
epoch_length: FAST_EPOCH_LENGTH,
validators,
accounts,
contracts: vec![],
Expand Down Expand Up @@ -383,7 +397,7 @@ pub fn testnet_genesis() -> GenesisConfig {
block_producers_per_shard: vec![4],
avg_fisherman_per_shard: vec![100],
dynamic_resharding: true,
epoch_length: 20000,
epoch_length: EXPECTED_EPOCH_LENGTH,
validators: vec![AccountInfo {
account_id: ".near".to_string(),
public_key: ReadablePublicKey(
Expand All @@ -408,6 +422,7 @@ pub fn init_configs(
chain_id: Option<&str>,
account_id: Option<&str>,
test_seed: Option<&str>,
fast: bool,
) {
fs::create_dir_all(dir).expect("Failed to create directory");
// Check if config already exists in home dir.
Expand All @@ -416,7 +431,7 @@ pub fn init_configs(
let genesis_config = GenesisConfig::from_file(&dir.join(config.genesis_file));
panic!("Found existing config in {} with chain-id = {}. Use unsafe_reset_all to clear the folder.", dir.to_str().unwrap(), genesis_config.chain_id);
}
let chain_id = chain_id.map(|c| c.to_string()).unwrap_or(random_chain_id());
let chain_id = chain_id.and_then(|c| if c.is_empty() { None } else { Some(c.to_string()) }).unwrap_or(random_chain_id());
match chain_id.as_ref() {
"mainnet" => {
// TODO:
Expand All @@ -430,8 +445,8 @@ pub fn init_configs(
config.write_to_file(&dir.join(CONFIG_FILENAME));

// If account id was given, create new key pair for this validator.
if let Some(account_id) = account_id {
let signer = InMemorySigner::new(account_id.to_string());
if let Some(account_id) = account_id.and_then(|x| if x.is_empty() { None } else { Some(x.to_string()) }) {
let signer = InMemorySigner::new(account_id.clone());
info!(target: "near", "Use key {} for {} to stake.", signer.public_key, account_id);
signer.write_to_file(&dir.join(config.validator_key_file));
}
Expand All @@ -446,9 +461,13 @@ pub fn init_configs(
// Create new configuration, key files and genesis for one validator.
let mut config = Config::default();
config.network.skip_sync_wait = true;
if fast {
config.consensus.min_block_production_delay = Duration::from_millis(FAST_MIN_BLOCK_PRODUCTION_DELAY);
config.consensus.max_block_production_delay = Duration::from_millis(FAST_MAX_BLOCK_PRODUCTION_DELAY);
}
config.write_to_file(&dir.join(CONFIG_FILENAME));

let account_id = account_id.unwrap_or("test.near").to_string();
let account_id = account_id.and_then(|x| if x.is_empty() { None } else { Some(x) }).unwrap_or("test.near").to_string();

let signer = if let Some(test_seed) = test_seed {
InMemorySigner::from_seed(&account_id, test_seed)
Expand All @@ -467,7 +486,7 @@ pub fn init_configs(
block_producers_per_shard: vec![1],
avg_fisherman_per_shard: vec![0],
dynamic_resharding: false,
epoch_length: 1000,
epoch_length: if fast { FAST_EPOCH_LENGTH } else { EXPECTED_EPOCH_LENGTH },
validators: vec![AccountInfo {
account_id: account_id.clone(),
public_key: signer.public_key.to_readable(),
Expand Down Expand Up @@ -522,7 +541,7 @@ pub fn create_testnet_configs_from_seeds(
block_producers_per_shard: vec![num_validators],
avg_fisherman_per_shard: vec![0],
dynamic_resharding: false,
epoch_length: 10,
epoch_length: FAST_EPOCH_LENGTH,
validators,
accounts,
contracts: vec![],
Expand Down Expand Up @@ -598,6 +617,7 @@ pub fn load_config(dir: &Path) -> NearConfig {

pub fn load_test_config(seed: &str, port: u16, genesis_config: &GenesisConfig) -> NearConfig {
let mut config = Config::default();
config.network.skip_sync_wait = true;
config.network.addr = format!("0.0.0.0:{}", port);
config.rpc.addr = format!("0.0.0.0:{}", port + 100);
let signer = Arc::new(InMemorySigner::from_seed(seed, seed));
Expand Down
37 changes: 34 additions & 3 deletions near/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::convert::TryInto;
use std::fs;
use std::path::Path;

Expand Down Expand Up @@ -52,8 +53,9 @@ fn main() {
)
.subcommand(SubCommand::with_name("init").about("Initializes NEAR configuration")
.arg(Arg::with_name("chain-id").long("chain-id").takes_value(true).help("Chain ID, by default creates new random"))
.arg(Arg::with_name("account-id").long("account-id").takes_value(true).help("Account ID for initial validator"))
.arg(Arg::with_name("account-id").long("account-id").takes_value(true).help("Account ID for the validator key"))
.arg(Arg::with_name("test-seed").long("test-seed").takes_value(true).help("Specify private key generated from seed (TESTING ONLY)"))
.arg(Arg::with_name("fast").long("fast").takes_value(false).help("Makes block production fast (TESTING ONLY)"))
)
.subcommand(SubCommand::with_name("testnet").about("Setups testnet configuration with all necessary files (validator key, node key, genesis and config)")
.arg(Arg::with_name("v").long("v").takes_value(true).help("Number of validators to initialize the testnet with (default 4)"))
Expand All @@ -62,6 +64,10 @@ fn main() {
)
.subcommand(SubCommand::with_name("run").about("Runs NEAR node")
.arg(Arg::with_name("produce-empty-blocks").long("produce-empty-blocks").help("Set this to false to only produce blocks when there are txs or receipts (default true)").default_value("true").takes_value(true))
.arg(Arg::with_name("boot-nodes").long("boot-nodes").help("Set the boot nodes to bootstrap network from").takes_value(true))
.arg(Arg::with_name("min-peers").long("min-peers").help("Minimum number of peers to start syncing / producing blocks").takes_value(true))
.arg(Arg::with_name("network-addr").long("network-addr").help("Customize network listening address (useful for running multiple nodes on the same machine)").takes_value(true))
.arg(Arg::with_name("rpc-addr").long("rpc-addr").help("Customize RPC listening address (useful for running multiple nodes on the same machine)").takes_value(true))
)
.subcommand(SubCommand::with_name("unsafe_reset_data").about("(unsafe) Remove all the data, effectively resetting node to genesis state (keeps genesis and config)"))
.subcommand(SubCommand::with_name("unsafe_reset_all").about("(unsafe) Remove all the config, keys, data and effectively removing all information about the network"))
Expand All @@ -77,7 +83,8 @@ fn main() {
let chain_id = args.value_of("chain-id");
let account_id = args.value_of("account-id");
let test_seed = args.value_of("test-seed");
init_configs(home_dir, chain_id, account_id, test_seed);
let fast = args.is_present("fast");
init_configs(home_dir, chain_id, account_id, test_seed, fast);
}
("testnet", Some(args)) => {
let num_validators = args
Expand All @@ -97,10 +104,34 @@ fn main() {
// Override some parameters from command line.
if let Some(produce_empty_blocks) = args
.value_of("produce-empty-blocks")
.map(|x| x.parse().expect("Failed to parse boolean"))
.map(|x| x.parse().expect("Failed to parse boolean for produce-empty-blocks"))
{
near_config.client_config.produce_empty_blocks = produce_empty_blocks;
}
if let Some(boot_nodes) = args.value_of("boot-nodes") {
if !boot_nodes.is_empty() {
near_config.network_config.boot_nodes = boot_nodes
.to_string()
.split(",")
.map(|chunk| chunk.try_into().expect("Failed to parse PeerInfo"))
.collect();
}
}
if let Some(min_peers) = args
.value_of("min-peers")
.map(|x| x.parse().expect("Failed to parse number for min-peers"))
{
near_config.client_config.min_num_peers = min_peers;
}
if let Some(network_addr) = args
.value_of("network-addr")
.map(|value| value.parse().expect("Failed to parse an address"))
{
near_config.network_config.addr = Some(network_addr);
}
if let Some(rpc_addr) = args.value_of("rpc-addr") {
near_config.rpc_config.addr = rpc_addr.to_string();
}

let system = System::new("NEAR");
start_with_config(home_dir, near_config);
Expand Down
Loading

0 comments on commit 12d9ef3

Please sign in to comment.