Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions native-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ without-std = []
runtime-std = { path = "./std", version = "0.1" }
rustc-hex = "1.0"
hex-literal = "0.1.0"
log = "0.3"
3 changes: 3 additions & 0 deletions wasm-runtime/polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ extern crate runtime_std;

#[cfg(feature = "with-std")]
extern crate rustc_hex;
#[cfg(feature = "with-std")]
#[macro_use]
extern crate log;

#[cfg(test)]
#[macro_use]
Expand Down
18 changes: 9 additions & 9 deletions wasm-runtime/polkadot/src/runtime/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn approval_ppm_required() -> u32 {

/// The number of concrete validator approvals required for a proposal to pass.
pub fn approvals_required() -> u32 {
approval_ppm_required() * session::validator_count() as u32 / 1000
approval_ppm_required() * session::validator_count() / 1000
}

pub mod public {
Expand Down Expand Up @@ -152,7 +152,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand All @@ -178,7 +178,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand Down Expand Up @@ -213,7 +213,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand All @@ -239,7 +239,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand All @@ -266,7 +266,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand Down Expand Up @@ -294,7 +294,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand Down Expand Up @@ -324,7 +324,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand All @@ -348,7 +348,7 @@ mod tests {
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3usize);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());

Expand Down
4 changes: 2 additions & 2 deletions wasm-runtime/polkadot/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ pub mod timestamp;
pub mod session;
#[allow(unused)]
pub mod governance;
#[allow(unused)]
pub mod parachains;

// TODO: polkadao
// TODO: parachains


#[cfg(feature = "with-std")]
pub mod genesismap;
143 changes: 143 additions & 0 deletions wasm-runtime/polkadot/src/runtime/parachains.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Main parachains logic. For now this is just the determination of which validators do what.

use runtime_std::mem;
use codec::{Slicable, Joiner};
use support::{Hashable, with_env, storage};
use runtime::session;

const PARACHAIN_COUNT: &[u8] = b"par:cou";

/// Identifier for a chain, either one of a number of parachains or the relay chain.
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(test, derive(Debug))]
pub enum Chain {
/// The relay chain.
Relay,
/// A parachain of the given index.
Parachain(u32),
}

/// The duty roster specifying what jobs each validator must do.
#[derive(Clone, PartialEq)]
#[cfg_attr(test, derive(Default, Debug))]
pub struct DutyRoster {
/// Lookup from validator index to chain on which that validator has a duty to validate.
pub validator_duty: Vec<Chain>,
/// Lookup from validator index to chain on which that validator has a duty to guarantee
/// availability.
pub guarantor_duty: Vec<Chain>,
}

/// Get the number of parachains registered at present.
pub fn parachain_count() -> u32 {
storage::get_or(PARACHAIN_COUNT, 0)
}

/// Calculate the current block's duty roster.
pub fn calculate_duty_roster() -> DutyRoster {
let parachain_count = parachain_count();
let validator_count = session::validator_count() as u32;
let validators_per_parachain = (validator_count - 1) / parachain_count;
let validators_on_relay = validator_count - validators_per_parachain * parachain_count;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means there's a high enough chance for relay chain to get only a single validator. Shouldn't there be at least the same number of validators on relay chain as there is on each parachain?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, validators_on_relay does not seem to be used in the code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's fine even with a single validator; parachains have multiple validators in order to ensure there is some co-validation; all validators on the relay chain can co-validate anyway so the only reason you'd want multiple validators there is some redundancy to avoid empty blocks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed validators_on_relay


let mut roles_val = (0..validator_count).map(|i| match i {
i if i < parachain_count * validators_per_parachain => Chain::Parachain(i / validators_per_parachain as u32),
_ => Chain::Relay,
}).collect::<Vec<_>>();
let mut roles_gua = roles_val.clone();

let h = with_env(|e| e.parent_hash.clone());
let mut seed = vec![].join(&h).join(b"validator_role_pairs").blake2_256();

// shuffle
for i in 0..(validator_count - 1) {
// 8 bytes of entropy used per cycle, 32 bytes entropy per hash
let offset = (i * 8 % 32) as usize;

// number of roles remaining to select from.
let remaining = (validator_count - i) as usize;

// 4 * 2 32-bit ints per 256-bit seed.
let val_index = u32::from_slice(&seed[offset..offset + 4]).expect("using 4 bytes for a 32-byte quantity") as usize % remaining;
let gua_index = u32::from_slice(&seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-byte quantity") as usize % remaining;

if offset == 24 {
// into the last 8 bytes - rehash to gather new entropy
seed = seed.blake2_256();
}

// exchange last item with randomly chosen first.
roles_val.swap(remaining - 1, val_index);
roles_gua.swap(remaining - 1, gua_index);
}

DutyRoster {
validator_duty: roles_val,
guarantor_duty: roles_gua,
}
}

#[cfg(test)]
mod tests {
use super::*;
use runtime_std::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use support::{one, two, with_env};
use primitives::AccountID;
use runtime::{consensus, session};

fn simple_setup() -> TestExternalities {
TestExternalities { storage: map![
twox_128(b"ses:val:len").to_vec() => vec![].join(&8u32),
twox_128(b"par:cou").to_vec() => vec![].join(&2u32)
], }
}

#[test]
fn should_work() {
let mut t = simple_setup();
with_externalities(&mut t, || {
let check_roster = |duty_roster: &DutyRoster| {
assert_eq!(duty_roster.validator_duty.len(), 8);
assert_eq!(duty_roster.guarantor_duty.len(), 8);
for i in 0..2 {
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
}
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
};

with_env(|e| e.parent_hash = [0u8; 32]);
let duty_roster_0 = calculate_duty_roster();
check_roster(&duty_roster_0);

with_env(|e| e.parent_hash = [1u8; 32]);
let duty_roster_1 = calculate_duty_roster();
check_roster(&duty_roster_1);
assert!(duty_roster_0 != duty_roster_1);

with_env(|e| e.parent_hash = [2u8; 32]);
let duty_roster_2 = calculate_duty_roster();
check_roster(&duty_roster_2);
assert!(duty_roster_0 != duty_roster_2);
assert!(duty_roster_1 != duty_roster_2);
});
}
}
4 changes: 2 additions & 2 deletions wasm-runtime/polkadot/src/runtime/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ pub fn length() -> BlockNumber {
}

/// The number of validators currently.
pub fn validator_count() -> usize {
ValidatorStorageVec::count() as usize
pub fn validator_count() -> u32 {
ValidatorStorageVec::count() as u32
}

/// The current era index.
Expand Down
Loading