Skip to content

Commit

Permalink
Merge branch 'master' into a-wasm-authoring
Browse files Browse the repository at this point in the history
  • Loading branch information
gavofyork authored Aug 30, 2018
2 parents 1576ad9 + ab08eb7 commit 0357d23
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 621 deletions.
98 changes: 39 additions & 59 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-executor = { git = "https://github.com/paritytech/substrate" }
substrate-state-machine = { git = "https://github.com/paritytech/substrate" }
log = "0.3"

[dev-dependencies]
substrate-keyring = { git = "https://github.com/paritytech/substrate" }
7 changes: 5 additions & 2 deletions api/src/full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
let encoded = block.encode();
let res: Result<()> = call(self, at, "execute_block", &encoded);
match res {
Ok(()) => Ok(true),
Ok(_) => Ok(true),
Err(err) => match err.kind() {
&ErrorKind::Execution(_) => Ok(false),
_ => Err(err)
Expand Down Expand Up @@ -165,7 +165,8 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
}

fn inherent_extrinsics(&self, at: &BlockId, inherent_data: InherentData) -> Result<Vec<UncheckedExtrinsic>> {
inherent_data.using_encoded(|encoded| {
let runtime_version = self.runtime_version_at(at)?;
(inherent_data, runtime_version.spec_version).using_encoded(|encoded| {
call(self, at, "inherent_extrinsics", encoded)
})
}
Expand Down Expand Up @@ -241,6 +242,7 @@ mod tests {

assert_eq!(block.header.number, 1);
assert!(block.header.extrinsics_root != Default::default());
assert!(client.evaluate_block(&id, block).unwrap());
}

#[test]
Expand All @@ -263,6 +265,7 @@ mod tests {

assert_eq!(block.header.number, 1);
assert!(block.header.extrinsics_root != Default::default());
assert!(client.evaluate_block(&id, block).unwrap());
}

#[test]
Expand Down
20 changes: 0 additions & 20 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,9 @@ authors = ["Parity Technologies <[email protected]>"]
description = "Polkadot node implementation in Rust."

[dependencies]
clap = { version = "~2.32", features = ["yaml"] }
error-chain = "0.12"
log = "0.3"
slog = "^2"
lazy_static = "1.0"
tokio = "0.1.7"
futures = "0.1.17"
parking_lot = "0.4"
exit-future = "0.1"
substrate-cli = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-codec = { git = "https://github.com/paritytech/substrate" }
substrate-extrinsic-pool = { git = "https://github.com/paritytech/substrate" }
substrate-network = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-rpc = { git = "https://github.com/paritytech/substrate" }
substrate-rpc-servers = { git = "https://github.com/paritytech/substrate" }
substrate-runtime-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-service = { git = "https://github.com/paritytech/substrate" }
substrate-state-machine = { git = "https://github.com/paritytech/substrate" }
substrate-telemetry = { git = "https://github.com/paritytech/substrate" }
polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
polkadot-service = { path = "../service" }
polkadot-transaction-pool = { path = "../transaction-pool" }

34 changes: 18 additions & 16 deletions consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: Au
}

/// Polkadot proposer factory.
pub struct ProposerFactory<C, N, P> {
pub struct ProposerFactory<C, N, P>
where
P: PolkadotApi + Send + Sync + 'static
{
/// The client instance.
pub client: Arc<P>,
/// The transaction pool.
Expand Down Expand Up @@ -407,7 +410,7 @@ struct LocalDuty {
}

/// The Polkadot proposer logic.
pub struct Proposer<C: PolkadotApi> {
pub struct Proposer<C: PolkadotApi + Send + Sync> {
client: Arc<C>,
dynamic_inclusion: DynamicInclusion,
local_key: Arc<ed25519::Pair>,
Expand Down Expand Up @@ -587,10 +590,10 @@ impl<C> bft::Proposer<Block> for Proposer<C>

let local_id = self.local_key.public().0.into();
let mut next_index = {
let cur_index = self.transaction_pool.cull_and_get_pending(BlockId::hash(self.parent_hash), |pending| pending
.filter(|tx| tx.sender().map(|s| s == local_id).unwrap_or(false))
let cur_index = self.transaction_pool.cull_and_get_pending(&BlockId::hash(self.parent_hash), |pending| pending
.filter(|tx| tx.verified.sender().map(|s| s == local_id).unwrap_or(false))
.last()
.map(|tx| Ok(tx.index()))
.map(|tx| Ok(tx.verified.index()))
.unwrap_or_else(|| self.client.index(&self.parent_id, local_id))
);

Expand Down Expand Up @@ -636,9 +639,8 @@ impl<C> bft::Proposer<Block> for Proposer<C>
index: extrinsic.index,
function: extrinsic.function,
};
let uxt = UncheckedExtrinsic::new(extrinsic, signature);

self.transaction_pool.import_unchecked_extrinsic(BlockId::hash(self.parent_hash), uxt)
let uxt: Vec<u8> = Decode::decode(&mut UncheckedExtrinsic::new(extrinsic, signature).encode().as_slice()).expect("Encoded extrinsic is valid");
self.transaction_pool.submit_one(&BlockId::hash(self.parent_hash), uxt)
.expect("locally signed extrinsic is valid; qed");
}
}
Expand Down Expand Up @@ -720,7 +722,7 @@ impl ProposalTiming {
}

/// Future which resolves upon the creation of a proposal.
pub struct CreateProposal<C: PolkadotApi> {
pub struct CreateProposal<C: PolkadotApi + Send + Sync> {
parent_hash: Hash,
parent_number: BlockNumber,
parent_id: BlockId,
Expand All @@ -732,7 +734,7 @@ pub struct CreateProposal<C: PolkadotApi> {
offline: SharedOfflineTracker,
}

impl<C> CreateProposal<C> where C: PolkadotApi {
impl<C> CreateProposal<C> where C: PolkadotApi + Send + Sync {
fn propose_with(&self, candidates: Vec<CandidateReceipt>) -> Result<Block, Error> {
use polkadot_api::BlockBuilder;
use runtime_primitives::traits::{Hash as HashT, BlakeTwo256};
Expand Down Expand Up @@ -767,18 +769,18 @@ impl<C> CreateProposal<C> where C: PolkadotApi {

{
let mut unqueue_invalid = Vec::new();
let result = self.transaction_pool.cull_and_get_pending(BlockId::hash(self.parent_hash), |pending_iterator| {
let result = self.transaction_pool.cull_and_get_pending(&BlockId::hash(self.parent_hash), |pending_iterator| {
let mut pending_size = 0;
for pending in pending_iterator {
if pending_size + pending.encoded_size() >= MAX_TRANSACTIONS_SIZE { break }
if pending_size + pending.verified.encoded_size() >= MAX_TRANSACTIONS_SIZE { break }

match block_builder.push_extrinsic(pending.primitive_extrinsic()) {
match block_builder.push_extrinsic(pending.original.clone()) {
Ok(()) => {
pending_size += pending.encoded_size();
pending_size += pending.verified.encoded_size();
}
Err(e) => {
trace!(target: "transaction-pool", "Invalid transaction: {}", e);
unqueue_invalid.push(pending.hash().clone());
unqueue_invalid.push(pending.verified.hash().clone());
}
}
}
Expand Down Expand Up @@ -819,7 +821,7 @@ impl<C> CreateProposal<C> where C: PolkadotApi {
}
}

impl<C> Future for CreateProposal<C> where C: PolkadotApi {
impl<C> Future for CreateProposal<C> where C: PolkadotApi + Send + Sync {
type Item = Block;
type Error = Error;

Expand Down
82 changes: 56 additions & 26 deletions consensus/src/offline_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ use polkadot_primitives::AccountId;
use std::collections::HashMap;
use std::time::{Instant, Duration};

// time before we report a validator.
const REPORT_TIME: Duration = Duration::from_secs(60 * 5);

struct Observed {
last_round_end: Instant,
offline_since: Instant,
}

#[derive(Eq, PartialEq)]
enum Activity {
Offline,
StillOffline(Duration),
Online,
}

impl Observed {
fn new() -> Observed {
let now = Instant::now();
Expand All @@ -38,31 +42,32 @@ impl Observed {
}
}

fn note_round_end(&mut self, was_online: bool) {
let now = Instant::now();

fn note_round_end(&mut self, now: Instant, was_online: Option<bool>) {
self.last_round_end = now;
if was_online {
if let Some(false) = was_online {
self.offline_since = now;
}
}

fn is_active(&self) -> bool {
/// Returns what we have observed about the online/offline state of the validator.
fn activity(&self) -> Activity {
// can happen if clocks are not monotonic
if self.offline_since > self.last_round_end { return true }
self.last_round_end.duration_since(self.offline_since) < REPORT_TIME
if self.offline_since > self.last_round_end { return Activity::Online }
if self.offline_since == self.last_round_end { return Activity::Offline }
Activity::StillOffline(self.last_round_end.duration_since(self.offline_since))
}
}

/// Tracks offline validators and can issue a report for those offline.
pub struct OfflineTracker {
observed: HashMap<AccountId, Observed>,
block_instant: Instant,
}

impl OfflineTracker {
/// Create a new tracker.
pub fn new() -> Self {
OfflineTracker { observed: HashMap::new() }
OfflineTracker { observed: HashMap::new(), block_instant: Instant::now() }
}

/// Note new consensus is starting with the given set of validators.
Expand All @@ -71,23 +76,33 @@ impl OfflineTracker {

let set: HashSet<_> = validators.iter().cloned().collect();
self.observed.retain(|k, _| set.contains(k));

self.block_instant = Instant::now();
}

/// Note that a round has ended.
pub fn note_round_end(&mut self, validator: AccountId, was_online: bool) {
self.observed.entry(validator)
.or_insert_with(Observed::new)
.note_round_end(was_online);
self.observed.entry(validator).or_insert_with(Observed::new);
for (val, obs) in self.observed.iter_mut() {
obs.note_round_end(
self.block_instant,
if val == &validator {
Some(was_online)
} else {
None
}
)
}
}

/// Generate a vector of indices for offline account IDs.
pub fn reports(&self, validators: &[AccountId]) -> Vec<u32> {
validators.iter()
.enumerate()
.filter_map(|(i, v)| if self.is_online(v) {
None
} else {
.filter_map(|(i, v)| if self.is_known_offline_now(v) {
Some(i as u32)
} else {
None
})
.collect()
}
Expand All @@ -101,13 +116,15 @@ impl OfflineTracker {
};

// we must think all validators reported externally are offline.
let thinks_online = self.is_online(v);
!thinks_online
self.is_known_offline_now(v)
})
}

fn is_online(&self, v: &AccountId) -> bool {
self.observed.get(v).map(Observed::is_active).unwrap_or(true)
/// Rwturns true only if we have seen the validator miss the last round. For further
/// rounds where we can't say for sure that they're still offline, we give them the
/// benefit of the doubt.
fn is_known_offline_now(&self, v: &AccountId) -> bool {
self.observed.get(v).map(|o| o.activity() == Activity::Offline).unwrap_or(false)
}
}

Expand All @@ -121,17 +138,30 @@ mod tests {
let v = [0; 32].into();
let v2 = [1; 32].into();
let v3 = [2; 32].into();
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, true);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, true);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0u32; 0]);

tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, true);
tracker.note_round_end(v2, false);
tracker.note_round_end(v3, true);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![1]);

let slash_time = REPORT_TIME + Duration::from_secs(5);
tracker.observed.get_mut(&v).unwrap().offline_since -= slash_time;
tracker.observed.get_mut(&v2).unwrap().offline_since -= slash_time;
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);

assert_eq!(tracker.reports(&[v, v2, v3]), vec![0, 1]);
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, false);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0, 2]);

tracker.note_new_block(&[v, v3]);
tracker.note_new_block(&[v, v2]);
tracker.note_round_end(v, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);
}
}
Loading

0 comments on commit 0357d23

Please sign in to comment.