Fixes and improvements for PoC-1 Testnet (#143)

* Fix initialisations and add a test.

* Fix test.

* Fix overflow bug.

* Minor refactoring and fixes.

* Fix vote threshold.

* Add note.

* Fixes for latest rust and the readme.

* Better readme.

* An extra validator for PoC-1

* Update README.

* PoC-1 bootnodes.

* don't return async::notready for messages without scheduling wakeup

* Fix endowed account

* give polkadot control over round proposer based on random seed

* address grumbles.
This commit is contained in:
Gav Wood
2018-05-07 15:25:47 +02:00
committed by GitHub
parent 353d9438c8
commit ff93bc2a79
10 changed files with 86 additions and 23 deletions
+8 -4
View File
@@ -31,9 +31,6 @@ extern crate substrate_state_machine as state_machine;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
#[macro_use]
extern crate log;
#[cfg(test)] #[cfg(test)]
extern crate substrate_keyring as keyring; extern crate substrate_keyring as keyring;
@@ -42,7 +39,7 @@ use client::Client;
use polkadot_executor::Executor as LocalDispatch; use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor}; use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
use state_machine::OverlayedChanges; use state_machine::OverlayedChanges;
use primitives::{AccountId, BlockId, Index, SessionKey, Timestamp}; use primitives::{AccountId, BlockId, Hash, Index, SessionKey, Timestamp};
use primitives::parachain::DutyRoster; use primitives::parachain::DutyRoster;
use runtime::{Block, Header, UncheckedExtrinsic, Extrinsic, Call, TimestampCall}; use runtime::{Block, Header, UncheckedExtrinsic, Extrinsic, Call, TimestampCall};
@@ -126,6 +123,9 @@ pub trait PolkadotApi {
/// Get validators at a given block. /// Get validators at a given block.
fn validators(&self, at: &Self::CheckedBlockId) -> Result<Vec<AccountId>>; fn validators(&self, at: &Self::CheckedBlockId) -> Result<Vec<AccountId>>;
/// Get the value of the randomness beacon at a given block.
fn random_seed(&self, at: &Self::CheckedBlockId) -> Result<Hash>;
/// Get the authority duty roster at a block. /// Get the authority duty roster at a block.
fn duty_roster(&self, at: &Self::CheckedBlockId) -> Result<DutyRoster>; fn duty_roster(&self, at: &Self::CheckedBlockId) -> Result<DutyRoster>;
@@ -191,6 +191,10 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
with_runtime!(self, at, ::runtime::Session::validators) with_runtime!(self, at, ::runtime::Session::validators)
} }
fn random_seed(&self, at: &CheckedId) -> Result<Hash> {
with_runtime!(self, at, ::runtime::System::random_seed)
}
fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> { fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> {
// duty roster can only be queried at the start of a block, // duty roster can only be queried at the start of a block,
// so we create a dummy. // so we create a dummy.
+1 -1
View File
@@ -56,6 +56,6 @@ args:
- chain: - chain:
long: chain long: chain
value_name: CHAIN_SPEC value_name: CHAIN_SPEC
help: Specify the chain specification (one of dev or poc-1) help: Specify the chain specification (one of dev, local or poc-1)
takes_value: true takes_value: true
subcommands: subcommands:
+4 -2
View File
@@ -126,13 +126,15 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
} }
match matches.value_of("chain") { match matches.value_of("chain") {
Some("poc-1") => config.chain_spec = ChainSpec::PoC1Testnet,
Some("dev") => config.chain_spec = ChainSpec::Development, Some("dev") => config.chain_spec = ChainSpec::Development,
Some("local") => config.chain_spec = ChainSpec::LocalTestnet,
Some("poc-1") => config.chain_spec = ChainSpec::PoC1Testnet,
None => (), None => (),
Some(unknown) => panic!("Invalid chain name: {}", unknown), Some(unknown) => panic!("Invalid chain name: {}", unknown),
} }
info!("Chain specification: {}", match config.chain_spec { info!("Chain specification: {}", match config.chain_spec {
ChainSpec::Development => "Local Development", ChainSpec::Development => "Development",
ChainSpec::LocalTestnet => "Local Testnet",
ChainSpec::PoC1Testnet => "PoC-1 Testnet", ChainSpec::PoC1Testnet => "PoC-1 Testnet",
}); });
+15
View File
@@ -495,6 +495,7 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N>
let checked_id = self.client.check_id(BlockId::Hash(parent_hash))?; let checked_id = self.client.check_id(BlockId::Hash(parent_hash))?;
let duty_roster = self.client.duty_roster(&checked_id)?; let duty_roster = self.client.duty_roster(&checked_id)?;
let random_seed = self.client.random_seed(&checked_id)?;
let group_info = make_group_info(duty_roster, authorities)?; let group_info = make_group_info(duty_roster, authorities)?;
let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash)); let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash));
@@ -510,6 +511,7 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N>
parent_hash, parent_hash,
parent_number: parent_header.number, parent_number: parent_header.number,
parent_id: checked_id, parent_id: checked_id,
random_seed,
local_key: sign_with, local_key: sign_with,
client: self.client.clone(), client: self.client.clone(),
transaction_pool: self.transaction_pool.clone(), transaction_pool: self.transaction_pool.clone(),
@@ -533,6 +535,7 @@ pub struct Proposer<C: PolkadotApi, R> {
parent_hash: HeaderHash, parent_hash: HeaderHash,
parent_number: BlockNumber, parent_number: BlockNumber,
parent_id: C::CheckedBlockId, parent_id: C::CheckedBlockId,
random_seed: Hash,
client: Arc<C>, client: Arc<C>,
local_key: Arc<ed25519::Pair>, local_key: Arc<ed25519::Pair>,
transaction_pool: Arc<Mutex<TransactionPool>>, transaction_pool: Arc<Mutex<TransactionPool>>,
@@ -561,6 +564,7 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
let mut pool = self.transaction_pool.lock(); let mut pool = self.transaction_pool.lock();
let mut unqueue_invalid = Vec::new(); let mut unqueue_invalid = Vec::new();
let mut pending_size = 0; let mut pending_size = 0;
pool.cull(None, readiness_evaluator.clone());
for pending in pool.pending(readiness_evaluator.clone()) { for pending in pool.pending(readiness_evaluator.clone()) {
// skip and cull transactions which are too large. // skip and cull transactions which are too large.
if pending.encoded_size() > MAX_TRANSACTIONS_SIZE { if pending.encoded_size() > MAX_TRANSACTIONS_SIZE {
@@ -624,6 +628,16 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
Box::new(self.delay.clone().map_err(Error::from).and_then(move |_| evaluated)) Box::new(self.delay.clone().map_err(Error::from).and_then(move |_| evaluated))
} }
fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId {
use primitives::uint::U256;
let len: U256 = authorities.len().into();
let offset = U256::from_big_endian(&self.random_seed.0) % len;
let offset = offset.low_u64() as usize + round_number;
authorities[offset % authorities.len()].clone()
}
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) { fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) {
use bft::generic::Misbehavior as GenericMisbehavior; use bft::generic::Misbehavior as GenericMisbehavior;
use primitives::bft::{MisbehaviorKind, MisbehaviorReport}; use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
@@ -634,6 +648,7 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
let mut next_index = { let mut next_index = {
let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client); let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client);
pool.cull(None, readiness_evaluator.clone());
let cur_index = pool.pending(readiness_evaluator) let cur_index = pool.pending(readiness_evaluator)
.filter(|tx| tx.as_ref().as_ref().signed == local_id) .filter(|tx| tx.as_ref().as_ref().signed == local_id)
.last() .last()
+24
View File
@@ -27,6 +27,10 @@ extern crate substrate_runtime_support as runtime_support;
#[macro_use] #[macro_use]
extern crate substrate_runtime_primitives as runtime_primitives; extern crate substrate_runtime_primitives as runtime_primitives;
#[cfg(feature = "std")]
#[macro_use]
extern crate hex_literal;
#[cfg(test)] #[cfg(test)]
extern crate substrate_serializer; extern crate substrate_serializer;
@@ -298,4 +302,24 @@ mod tests {
println!("{}", HexDisplay::from(&v)); println!("{}", HexDisplay::from(&v));
assert_eq!(UncheckedExtrinsic::decode(&mut &v[..]).unwrap(), tx); assert_eq!(UncheckedExtrinsic::decode(&mut &v[..]).unwrap(), tx);
} }
#[test]
fn serialize_checked() {
let xt = Extrinsic {
signed: hex!["0d71d1a9cad6f2ab773435a7dec1bac019994d05d1dd5eb3108211dcf25c9d1e"],
index: 0u64,
function: Call::CouncilVoting(council::voting::Call::propose(Box::new(
PrivCall::Consensus(consensus::PrivCall::set_code(
vec![]
))
))),
};
let v = Slicable::encode(&xt);
let data = hex!["e00000000d71d1a9cad6f2ab773435a7dec1bac019994d05d1dd5eb3108211dcf25c9d1e000000000000000007000000000000006369D39D892B7B87A6769F90E14C618C2B84EBB293E2CC46640136E112C078C75619AC2E0815F2511568736623C055156C8FC427CE2AEE4AE2838F86EFE80208"];
let uxt: UncheckedExtrinsic = Slicable::decode(&mut &data[..]).unwrap();
assert_eq!(uxt.extrinsic, xt);
assert_eq!(Extrinsic::decode(&mut &v[..]).unwrap(), xt);
}
} }
Binary file not shown.
+3 -1
View File
@@ -23,8 +23,10 @@ pub use network::NetworkConfiguration;
/// The chain specification (this should eventually be replaced by a more general JSON-based chain /// The chain specification (this should eventually be replaced by a more general JSON-based chain
/// specification). /// specification).
pub enum ChainSpec { pub enum ChainSpec {
/// Whatever the current runtime is, with simple Alice/Bob auths. /// Whatever the current runtime is, with just Alice as an auth.
Development, Development,
/// Whatever the current runtime is, with simple Alice/Bob auths.
LocalTestnet,
/// The PoC-1 testnet. /// The PoC-1 testnet.
PoC1Testnet, PoC1Testnet,
} }
+31 -15
View File
@@ -56,7 +56,7 @@ use parking_lot::Mutex;
use tokio_core::reactor::Core; use tokio_core::reactor::Core;
use codec::Slicable; use codec::Slicable;
use primitives::block::{Id as BlockId, Extrinsic, ExtrinsicHash, HeaderHash}; use primitives::block::{Id as BlockId, Extrinsic, ExtrinsicHash, HeaderHash};
use primitives::hashing; use primitives::{AuthorityId, hashing};
use transaction_pool::TransactionPool; use transaction_pool::TransactionPool;
use substrate_executor::NativeExecutor; use substrate_executor::NativeExecutor;
use polkadot_executor::Executor as LocalDispatch; use polkadot_executor::Executor as LocalDispatch;
@@ -98,8 +98,9 @@ impl network::TransactionPool for TransactionPoolAdapter {
} }
}; };
let id = self.client.check_id(BlockId::Hash(best_block)).expect("Best block is always valid; qed."); let id = self.client.check_id(BlockId::Hash(best_block)).expect("Best block is always valid; qed.");
let ready = transaction_pool::Ready::create(id, &*self.client); let mut pool = self.pool.lock();
self.pool.lock().pending(ready).map(|t| { pool.cull(None, transaction_pool::Ready::create(id, &*self.client));
pool.pending(transaction_pool::Ready::create(id, &*self.client)).map(|t| {
let hash = ::primitives::Hash::from(&t.hash()[..]); let hash = ::primitives::Hash::from(&t.hash()[..]);
let tx = codec::Slicable::encode(t.as_transaction()); let tx = codec::Slicable::encode(t.as_transaction());
(hash, tx) (hash, tx)
@@ -135,9 +136,10 @@ fn poc_1_testnet_config() -> ChainConfig {
hex!["82c39b31a2b79a90f8e66e7a77fdb85a4ed5517f2ae39f6a80565e8ecae85cf5"].into(), hex!["82c39b31a2b79a90f8e66e7a77fdb85a4ed5517f2ae39f6a80565e8ecae85cf5"].into(),
hex!["4de37a07567ebcbf8c64568428a835269a566723687058e017b6d69db00a77e7"].into(), hex!["4de37a07567ebcbf8c64568428a835269a566723687058e017b6d69db00a77e7"].into(),
hex!["063d7787ebca768b7445dfebe7d62cbb1625ff4dba288ea34488da266dd6dca5"].into(), hex!["063d7787ebca768b7445dfebe7d62cbb1625ff4dba288ea34488da266dd6dca5"].into(),
hex!["8101764f45778d4980dadaceee6e8af2517d3ab91ac9bec9cd1714fa5994081c"].into(),
]; ];
let endowed_accounts = vec![ let endowed_accounts = vec![
hex!["24d132eb1a4cbf8e46de22652019f1e07fadd5037a6a057c75dbbfd4641ba85d"].into(), hex!["f295940fa750df68a686fcf4abd4111c8a9c5a5a5a83c4c8639c451a94a7adfd"].into(),
]; ];
let genesis_config = GenesisConfig { let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig { consensus: Some(ConsensusConfig {
@@ -151,7 +153,7 @@ fn poc_1_testnet_config() -> ChainConfig {
}), }),
staking: Some(StakingConfig { staking: Some(StakingConfig {
current_era: 0, current_era: 0,
intentions: vec![], intentions: initial_authorities.clone(),
transaction_fee: 100, transaction_fee: 100,
balances: endowed_accounts.iter().map(|&k|(k, 1u64 << 60)).collect(), balances: endowed_accounts.iter().map(|&k|(k, 1u64 << 60)).collect(),
validator_count: 12, validator_count: 12,
@@ -180,15 +182,15 @@ fn poc_1_testnet_config() -> ChainConfig {
}), }),
parachains: Some(Default::default()), parachains: Some(Default::default()),
}; };
let boot_nodes = Vec::new(); let boot_nodes = vec![
"enode://ce29df27adace5c2a08efc2fd58ce1a2587f2157061e7788861dfef3c0cbf275af8476f93b5f10ecbcd7d6c2fdac109b581502dd7a67a361f9efa7593308bedd@104.211.54.233:30333".into(),
"enode://db86cdf0d653c774cb9f357ba99ee035b2dc3ae4313e93a79a38d9e0089dc5eacdf01a5cab7d41b6a44c83bc78599b76318bc59501f9d62cc6b08cfb74777032@104.211.48.51:30333".into(),
"enode://a9458a01ccc278eab98ee329f529ca3bcb88e13e4e0cda7318a63c6ae704b74eca7c5a05cff106d531cdc41facfbe63540de5f733108fbbbb7d0235131ca39a0@104.211.48.247:30333".into(),
];
ChainConfig { genesis_config, boot_nodes } ChainConfig { genesis_config, boot_nodes }
} }
fn local_testnet_config() -> ChainConfig { fn testnet_config(initial_authorities: Vec<AuthorityId>) -> ChainConfig {
let initial_authorities = vec![
ed25519::Pair::from_seed(b"Alice ").public().into(),
ed25519::Pair::from_seed(b"Bob ").public().into(),
];
let endowed_accounts = vec![ let endowed_accounts = vec![
ed25519::Pair::from_seed(b"Alice ").public().into(), ed25519::Pair::from_seed(b"Alice ").public().into(),
ed25519::Pair::from_seed(b"Bob ").public().into(), ed25519::Pair::from_seed(b"Bob ").public().into(),
@@ -222,15 +224,15 @@ fn local_testnet_config() -> ChainConfig {
minimum_deposit: 10, minimum_deposit: 10,
}), }),
council: Some(CouncilConfig { council: Some(CouncilConfig {
active_council: vec![], active_council: endowed_accounts.iter().filter(|a| initial_authorities.iter().find(|b| a == b).is_none()).map(|a| (a.clone(), 1000000)).collect(),
candidacy_bond: 10, candidacy_bond: 10,
voter_bond: 2, voter_bond: 2,
present_slash_per_voter: 1, present_slash_per_voter: 1,
carry_count: 4, carry_count: 4,
presentation_duration: 10, presentation_duration: 10,
approval_voting_period: 20, approval_voting_period: 20,
term_duration: 40, term_duration: 1000000,
desired_seats: 0, desired_seats: (endowed_accounts.len() - initial_authorities.len()) as u32,
inactive_grace_period: 1, inactive_grace_period: 1,
cooloff_period: 75, cooloff_period: 75,
@@ -242,6 +244,19 @@ fn local_testnet_config() -> ChainConfig {
ChainConfig { genesis_config, boot_nodes } ChainConfig { genesis_config, boot_nodes }
} }
fn development_config() -> ChainConfig {
testnet_config(vec![
ed25519::Pair::from_seed(b"Alice ").public().into(),
])
}
fn local_testnet_config() -> ChainConfig {
testnet_config(vec![
ed25519::Pair::from_seed(b"Alice ").public().into(),
ed25519::Pair::from_seed(b"Bob ").public().into(),
])
}
impl Service { impl Service {
/// Creates and register protocol with the network service /// Creates and register protocol with the network service
pub fn new(mut config: Configuration) -> Result<Service, error::Error> { pub fn new(mut config: Configuration) -> Result<Service, error::Error> {
@@ -264,7 +279,8 @@ impl Service {
} }
let ChainConfig { genesis_config, boot_nodes } = match config.chain_spec { let ChainConfig { genesis_config, boot_nodes } = match config.chain_spec {
ChainSpec::Development => local_testnet_config(), ChainSpec::Development => development_config(),
ChainSpec::LocalTestnet => local_testnet_config(),
ChainSpec::PoC1Testnet => poc_1_testnet_config(), ChainSpec::PoC1Testnet => poc_1_testnet_config(),
}; };
config.network.boot_nodes.extend(boot_nodes); config.network.boot_nodes.extend(boot_nodes);