Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
give polkadot control over round proposer based on random seed
Browse files Browse the repository at this point in the history
  • Loading branch information
rphmeier committed May 7, 2018
1 parent aa7b42c commit 0ea5dc6
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 19 deletions.
12 changes: 8 additions & 4 deletions polkadot/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ extern crate substrate_state_machine as state_machine;
#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate log;

#[cfg(test)]
extern crate substrate_keyring as keyring;

Expand All @@ -42,7 +39,7 @@ use client::Client;
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
use state_machine::OverlayedChanges;
use primitives::{AccountId, BlockId, Index, SessionKey, Timestamp};
use primitives::{AccountId, BlockId, Hash, Index, SessionKey, Timestamp};
use primitives::parachain::DutyRoster;
use runtime::{Block, Header, UncheckedExtrinsic, Extrinsic, Call, TimestampCall};

Expand Down Expand Up @@ -126,6 +123,9 @@ pub trait PolkadotApi {
/// Get validators at a given block.
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.
fn duty_roster(&self, at: &Self::CheckedBlockId) -> Result<DutyRoster>;

Expand Down Expand Up @@ -191,6 +191,10 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
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> {
// duty roster can only be queried at the start of a block,
// so we create a dummy.
Expand Down
13 changes: 13 additions & 0 deletions polkadot/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 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 table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash));
Expand All @@ -510,6 +511,7 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N>
parent_hash,
parent_number: parent_header.number,
parent_id: checked_id,
random_seed,
local_key: sign_with,
client: self.client.clone(),
transaction_pool: self.transaction_pool.clone(),
Expand All @@ -533,6 +535,7 @@ pub struct Proposer<C: PolkadotApi, R> {
parent_hash: HeaderHash,
parent_number: BlockNumber,
parent_id: C::CheckedBlockId,
random_seed: Hash,
client: Arc<C>,
local_key: Arc<ed25519::Pair>,
transaction_pool: Arc<Mutex<TransactionPool>>,
Expand Down Expand Up @@ -625,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))
}

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)>) {
use bft::generic::Misbehavior as GenericMisbehavior;
use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
Expand Down
26 changes: 11 additions & 15 deletions substrate/bft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,16 @@ pub trait Proposer {

/// Create a proposal.
fn propose(&self) -> Self::Create;

/// Evaluate proposal. True means valid.
// TODO: change this to a future.
fn evaluate(&self, proposal: &Block) -> Self::Evaluate;

/// Import witnessed misbehavior.
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, Misbehavior)>);

/// Determine the proposer for a given round. This should be a deterministic function
/// with consistent results across all authorities.
fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId;
}

/// Block import trait.
Expand Down Expand Up @@ -189,20 +194,7 @@ impl<P: Proposer> generic::Context for BftInstance<P> {
}

fn round_proposer(&self, round: usize) -> AuthorityId {
use primitives::hashing::blake2_256;

// repeat blake2_256 on parent hash round + 1 times.
// use as index into authorities vec.
// TODO: parent hash is really insecure as a randomness beacon as
// the prior can easily influence the block hash.
let hashed = (0..round + 1).fold(self.parent_hash.0, |a, _| {
blake2_256(&a[..])
});

let index = u32::decode(&mut &hashed[..])
.expect("there are more than 4 bytes in a 32 byte hash; qed");

self.authorities[(index as usize) % self.authorities.len()]
self.proposer.round_proposer(round, &self.authorities[..])
}

fn proposal_valid(&self, proposal: &Block) -> Self::EvaluateProposal {
Expand Down Expand Up @@ -649,6 +641,10 @@ mod tests {
}

fn import_misbehavior(&self, _misbehavior: Vec<(AuthorityId, Misbehavior)>) {}

fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId {
authorities[round_number % authorities.len()].clone()
}
}

fn make_service(client: FakeClient)
Expand Down

0 comments on commit 0ea5dc6

Please sign in to comment.