mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 15:11:02 +00:00
Merge branch 'master' into gav-demo
This commit is contained in:
@@ -9,6 +9,7 @@ parking_lot = "0.4"
|
|||||||
tokio-timer = "0.1.2"
|
tokio-timer = "0.1.2"
|
||||||
ed25519 = { path = "../../substrate/ed25519" }
|
ed25519 = { path = "../../substrate/ed25519" }
|
||||||
error-chain = "0.11"
|
error-chain = "0.11"
|
||||||
|
log = "0.4"
|
||||||
polkadot-api = { path = "../api" }
|
polkadot-api = { path = "../api" }
|
||||||
polkadot-collator = { path = "../collator" }
|
polkadot-collator = { path = "../collator" }
|
||||||
polkadot-primitives = { path = "../primitives" }
|
polkadot-primitives = { path = "../primitives" }
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ extern crate substrate_primitives as primitives;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate error_chain;
|
extern crate error_chain;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -55,9 +58,9 @@ use polkadot_api::{PolkadotApi, BlockBuilder};
|
|||||||
use polkadot_primitives::{Hash, Timestamp};
|
use polkadot_primitives::{Hash, Timestamp};
|
||||||
use polkadot_primitives::block::Block as PolkadotBlock;
|
use polkadot_primitives::block::Block as PolkadotBlock;
|
||||||
use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt};
|
use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt};
|
||||||
use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId};
|
use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId, Number as BlockNumber};
|
||||||
use primitives::AuthorityId;
|
use primitives::AuthorityId;
|
||||||
use transaction_pool::TransactionPool;
|
use transaction_pool::{Ready, TransactionPool};
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
@@ -477,17 +480,19 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N>
|
|||||||
let duty_roster = self.client.duty_roster(&checked_id)?;
|
let duty_roster = self.client.duty_roster(&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, parent_hash));
|
let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash));
|
||||||
let router = self.network.table_router(table.clone());
|
let router = self.network.table_router(table.clone());
|
||||||
|
|
||||||
// TODO [PoC-2]: kick off collation process.
|
// TODO [PoC-2]: kick off collation process.
|
||||||
Ok(Proposer {
|
Ok(Proposer {
|
||||||
parent_hash,
|
parent_hash,
|
||||||
|
parent_number: parent_header.number,
|
||||||
parent_id: checked_id,
|
parent_id: checked_id,
|
||||||
_table: table,
|
local_key: sign_with,
|
||||||
_router: router,
|
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
transaction_pool: self.transaction_pool.clone(),
|
transaction_pool: self.transaction_pool.clone(),
|
||||||
|
_table: table,
|
||||||
|
_router: router,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,8 +508,10 @@ fn current_timestamp() -> Timestamp {
|
|||||||
/// The Polkadot proposer logic.
|
/// The Polkadot proposer logic.
|
||||||
pub struct Proposer<C: PolkadotApi, R> {
|
pub struct Proposer<C: PolkadotApi, R> {
|
||||||
parent_hash: HeaderHash,
|
parent_hash: HeaderHash,
|
||||||
|
parent_number: BlockNumber,
|
||||||
parent_id: C::CheckedBlockId,
|
parent_id: C::CheckedBlockId,
|
||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
|
local_key: Arc<ed25519::Pair>,
|
||||||
transaction_pool: Arc<Mutex<TransactionPool>>,
|
transaction_pool: Arc<Mutex<TransactionPool>>,
|
||||||
_table: Arc<SharedTable>,
|
_table: Arc<SharedTable>,
|
||||||
_router: R,
|
_router: R,
|
||||||
@@ -516,8 +523,6 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
|
|||||||
type Evaluate = Result<bool, Error>;
|
type Evaluate = Result<bool, Error>;
|
||||||
|
|
||||||
fn propose(&self) -> Result<SubstrateBlock, Error> {
|
fn propose(&self) -> Result<SubstrateBlock, Error> {
|
||||||
use transaction_pool::Ready;
|
|
||||||
|
|
||||||
// TODO: handle case when current timestamp behind that in state.
|
// TODO: handle case when current timestamp behind that in state.
|
||||||
let mut block_builder = self.client.build_block(
|
let mut block_builder = self.client.build_block(
|
||||||
&self.parent_id,
|
&self.parent_id,
|
||||||
@@ -565,6 +570,65 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
|
|||||||
fn evaluate(&self, proposal: &SubstrateBlock) -> Result<bool, Error> {
|
fn evaluate(&self, proposal: &SubstrateBlock) -> Result<bool, Error> {
|
||||||
evaluate_proposal(proposal, &*self.client, current_timestamp(), &self.parent_hash, &self.parent_id)
|
evaluate_proposal(proposal, &*self.client, current_timestamp(), &self.parent_hash, &self.parent_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) {
|
||||||
|
use bft::generic::Misbehavior as GenericMisbehavior;
|
||||||
|
use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
|
||||||
|
use polkadot_primitives::transaction::{Function, Transaction, UncheckedTransaction};
|
||||||
|
|
||||||
|
let local_id = self.local_key.public().0;
|
||||||
|
let mut pool = self.transaction_pool.lock();
|
||||||
|
let mut next_nonce = {
|
||||||
|
let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client);
|
||||||
|
|
||||||
|
let cur_nonce = pool.pending(readiness_evaluator)
|
||||||
|
.filter(|tx| tx.as_transaction().transaction.signed == local_id)
|
||||||
|
.last()
|
||||||
|
.map(|tx| Ok(tx.as_transaction().transaction.nonce))
|
||||||
|
.unwrap_or_else(|| self.client.nonce(&self.parent_id, local_id));
|
||||||
|
|
||||||
|
match cur_nonce {
|
||||||
|
Ok(cur_nonce) => cur_nonce + 1,
|
||||||
|
Err(e) => {
|
||||||
|
warn!(target: "consensus", "Error computing next transaction nonce: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (target, misbehavior) in misbehavior {
|
||||||
|
let report = MisbehaviorReport {
|
||||||
|
parent_hash: self.parent_hash,
|
||||||
|
parent_number: self.parent_number,
|
||||||
|
target,
|
||||||
|
misbehavior: match misbehavior {
|
||||||
|
GenericMisbehavior::ProposeOutOfTurn(_, _, _) => continue,
|
||||||
|
GenericMisbehavior::DoublePropose(_, _, _) => continue,
|
||||||
|
GenericMisbehavior::DoublePrepare(round, (h1, s1), (h2, s2))
|
||||||
|
=> MisbehaviorKind::BftDoublePrepare(round as u32, (h1, s1.signature), (h2, s2.signature)),
|
||||||
|
GenericMisbehavior::DoubleCommit(round, (h1, s1), (h2, s2))
|
||||||
|
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tx = Transaction {
|
||||||
|
signed: local_id,
|
||||||
|
nonce: next_nonce,
|
||||||
|
function: Function::ReportMisbehavior(report),
|
||||||
|
};
|
||||||
|
|
||||||
|
next_nonce += 1;
|
||||||
|
|
||||||
|
let message = tx.encode();
|
||||||
|
let signature = self.local_key.sign(&message);
|
||||||
|
let tx = UncheckedTransaction {
|
||||||
|
transaction: tx,
|
||||||
|
signature,
|
||||||
|
};
|
||||||
|
|
||||||
|
pool.import(tx).expect("locally signed transaction is valid; qed");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_proposal<C: PolkadotApi>(
|
fn evaluate_proposal<C: PolkadotApi>(
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ mod tests {
|
|||||||
construct_block(
|
construct_block(
|
||||||
2,
|
2,
|
||||||
block1().1,
|
block1().1,
|
||||||
hex!("c8776c92e8012bf6b3f206448eda3f00bca26d77f220f4714c81cbc92a30e1e2").into(),
|
hex!("5604fe023cd6effd93aec9b4a008398abdd32afb3fec988a19aa853ab0424a7c").into(),
|
||||||
200_000,
|
200_000,
|
||||||
vec![
|
vec![
|
||||||
Transaction {
|
Transaction {
|
||||||
|
|||||||
@@ -80,3 +80,9 @@ pub type Signature = primitives::hash::H512;
|
|||||||
|
|
||||||
/// A timestamp: seconds since the unix epoch.
|
/// A timestamp: seconds since the unix epoch.
|
||||||
pub type Timestamp = u64;
|
pub type Timestamp = u64;
|
||||||
|
|
||||||
|
/// The balance of an account.
|
||||||
|
pub type Balance = u64;
|
||||||
|
|
||||||
|
/// The amount of bonding period left in an account. Measured in eras.
|
||||||
|
pub type Bondage = u64;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use rstd::vec::Vec;
|
use rstd::vec::Vec;
|
||||||
use codec::{Input, Slicable};
|
use codec::{Input, Slicable};
|
||||||
|
use primitives::bft::MisbehaviorReport;
|
||||||
use ::Signature;
|
use ::Signature;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -168,6 +169,8 @@ enum FunctionId {
|
|||||||
StakingUnstake = 0x21,
|
StakingUnstake = 0x21,
|
||||||
/// Staking subsystem: transfer stake.
|
/// Staking subsystem: transfer stake.
|
||||||
StakingTransfer = 0x22,
|
StakingTransfer = 0x22,
|
||||||
|
/// Report misbehavior.
|
||||||
|
StakingReportMisbehavior = 0x23,
|
||||||
/// Make a proposal for the governance system.
|
/// Make a proposal for the governance system.
|
||||||
GovernancePropose = 0x30,
|
GovernancePropose = 0x30,
|
||||||
/// Approve a proposal for the governance system.
|
/// Approve a proposal for the governance system.
|
||||||
@@ -178,9 +181,16 @@ impl FunctionId {
|
|||||||
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
|
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
|
||||||
fn from_u8(value: u8) -> Option<FunctionId> {
|
fn from_u8(value: u8) -> Option<FunctionId> {
|
||||||
use self::*;
|
use self::*;
|
||||||
let functions = [FunctionId::StakingStake, FunctionId::StakingUnstake,
|
let functions = [
|
||||||
FunctionId::StakingTransfer, FunctionId::SessionSetKey, FunctionId::TimestampSet,
|
FunctionId::StakingStake,
|
||||||
FunctionId::GovernancePropose, FunctionId::GovernanceApprove];
|
FunctionId::StakingUnstake,
|
||||||
|
FunctionId::StakingTransfer,
|
||||||
|
FunctionId::StakingReportMisbehavior,
|
||||||
|
FunctionId::SessionSetKey,
|
||||||
|
FunctionId::TimestampSet,
|
||||||
|
FunctionId::GovernancePropose,
|
||||||
|
FunctionId::GovernanceApprove,
|
||||||
|
];
|
||||||
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,6 +232,8 @@ pub enum Function {
|
|||||||
StakingUnstake,
|
StakingUnstake,
|
||||||
/// Staking subsystem: transfer stake.
|
/// Staking subsystem: transfer stake.
|
||||||
StakingTransfer(::AccountId, u64),
|
StakingTransfer(::AccountId, u64),
|
||||||
|
/// Staking subsystem: report misbehavior of a validator.
|
||||||
|
ReportMisbehavior(MisbehaviorReport),
|
||||||
/// Make a proposal for the governance system.
|
/// Make a proposal for the governance system.
|
||||||
GovernancePropose(Proposal),
|
GovernancePropose(Proposal),
|
||||||
/// Approve a proposal for the governance system.
|
/// Approve a proposal for the governance system.
|
||||||
@@ -269,6 +281,7 @@ impl Slicable for Function {
|
|||||||
|
|
||||||
Function::StakingTransfer(to, amount)
|
Function::StakingTransfer(to, amount)
|
||||||
}
|
}
|
||||||
|
FunctionId::StakingReportMisbehavior => Function::ReportMisbehavior(MisbehaviorReport::decode(input)?),
|
||||||
FunctionId::GovernancePropose =>
|
FunctionId::GovernancePropose =>
|
||||||
Function::GovernancePropose(try_opt!(Slicable::decode(input))),
|
Function::GovernancePropose(try_opt!(Slicable::decode(input))),
|
||||||
FunctionId::GovernanceApprove =>
|
FunctionId::GovernanceApprove =>
|
||||||
@@ -293,6 +306,10 @@ impl Slicable for Function {
|
|||||||
Function::StakingUnstake => {
|
Function::StakingUnstake => {
|
||||||
(FunctionId::StakingUnstake as u8).using_encoded(|s| v.extend(s));
|
(FunctionId::StakingUnstake as u8).using_encoded(|s| v.extend(s));
|
||||||
}
|
}
|
||||||
|
Function::ReportMisbehavior(ref report) => {
|
||||||
|
(FunctionId::StakingReportMisbehavior as u8).using_encoded(|s| v.extend(s));
|
||||||
|
report.using_encoded(|s| v.extend(s));
|
||||||
|
}
|
||||||
Function::StakingTransfer(ref to, ref amount) => {
|
Function::StakingTransfer(ref to, ref amount) => {
|
||||||
(FunctionId::StakingTransfer as u8).using_encoded(|s| v.extend(s));
|
(FunctionId::StakingTransfer as u8).using_encoded(|s| v.extend(s));
|
||||||
to.using_encoded(|s| v.extend(s));
|
to.using_encoded(|s| v.extend(s));
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ substrate-runtime-std = { path = "../../substrate/runtime-std" }
|
|||||||
substrate-runtime-io = { path = "../../substrate/runtime-io" }
|
substrate-runtime-io = { path = "../../substrate/runtime-io" }
|
||||||
substrate-runtime-support = { path = "../../substrate/runtime-support" }
|
substrate-runtime-support = { path = "../../substrate/runtime-support" }
|
||||||
substrate-primitives = { path = "../../substrate/primitives" }
|
substrate-primitives = { path = "../../substrate/primitives" }
|
||||||
|
substrate-misbehavior-check = { path = "../../substrate/misbehavior-check" }
|
||||||
polkadot-primitives = { path = "../primitives" }
|
polkadot-primitives = { path = "../primitives" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@@ -25,6 +26,7 @@ std = [
|
|||||||
"substrate-runtime-io/std",
|
"substrate-runtime-io/std",
|
||||||
"substrate-runtime-support/std",
|
"substrate-runtime-support/std",
|
||||||
"substrate-primitives/std",
|
"substrate-primitives/std",
|
||||||
|
"substrate-misbehavior-check/std",
|
||||||
"polkadot-primitives/std",
|
"polkadot-primitives/std",
|
||||||
"log"
|
"log"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ pub struct Environment {
|
|||||||
pub parent_hash: Hash,
|
pub parent_hash: Hash,
|
||||||
/// The current block digest.
|
/// The current block digest.
|
||||||
pub digest: Digest,
|
pub digest: Digest,
|
||||||
/// The current transaction index
|
|
||||||
pub transaction_index: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do something with the environment and return its value. Keep the function short.
|
/// Do something with the environment and return its value. Keep the function short.
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ use std::collections::HashMap;
|
|||||||
use runtime_io::twox_128;
|
use runtime_io::twox_128;
|
||||||
use runtime_support::Hashable;
|
use runtime_support::Hashable;
|
||||||
use primitives::Block;
|
use primitives::Block;
|
||||||
use polkadot_primitives::{BlockNumber, AccountId};
|
use polkadot_primitives::{Balance, BlockNumber, AccountId};
|
||||||
use runtime::staking::Balance;
|
|
||||||
|
|
||||||
/// Configuration of a general Polkadot genesis block.
|
/// Configuration of a general Polkadot genesis block.
|
||||||
pub struct GenesisConfig {
|
pub struct GenesisConfig {
|
||||||
|
|||||||
@@ -19,23 +19,33 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
extern crate substrate_runtime_std as rstd;
|
extern crate substrate_runtime_std as rstd;
|
||||||
#[macro_use] extern crate substrate_runtime_io as runtime_io;
|
|
||||||
extern crate substrate_runtime_support as runtime_support;
|
extern crate substrate_runtime_support as runtime_support;
|
||||||
#[cfg(all(feature = "std", test))] extern crate substrate_keyring as keyring;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")] extern crate rustc_hex;
|
|
||||||
|
|
||||||
extern crate substrate_codec as codec;
|
extern crate substrate_codec as codec;
|
||||||
#[cfg(feature = "std")] #[macro_use] extern crate substrate_primitives as primitives;
|
extern crate substrate_misbehavior_check as misbehavior_check;
|
||||||
extern crate polkadot_primitives;
|
extern crate polkadot_primitives;
|
||||||
|
|
||||||
#[cfg(test)] #[macro_use] extern crate hex_literal;
|
#[cfg(all(feature = "std", test))]
|
||||||
|
extern crate substrate_keyring as keyring;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
extern crate rustc_hex;
|
||||||
|
|
||||||
|
#[cfg_attr(any(test, feature = "std"), macro_use)]
|
||||||
|
extern crate substrate_primitives as primitives;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate substrate_runtime_io as runtime_io;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate hex_literal;
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod environment;
|
pub mod environment;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|
||||||
#[cfg(feature = "std")] pub mod genesismap;
|
#[cfg(feature = "std")]
|
||||||
|
pub mod genesismap;
|
||||||
|
|
||||||
/// Type definitions and helpers for transactions.
|
/// Type definitions and helpers for transactions.
|
||||||
pub mod transaction {
|
pub mod transaction {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use polkadot_primitives::SessionKey;
|
|||||||
struct AuthorityStorageVec {}
|
struct AuthorityStorageVec {}
|
||||||
impl StorageVec for AuthorityStorageVec {
|
impl StorageVec for AuthorityStorageVec {
|
||||||
type Item = SessionKey;
|
type Item = SessionKey;
|
||||||
const PREFIX: &'static[u8] = b":auth:";
|
const PREFIX: &'static [u8] = b":auth:";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current set of authorities. These are the session keys.
|
/// Get the current set of authorities. These are the session keys.
|
||||||
@@ -37,7 +37,7 @@ pub mod internal {
|
|||||||
/// Set the current set of authorities' session keys.
|
/// Set the current set of authorities' session keys.
|
||||||
///
|
///
|
||||||
/// Called by `next_session` only.
|
/// Called by `next_session` only.
|
||||||
pub fn set_authorities(authorities: &[SessionKey]) {
|
pub fn set_authorities<'a, I: IntoIterator<Item=&'a SessionKey>>(authorities: I) {
|
||||||
AuthorityStorageVec::set_items(authorities);
|
AuthorityStorageVec::set_items(authorities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,23 @@ use runtime::{system, staking, consensus};
|
|||||||
|
|
||||||
const SESSION_LENGTH: &[u8] = b"ses:len";
|
const SESSION_LENGTH: &[u8] = b"ses:len";
|
||||||
const CURRENT_INDEX: &[u8] = b"ses:ind";
|
const CURRENT_INDEX: &[u8] = b"ses:ind";
|
||||||
|
const CURRENT_SESSION_START: &[u8] = b"ses:sta";
|
||||||
|
const LAST_SESSION_START: &[u8] = b"ses:lst";
|
||||||
const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc";
|
const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc";
|
||||||
const NEXT_KEY_FOR: &[u8] = b"ses:nxt:";
|
const NEXT_KEY_FOR: &[u8] = b"ses:nxt:";
|
||||||
const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln";
|
const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln";
|
||||||
|
|
||||||
struct ValidatorStorageVec {}
|
struct ValidatorStorageVec;
|
||||||
impl StorageVec for ValidatorStorageVec {
|
impl StorageVec for ValidatorStorageVec {
|
||||||
type Item = AccountId;
|
type Item = AccountId;
|
||||||
const PREFIX: &'static[u8] = b"ses:val:";
|
const PREFIX: &'static [u8] = b"ses:val:";
|
||||||
|
}
|
||||||
|
|
||||||
|
// the session keys before the previous.
|
||||||
|
struct LastValidators;
|
||||||
|
impl StorageVec for LastValidators {
|
||||||
|
type Item = (AccountId, SessionKey);
|
||||||
|
const PREFIX: &'static [u8] = b"ses:old:";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current set of validators.
|
/// Get the current set of validators.
|
||||||
@@ -50,11 +59,31 @@ pub fn validator_count() -> u32 {
|
|||||||
ValidatorStorageVec::count() as u32
|
ValidatorStorageVec::count() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current era index.
|
/// The current session index.
|
||||||
pub fn current_index() -> BlockNumber {
|
pub fn current_index() -> BlockNumber {
|
||||||
storage::get_or(CURRENT_INDEX, 0)
|
storage::get_or(CURRENT_INDEX, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the starting block of the current session.
|
||||||
|
pub fn current_start_block() -> BlockNumber {
|
||||||
|
// this seems like it's computable just by examining the current block number, session length,
|
||||||
|
// and last length change, but it's not simple to tell whether we are before or after
|
||||||
|
// a session rotation on a block which will have one.
|
||||||
|
storage::get_or(CURRENT_SESSION_START, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the last session's validators, paired with their authority keys.
|
||||||
|
pub fn last_session_keys() -> Vec<(AccountId, SessionKey)> {
|
||||||
|
LastValidators::items()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the start block of the last session.
|
||||||
|
/// In general this is computable from the session length,
|
||||||
|
/// but when the current session is the first with a new length it is uncomputable.
|
||||||
|
pub fn last_session_start() -> Option<BlockNumber> {
|
||||||
|
storage::get(LAST_SESSION_START)
|
||||||
|
}
|
||||||
|
|
||||||
/// The block number at which the era length last changed.
|
/// The block number at which the era length last changed.
|
||||||
pub fn last_length_change() -> BlockNumber {
|
pub fn last_length_change() -> BlockNumber {
|
||||||
storage::get_or(LAST_LENGTH_CHANGE, 0)
|
storage::get_or(LAST_LENGTH_CHANGE, 0)
|
||||||
@@ -90,11 +119,14 @@ pub mod privileged {
|
|||||||
pub mod internal {
|
pub mod internal {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Set the current set of validators.
|
/// Transition to a new era, with a new set of valiators.
|
||||||
///
|
///
|
||||||
/// Called by staking::next_era() only. `next_session` should be called after this in order to
|
/// Called by staking::next_era() only. `next_session` should be called after this in order to
|
||||||
/// update the session keys to the next validator set.
|
/// update the session keys to the next validator set.
|
||||||
pub fn set_validators(new: &[AccountId]) {
|
pub fn set_validators(new: &[AccountId]) {
|
||||||
|
LastValidators::set_items(
|
||||||
|
new.iter().cloned().zip(consensus::authorities())
|
||||||
|
);
|
||||||
ValidatorStorageVec::set_items(new);
|
ValidatorStorageVec::set_items(new);
|
||||||
consensus::internal::set_authorities(new);
|
consensus::internal::set_authorities(new);
|
||||||
}
|
}
|
||||||
@@ -114,7 +146,6 @@ pub mod internal {
|
|||||||
fn rotate_session() {
|
fn rotate_session() {
|
||||||
// Increment current session index.
|
// Increment current session index.
|
||||||
storage::put(CURRENT_INDEX, &(current_index() + 1));
|
storage::put(CURRENT_INDEX, &(current_index() + 1));
|
||||||
|
|
||||||
// Enact era length change.
|
// Enact era length change.
|
||||||
if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) {
|
if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) {
|
||||||
storage::put(SESSION_LENGTH, &next_len);
|
storage::put(SESSION_LENGTH, &next_len);
|
||||||
@@ -122,10 +153,23 @@ fn rotate_session() {
|
|||||||
storage::kill(NEXT_SESSION_LENGTH);
|
storage::kill(NEXT_SESSION_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let validators = validators();
|
||||||
|
|
||||||
|
storage::put(LAST_SESSION_START, ¤t_start_block());
|
||||||
|
storage::put(CURRENT_SESSION_START, &system::block_number());
|
||||||
|
LastValidators::set_items(
|
||||||
|
validators.iter()
|
||||||
|
.cloned()
|
||||||
|
.zip(consensus::authorities())
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// Update any changes in session keys.
|
// Update any changes in session keys.
|
||||||
validators().iter().enumerate().for_each(|(i, v)| {
|
validators.iter().enumerate().for_each(|(i, v)| {
|
||||||
let k = v.to_keyed_vec(NEXT_KEY_FOR);
|
let k = v.to_keyed_vec(NEXT_KEY_FOR);
|
||||||
if let Some(n) = storage::take(&k) {
|
if let Some(n) = storage::take(&k) {
|
||||||
|
// this is fine because the authorities vector currently
|
||||||
|
// matches the validators length perfectly.
|
||||||
consensus::internal::set_authority(i as u32, &n);
|
consensus::internal::set_authority(i as u32, &n);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,18 +22,16 @@ use runtime_io::print;
|
|||||||
use codec::KeyedVec;
|
use codec::KeyedVec;
|
||||||
use runtime_support::{storage, StorageVec};
|
use runtime_support::{storage, StorageVec};
|
||||||
use polkadot_primitives::{BlockNumber, AccountId};
|
use polkadot_primitives::{BlockNumber, AccountId};
|
||||||
use runtime::{system, session, governance};
|
use primitives::bft::{MisbehaviorReport, MisbehaviorKind};
|
||||||
|
use runtime::{system, session, governance, consensus};
|
||||||
|
|
||||||
/// The balance of an account.
|
type Balance = u64;
|
||||||
pub type Balance = u64;
|
type Bondage = u64;
|
||||||
|
|
||||||
/// The amount of bonding period left in an account. Measured in eras.
|
|
||||||
pub type Bondage = u64;
|
|
||||||
|
|
||||||
struct IntentionStorageVec {}
|
struct IntentionStorageVec {}
|
||||||
impl StorageVec for IntentionStorageVec {
|
impl StorageVec for IntentionStorageVec {
|
||||||
type Item = AccountId;
|
type Item = AccountId;
|
||||||
const PREFIX: &'static[u8] = b"sta:wil:";
|
const PREFIX: &'static [u8] = b"sta:wil:";
|
||||||
}
|
}
|
||||||
|
|
||||||
const BONDING_DURATION: &[u8] = b"sta:loc";
|
const BONDING_DURATION: &[u8] = b"sta:loc";
|
||||||
@@ -81,11 +79,16 @@ pub fn balance(who: &AccountId) -> Balance {
|
|||||||
storage::get_or_default(&who.to_keyed_vec(BALANCE_OF))
|
storage::get_or_default(&who.to_keyed_vec(BALANCE_OF))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The liquidity-state of a given account.
|
/// Gives the index of the era where the account's balance will no longer
|
||||||
|
/// be bonded.
|
||||||
pub fn bondage(who: &AccountId) -> Bondage {
|
pub fn bondage(who: &AccountId) -> Bondage {
|
||||||
storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF))
|
storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_balance(who: &AccountId, amount: Balance) {
|
||||||
|
storage::put(&who.to_keyed_vec(BALANCE_OF), &amount)
|
||||||
|
}
|
||||||
|
|
||||||
// Each identity's stake may be in one of three bondage states, given by an integer:
|
// Each identity's stake may be in one of three bondage states, given by an integer:
|
||||||
// - n | n <= current_era(): inactive: free to be transferred.
|
// - n | n <= current_era(): inactive: free to be transferred.
|
||||||
// - ~0: active: currently representing a validator.
|
// - ~0: active: currently representing a validator.
|
||||||
@@ -114,7 +117,7 @@ pub mod public {
|
|||||||
pub fn stake(transactor: &AccountId) {
|
pub fn stake(transactor: &AccountId) {
|
||||||
let mut intentions = IntentionStorageVec::items();
|
let mut intentions = IntentionStorageVec::items();
|
||||||
// can't be in the list twice.
|
// can't be in the list twice.
|
||||||
assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
|
assert!(intentions.iter().find(|t| t == &transactor).is_none(), "Cannot stake if already staked.");
|
||||||
intentions.push(transactor.clone());
|
intentions.push(transactor.clone());
|
||||||
IntentionStorageVec::set_items(&intentions);
|
IntentionStorageVec::set_items(&intentions);
|
||||||
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value());
|
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value());
|
||||||
@@ -133,6 +136,46 @@ pub mod public {
|
|||||||
IntentionStorageVec::set_items(&intentions);
|
IntentionStorageVec::set_items(&intentions);
|
||||||
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration()));
|
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Report misbehavior. Only validators may do this, signing under
|
||||||
|
/// the authority key of the session the report corresponds to.
|
||||||
|
///
|
||||||
|
/// Reports older than one session in the past will be ignored.
|
||||||
|
pub fn report_misbehavior(transactor: &AccountId, report: &MisbehaviorReport) {
|
||||||
|
let (validators, authorities) = if report.parent_number < session::last_session_start().unwrap_or(0) {
|
||||||
|
panic!("report is too old");
|
||||||
|
} else if report.parent_number < session::current_start_block() {
|
||||||
|
session::last_session_keys().into_iter().unzip()
|
||||||
|
} else {
|
||||||
|
(session::validators(), consensus::authorities())
|
||||||
|
};
|
||||||
|
|
||||||
|
if report.parent_hash != system::block_hash(report.parent_number) {
|
||||||
|
// report out of chain.
|
||||||
|
panic!("report not from this blockchain");
|
||||||
|
}
|
||||||
|
|
||||||
|
let reporting_validator = match authorities.iter().position(|x| x == transactor) {
|
||||||
|
None => panic!("only validators may report"),
|
||||||
|
Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// any invalidity beyond this point is actually its own misbehavior.
|
||||||
|
let target = match authorities.iter().position(|x| x == &report.target) {
|
||||||
|
None => {
|
||||||
|
slash(reporting_validator, None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let misbehaved = ::misbehavior_check::evaluate_misbehavior(&report.target, report.parent_hash, &report.misbehavior);
|
||||||
|
if misbehaved {
|
||||||
|
slash(target, Some(reporting_validator))
|
||||||
|
} else {
|
||||||
|
slash(reporting_validator, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod privileged {
|
pub mod privileged {
|
||||||
@@ -172,6 +215,23 @@ pub mod internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Slash a validator, with an optional benefactor.
|
||||||
|
fn slash(who: &AccountId, benefactor: Option<&AccountId>) {
|
||||||
|
// the reciprocal of the proportion of the amount slashed to give
|
||||||
|
// to the benefactor.
|
||||||
|
const SLASH_REWARD_DENOMINATOR: Balance = 10;
|
||||||
|
|
||||||
|
let slashed = balance(who);
|
||||||
|
set_balance(who, 0);
|
||||||
|
|
||||||
|
if let Some(benefactor) = benefactor {
|
||||||
|
let reward = slashed / SLASH_REWARD_DENOMINATOR;
|
||||||
|
|
||||||
|
let prior = balance(benefactor);
|
||||||
|
set_balance(benefactor, prior + reward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The era has changed - enact new staking set.
|
/// The era has changed - enact new staking set.
|
||||||
///
|
///
|
||||||
/// NOTE: This always happens immediately before a session change to ensure that new validators
|
/// NOTE: This always happens immediately before a session change to ensure that new validators
|
||||||
@@ -406,4 +466,31 @@ mod tests {
|
|||||||
transfer(&one, &two, 69);
|
transfer(&one, &two, 69);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn misbehavior_report_by_non_validator_panics() {
|
||||||
|
let one = Keyring::One.to_raw_public();
|
||||||
|
let two = Keyring::Two.to_raw_public();
|
||||||
|
|
||||||
|
let mut t: TestExternalities = map![
|
||||||
|
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64)
|
||||||
|
];
|
||||||
|
|
||||||
|
with_externalities(&mut t, || {
|
||||||
|
// the misbehavior report here is invalid, but that
|
||||||
|
// actually doesn't panic; instead it would slash the bad
|
||||||
|
// reporter.
|
||||||
|
report_misbehavior(&one, &MisbehaviorReport {
|
||||||
|
parent_hash: [0; 32].into(),
|
||||||
|
parent_number: 0,
|
||||||
|
target: two,
|
||||||
|
misbehavior: MisbehaviorKind::BftDoubleCommit(
|
||||||
|
2,
|
||||||
|
([1; 32].into(), [2; 64].into()),
|
||||||
|
([3; 32].into(), [4; 64].into()),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ fn dispatch_function(function: &Function, transactor: &AccountId) {
|
|||||||
Function::StakingTransfer(dest, value) => {
|
Function::StakingTransfer(dest, value) => {
|
||||||
::runtime::staking::public::transfer(transactor, &dest, value);
|
::runtime::staking::public::transfer(transactor, &dest, value);
|
||||||
}
|
}
|
||||||
|
Function::ReportMisbehavior(ref report) => {
|
||||||
|
::runtime::staking::public::report_misbehavior(transactor, report)
|
||||||
|
}
|
||||||
Function::SessionSetKey(session) => {
|
Function::SessionSetKey(session) => {
|
||||||
::runtime::session::public::set_key(transactor, &session);
|
::runtime::session::public::set_key(transactor, &session);
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+10
@@ -392,6 +392,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"polkadot-primitives 0.1.0",
|
"polkadot-primitives 0.1.0",
|
||||||
"substrate-codec 0.1.0",
|
"substrate-codec 0.1.0",
|
||||||
|
"substrate-misbehavior-check 0.1.0",
|
||||||
"substrate-primitives 0.1.0",
|
"substrate-primitives 0.1.0",
|
||||||
"substrate-runtime-io 0.1.0",
|
"substrate-runtime-io 0.1.0",
|
||||||
"substrate-runtime-std 0.1.0",
|
"substrate-runtime-std 0.1.0",
|
||||||
@@ -599,6 +600,15 @@ dependencies = [
|
|||||||
"substrate-runtime-std 0.1.0",
|
"substrate-runtime-std 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "substrate-misbehavior-check"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"substrate-codec 0.1.0",
|
||||||
|
"substrate-primitives 0.1.0",
|
||||||
|
"substrate-runtime-io 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "substrate-primitives"
|
name = "substrate-primitives"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ substrate-runtime-std = { path = "../../../substrate/runtime-std", default-featu
|
|||||||
substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false }
|
substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false }
|
||||||
substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false }
|
substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false }
|
||||||
substrate-primitives = { path = "../../../substrate/primitives", default-features = false }
|
substrate-primitives = { path = "../../../substrate/primitives", default-features = false }
|
||||||
|
substrate-misbehavior-check = { path = "../../../substrate/misbehavior-check", default-features = false }
|
||||||
polkadot-primitives = { path = "../../primitives", default-features = false }
|
polkadot-primitives = { path = "../../primitives", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -22,6 +23,7 @@ std = [
|
|||||||
"substrate-runtime-std/std",
|
"substrate-runtime-std/std",
|
||||||
"substrate-runtime-support/std",
|
"substrate-runtime-support/std",
|
||||||
"substrate-primitives/std",
|
"substrate-primitives/std",
|
||||||
|
"substrate-misbehavior-check/std",
|
||||||
"polkadot-primitives/std",
|
"polkadot-primitives/std",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user