Update to latest Substrate master. (#353)

* Integrate srml/im-online

* Fix all build errors with old aura.

* Fix most of the build errors.

* Builds and tests seem to pass (I will not trust this commit yet)

* Apply suggestions from code review

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Kill some warnings.

* fix panics on 0 validators

* Fix dev chain.

* Fix author stuff

* fix im online integration.

* Some tweaks

* Introduce app-crypto

* Initial build work

* codec update / tweaks

* patch polkadot-erasure-coding input

* More fixes for new crypto

* More fixes

* Update parachains module

* evamp parachain crypto

* More crypto work.

* Chain spec and service.

* ChainSpec stuff

* Last bits for a clean build

* Tweak coment

* adapt polkadot-validation to the new keystore

* polkadot-network compiles, but tests don't

* Integrate the new parachain validation stuff

* delete message_routing file

* make polkadot-network tests compile and pass

* runtime tests compile and pass

* update substrate ref

* service compiles

* all tests pass

* Add TODO, change branch back to polkadot-master

* Lock file

* TODOs done

* Issue number

* Remove old tODO

* Remove commented code
This commit is contained in:
Kian Paimani
2019-08-12 15:48:29 +02:00
committed by Gavin Wood
parent 9b6e630816
commit 10fc88f6b1
51 changed files with 1719 additions and 1513 deletions
+756 -536
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@ edition = "2018"
polkadot-primitives = { path = "../primitives" }
parking_lot = "0.9.0"
log = "0.4.6"
parity-codec = "4.1"
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
kvdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" }
kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" }
+1 -1
View File
@@ -16,7 +16,7 @@
//! Persistent database for parachain data.
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use kvdb::{KeyValueDB, DBTransaction};
use kvdb_rocksdb::{Database, DatabaseConfig};
use polkadot_primitives::Hash;
+5 -5
View File
@@ -26,15 +26,15 @@ pub enum ChainSpec {
Development,
/// Whatever the current runtime is, with simple Alice/Bob auths.
LocalTestnet,
/// The PoC-3 era testnet.
Alexander,
/// The Kusama network.
Kusama,
/// Whatever the current runtime is with the "global testnet" defaults.
StagingTestnet,
}
impl Default for ChainSpec {
fn default() -> Self {
ChainSpec::Alexander
ChainSpec::Kusama
}
}
@@ -42,7 +42,7 @@ impl Default for ChainSpec {
impl ChainSpec {
pub(crate) fn load(self) -> Result<service::ChainSpec, String> {
Ok(match self {
ChainSpec::Alexander => service::chain_spec::poc_3_testnet_config()?,
ChainSpec::Kusama => service::chain_spec::kusama_config()?,
ChainSpec::Development => service::chain_spec::development_config(),
ChainSpec::LocalTestnet => service::chain_spec::local_testnet_config(),
ChainSpec::StagingTestnet => service::chain_spec::staging_testnet_config(),
@@ -53,7 +53,7 @@ impl ChainSpec {
match s {
"dev" => Some(ChainSpec::Development),
"local" => Some(ChainSpec::LocalTestnet),
"poc-3" | "alex" | "alexander" => Some(ChainSpec::Alexander),
"kusama" => Some(ChainSpec::Kusama),
"staging" => Some(ChainSpec::StagingTestnet),
"" => Some(ChainSpec::default()),
_ => None,
-2
View File
@@ -9,11 +9,9 @@ edition = "2018"
futures = "0.1.17"
futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] }
client = { package = "substrate-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
parity-codec = "4.1"
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
substrate-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
consensus_common = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
aura = { package = "substrate-consensus-aura", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
polkadot-runtime = { path = "../runtime", version = "0.1" }
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-cli = { path = "../cli" }
+14 -15
View File
@@ -53,12 +53,12 @@ use futures::{future, Stream, Future, IntoFuture};
use futures03::{TryStreamExt as _, StreamExt as _};
use log::{info, warn};
use client::BlockchainEvents;
use primitives::{ed25519, Pair};
use primitives::Pair;
use polkadot_primitives::{
BlockId, SessionKey, Hash, Block,
BlockId, Hash, Block,
parachain::{
self, BlockData, DutyRoster, HeadData, ConsolidatedIngress, Message, Id as ParaId, Extrinsic,
PoVBlock, Status as ParachainStatus,
PoVBlock, Status as ParachainStatus, ValidatorId, CollatorPair,
}
};
use polkadot_cli::{
@@ -69,7 +69,6 @@ use polkadot_network::validation::{SessionParams, ValidationNetwork};
use polkadot_network::NetworkService;
use tokio::timer::Timeout;
use consensus_common::SelectChain;
use aura::AuraApi;
pub use polkadot_cli::VersionInfo;
pub use polkadot_network::validation::Incoming;
@@ -177,7 +176,7 @@ pub fn collate<'a, R, P>(
parachain_status: ParachainStatus,
relay_context: R,
para_context: P,
key: Arc<ed25519::Pair>,
key: Arc<CollatorPair>,
)
-> impl Future<Item=parachain::Collation, Error=Error<R::Error>> + 'a
where
@@ -230,7 +229,7 @@ pub fn collate<'a, R, P>(
struct ApiContext<P, E> {
network: Arc<ValidationNetwork<P, E, NetworkService, TaskExecutor>>,
parent_hash: Hash,
authorities: Vec<SessionKey>,
validators: Vec<ValidatorId>,
}
impl<P: 'static, E: 'static> RelayChainContext for ApiContext<P, E> where
@@ -248,7 +247,7 @@ impl<P: 'static, E: 'static> RelayChainContext for ApiContext<P, E> where
let _session = self.network.instantiate_session(SessionParams {
local_session_key: None,
parent_hash: self.parent_hash,
authorities: self.authorities.clone(),
authorities: self.validators.clone(),
}).map_err(|e| format!("unable to instantiate validation session: {:?}", e));
Box::new(future::ok(ConsolidatedIngress(Vec::new())))
@@ -259,7 +258,7 @@ struct CollationNode<P, E> {
build_parachain_context: P,
exit: E,
para_id: ParaId,
key: Arc<ed25519::Pair>,
key: Arc<CollatorPair>,
}
impl<P, E> IntoExit for CollationNode<P, E> where
@@ -364,18 +363,18 @@ impl<P, E> Worker for CollationNode<P, E> where
None => return future::Either::A(future::ok(())),
};
let authorities = try_fr!(api.authorities(&id));
let validators = try_fr!(api.validators(&id));
let targets = compute_targets(
para_id,
authorities.as_slice(),
validators.as_slice(),
try_fr!(api.duty_roster(&id)),
);
let context = ApiContext {
network: validation_network,
parent_hash: relay_parent,
authorities,
validators,
};
let collation_work = collate(
@@ -414,7 +413,7 @@ impl<P, E> Worker for CollationNode<P, E> where
}
}
fn compute_targets(para_id: ParaId, session_keys: &[SessionKey], roster: DutyRoster) -> HashSet<SessionKey> {
fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRoster) -> HashSet<ValidatorId> {
use polkadot_primitives::parachain::Chain;
roster.validator_duty.iter().enumerate()
@@ -433,7 +432,7 @@ pub fn run_collator<P, E>(
build_parachain_context: P,
para_id: ParaId,
exit: E,
key: Arc<ed25519::Pair>,
key: Arc<CollatorPair>,
version: VersionInfo,
) -> polkadot_cli::error::Result<()> where
P: BuildParachainContext + Send + 'static,
@@ -450,7 +449,7 @@ pub fn run_collator<P, E>(
mod tests {
use std::collections::HashMap;
use polkadot_primitives::parachain::{OutgoingMessage, FeeSchedule};
use keyring::Ed25519Keyring;
use keyring::Sr25519Keyring;
use super::*;
#[derive(Default, Clone)]
@@ -540,7 +539,7 @@ mod tests {
},
context.clone(),
DummyParachainContext,
Ed25519Keyring::Alice.pair().into(),
Arc::new(Sr25519Keyring::Alice.pair().into()),
).wait().unwrap();
// ascending order by root.
+1 -1
View File
@@ -7,6 +7,6 @@ edition = "2018"
[dependencies]
primitives = { package = "polkadot-primitives", path = "../primitives" }
reed_solomon = { package = "reed-solomon-erasure", git = "https://github.com/paritytech/reed-solomon-erasure" }
parity-codec = "4.1"
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
trie = { package = "substrate-trie", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
+21 -10
View File
@@ -24,12 +24,12 @@
//! f is the maximum number of faulty validators in the system.
//! The data is coded so any f+1 chunks can be used to reconstruct the full data.
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use reed_solomon::galois_16::{self, ReedSolomon};
use primitives::{Hash as H256, BlakeTwo256, HashT};
use primitives::parachain::{BlockData, Extrinsic};
use substrate_primitives::Blake2Hasher;
use trie::{MemoryDB, Trie, TrieMut, TrieDB, TrieDBMut};
use trie::{EMPTY_PREFIX, MemoryDB, Trie, TrieMut, trie_types::{TrieDBMut, TrieDB}};
use self::wrapped_shard::WrappedShard;
@@ -187,13 +187,14 @@ pub fn reconstruct<'a, I: 'a>(n_validators: usize, chunks: I)
// lazily decode from the data shards.
Decode::decode(&mut ShardInput {
remaining_len: shard_len.map(|s| s * params.data_shards).unwrap_or(0),
cur_shard: None,
shards: shards.iter()
.map(|x| x.as_ref())
.take(params.data_shards)
.map(|x| x.expect("all data shards have been recovered; qed"))
.map(|x| x.as_ref()),
}).ok_or_else(|| Error::BadPayload)
}).or_else(|_| Err(Error::BadPayload))
}
/// An iterator that yields merkle branches and chunk data for all chunks to
@@ -269,7 +270,7 @@ pub fn branches<'a>(chunks: Vec<&'a [u8]>) -> Branches<'a> {
pub fn branch_hash(root: &H256, branch_nodes: &[Vec<u8>], index: usize) -> Result<H256, Error> {
let mut trie_storage: MemoryDB<Blake2Hasher> = MemoryDB::default();
for node in branch_nodes.iter() {
(&mut trie_storage as &mut trie::HashDB<_>).insert(&[], node.as_slice());
(&mut trie_storage as &mut trie::HashDB<_>).insert(EMPTY_PREFIX, node.as_slice());
}
let trie = TrieDB::new(&trie_storage, &root).map_err(|_| Error::InvalidBranchProof)?;
@@ -278,21 +279,26 @@ pub fn branch_hash(root: &H256, branch_nodes: &[Vec<u8>], index: usize) -> Resul
);
match res {
Ok(Some(Some(hash))) => Ok(hash),
Ok(Some(None)) => Err(Error::InvalidBranchProof), // hash failed to decode
Ok(Some(Ok(hash))) => Ok(hash),
Ok(Some(Err(_))) => Err(Error::InvalidBranchProof), // hash failed to decode
Ok(None) => Err(Error::BranchOutOfBounds),
Err(_) => Err(Error::InvalidBranchProof),
}
}
// input for `parity_codec` which draws data from the data shards
// input for `codec` which draws data from the data shards
struct ShardInput<'a, I> {
remaining_len: usize,
shards: I,
cur_shard: Option<(&'a [u8], usize)>,
}
impl<'a, I: Iterator<Item=&'a [u8]>> parity_codec::Input for ShardInput<'a, I> {
fn read(&mut self, into: &mut [u8]) -> usize {
impl<'a, I: Iterator<Item=&'a [u8]>> codec::Input for ShardInput<'a, I> {
fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
Ok(Some(self.remaining_len))
}
fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
let mut read_bytes = 0;
loop {
@@ -320,7 +326,12 @@ impl<'a, I: Iterator<Item=&'a [u8]>> parity_codec::Input for ShardInput<'a, I> {
self.cur_shard = Some((active_shard, in_shard))
}
read_bytes
self.remaining_len -= read_bytes;
if read_bytes == into.len() {
Ok(())
} else {
Err("slice provided too big for input".into())
}
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ parking_lot = "0.9.0"
av_store = { package = "polkadot-availability-store", path = "../availability-store" }
polkadot-validation = { path = "../validation" }
polkadot-primitives = { path = "../primitives" }
parity-codec = { version = "4.1", features = ["derive"] }
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
substrate-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
sr-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
+1 -1
View File
@@ -16,7 +16,7 @@
//! Bridge between the network and consensus service for getting collations to it.
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use polkadot_primitives::Hash;
use polkadot_primitives::parachain::{CollatorId, Id as ParaId, Collation};
use substrate_network::PeerId;
+12 -12
View File
@@ -22,8 +22,8 @@ use substrate_network::consensus_gossip::{
ValidatorContext, MessageIntent, ConsensusMessage,
};
use polkadot_validation::{GenericStatement, SignedStatement};
use polkadot_primitives::{Block, Hash, SessionKey, parachain::ValidatorIndex};
use parity_codec::{Decode, Encode};
use polkadot_primitives::{Block, Hash, parachain::{ValidatorIndex, ValidatorId}};
use codec::{Decode, Encode};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
@@ -218,9 +218,9 @@ impl RegisteredMessageValidator {
#[derive(Default)]
pub(crate) struct MessageValidationData {
/// The authorities at a block.
pub(crate) authorities: Vec<SessionKey>,
/// Mapping from validator index to `SessionKey`.
pub(crate) index_mapping: HashMap<ValidatorIndex, SessionKey>,
pub(crate) authorities: Vec<ValidatorId>,
/// Mapping from validator index to `ValidatorId`.
pub(crate) index_mapping: HashMap<ValidatorIndex, ValidatorId>,
}
impl MessageValidationData {
@@ -481,15 +481,15 @@ impl<O: KnownOracle + ?Sized> network_gossip::Validator<Block> for MessageValida
-> GossipValidationResult<Hash>
{
let (res, cost_benefit) = match GossipMessage::decode(&mut data) {
None => (GossipValidationResult::Discard, cost::MALFORMED_MESSAGE),
Some(GossipMessage::Neighbor(VersionedNeighborPacket::V1(packet))) => {
Err(_) => (GossipValidationResult::Discard, cost::MALFORMED_MESSAGE),
Ok(GossipMessage::Neighbor(VersionedNeighborPacket::V1(packet))) => {
let (res, cb, topics) = self.inner.write().validate_neighbor_packet(sender, packet);
for new_topic in topics {
context.send_topic(sender, new_topic, false);
}
(res, cb)
}
Some(GossipMessage::Statement(statement)) => {
Ok(GossipMessage::Statement(statement)) => {
let (res, cb) = self.inner.write().validate_statement(statement);
if let GossipValidationResult::ProcessAndKeep(ref topic) = res {
context.broadcast_message(topic.clone(), data.to_vec(), false);
@@ -535,7 +535,7 @@ impl<O: KnownOracle + ?Sized> network_gossip::Validator<Block> for MessageValida
};
match GossipMessage::decode(&mut &data[..]) {
Some(GossipMessage::Statement(statement)) => {
Ok(GossipMessage::Statement(statement)) => {
let signed = statement.signed_statement;
match signed.statement {
@@ -573,7 +573,7 @@ mod tests {
use parking_lot::Mutex;
use polkadot_primitives::parachain::{CandidateReceipt, HeadData};
use substrate_primitives::crypto::UncheckedInto;
use substrate_primitives::ed25519::Signature as Ed25519Signature;
use substrate_primitives::sr25519::Signature as Sr25519Signature;
#[derive(PartialEq, Clone, Debug)]
enum ContextEvent {
@@ -669,7 +669,7 @@ mod tests {
relay_parent: hash_a,
signed_statement: SignedStatement {
statement: GenericStatement::Candidate(candidate_receipt),
signature: Ed25519Signature([255u8; 64]),
signature: Sr25519Signature([255u8; 64]).into(),
sender: 1,
}
});
@@ -786,7 +786,7 @@ mod tests {
relay_parent: hash_a,
signed_statement: SignedStatement {
statement: GenericStatement::Valid(c_hash),
signature: Ed25519Signature([255u8; 64]),
signature: Sr25519Signature([255u8; 64]).into(),
sender: 1,
}
});
@@ -1,265 +0,0 @@
// Copyright 2019 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/>.
//! Data structures and synchronous logic for ICMP message gossip.
use sr_primitives::traits::{BlakeTwo256, Hash as HashT};
use polkadot_primitives::Hash;
use std::collections::{HashMap, HashSet};
use substrate_client::error::Error as ClientError;
use super::{MAX_CHAIN_HEADS, GossipValidationResult, LeavesVec, ChainContext};
/// Construct a topic for a message queue root deterministically.
pub fn queue_topic(queue_root: Hash) -> Hash {
let mut v = queue_root.as_ref().to_vec();
v.extend(b"message_queue");
BlakeTwo256::hash(&v[..])
}
/// A view of which queue roots are current for a given set of leaves.
#[derive(Default)]
pub struct View {
leaves: LeavesVec,
leaf_topics: HashMap<Hash, HashSet<Hash>>, // leaf_hash -> { topics }
expected_queues: HashMap<Hash, Hash>, // topic -> queue-root
}
impl View {
/// Update the set of current leaves.
pub fn update_leaves<T: ChainContext + ?Sized, I>(&mut self, context: &T, new_leaves: I)
-> Result<(), ClientError>
where I: Iterator<Item=Hash>
{
let new_leaves = new_leaves.take(MAX_CHAIN_HEADS);
let old_leaves = {
let mut new = LeavesVec::new();
for leaf in new_leaves {
new.push(leaf.clone());
}
std::mem::replace(&mut self.leaves, new)
};
let expected_queues = &mut self.expected_queues;
let leaves = &self.leaves;
self.leaf_topics.retain(|l, topics| {
if leaves.contains(l) { return true }
// prune out all data about old leaves we don't follow anymore.
for topic in topics.iter() {
expected_queues.remove(topic);
}
false
});
let mut res = Ok(());
// add in new data about fresh leaves.
for new_leaf in &self.leaves {
if old_leaves.contains(new_leaf) { continue }
let mut this_leaf_topics = HashSet::new();
let r = context.leaf_unrouted_roots(new_leaf, &mut |&queue_root| {
let topic = queue_topic(queue_root);
this_leaf_topics.insert(topic);
expected_queues.insert(topic, queue_root);
});
if r.is_err() {
res = r;
}
self.leaf_topics.insert(*new_leaf, this_leaf_topics);
}
res
}
/// Validate an incoming message queue against this view.
pub fn validate_queue(&self, messages: &super::GossipParachainMessages)
-> (GossipValidationResult<Hash>, i32)
{
let ostensible_topic = queue_topic(messages.queue_root);
if !self.is_topic_live(&ostensible_topic) {
(GossipValidationResult::Discard, super::cost::UNNEEDED_ICMP_MESSAGES)
} else if !messages.queue_root_is_correct() {
(
GossipValidationResult::Discard,
super::cost::icmp_messages_root_mismatch(messages.messages.len()),
)
} else {
(
GossipValidationResult::ProcessAndKeep(ostensible_topic),
super::benefit::NEW_ICMP_MESSAGES,
)
}
}
/// Whether a message with given topic is live.
pub fn is_topic_live(&self, topic: &Hash) -> bool {
self.expected_queues.get(topic).is_some()
}
/// Whether a message is allowed under the intersection of the given leaf-set
/// and our own.
pub fn allowed_intersecting(&self, other_leaves: &LeavesVec, topic: &Hash) -> bool {
for i in other_leaves {
for j in &self.leaves {
if i == j {
let leaf_topics = self.leaf_topics.get(i)
.expect("leaf_topics are mutated only in update_leaves; \
we have an entry for each item in self.leaves; \
i is in self.leaves; qed");
if leaf_topics.contains(topic) {
return true;
}
}
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::TestChainContext;
use crate::gossip::{Known, GossipParachainMessages};
use polkadot_primitives::parachain::Message as ParachainMessage;
fn hash(x: u8) -> Hash {
[x; 32].into()
}
fn message_queue(from: u8, to: u8) -> Option<[[u8; 2]; 1]> {
if from == to {
None
} else {
Some([[from, to]])
}
}
fn message_queue_root(from: u8, to: u8) -> Option<Hash> {
message_queue(from, to).map(
|q| polkadot_validation::message_queue_root(q.iter())
)
}
fn check_roots(view: &View, i: u8, max: u8) -> bool {
for j in 0..max {
if let Some(messages) = message_queue(i, j) {
let queue_root = message_queue_root(i, j).unwrap();
let messages = GossipParachainMessages {
queue_root,
messages: messages.iter().map(|m| ParachainMessage(m.to_vec())).collect(),
};
match view.validate_queue(&messages).0 {
GossipValidationResult::ProcessAndKeep(topic) => if topic != queue_topic(queue_root) {
return false
},
_ => return false,
}
}
}
true
}
#[test]
fn update_leaves_none_in_common() {
let mut ctx = TestChainContext::default();
let max = 5;
for i in 0..max {
ctx.known_map.insert(hash(i as u8), Known::Leaf);
let messages_out: Vec<_> = (0..max).filter_map(|j| message_queue_root(i, j)).collect();
if !messages_out.is_empty() {
ctx.ingress_roots.insert(hash(i as u8), messages_out);
}
}
let mut view = View::default();
view.update_leaves(
&ctx,
[hash(0), hash(1)].iter().cloned(),
).unwrap();
assert!(check_roots(&view, 0, max));
assert!(check_roots(&view, 1, max));
assert!(!check_roots(&view, 2, max));
assert!(!check_roots(&view, 3, max));
assert!(!check_roots(&view, 4, max));
assert!(!check_roots(&view, 5, max));
view.update_leaves(
&ctx,
[hash(2), hash(3), hash(4)].iter().cloned(),
).unwrap();
assert!(!check_roots(&view, 0, max));
assert!(!check_roots(&view, 1, max));
assert!(check_roots(&view, 2, max));
assert!(check_roots(&view, 3, max));
assert!(check_roots(&view, 4, max));
assert!(!check_roots(&view, 5, max));
}
#[test]
fn update_leaves_overlapping() {
let mut ctx = TestChainContext::default();
let max = 5;
for i in 0..max {
ctx.known_map.insert(hash(i as u8), Known::Leaf);
let messages_out: Vec<_> = (0..max).filter_map(|j| message_queue_root(i, j)).collect();
if !messages_out.is_empty() {
ctx.ingress_roots.insert(hash(i as u8), messages_out);
}
}
let mut view = View::default();
view.update_leaves(
&ctx,
[hash(0), hash(1), hash(2)].iter().cloned(),
).unwrap();
view.update_leaves(
&ctx,
[hash(2), hash(3), hash(4)].iter().cloned(),
).unwrap();
assert!(!check_roots(&view, 0, max));
assert!(!check_roots(&view, 1, max));
assert!(check_roots(&view, 2, max));
assert!(check_roots(&view, 3, max));
assert!(check_roots(&view, 4, max));
assert!(!check_roots(&view, 5, max));
}
}
+15 -19
View File
@@ -25,12 +25,12 @@ mod router;
pub mod validation;
pub mod gossip;
use parity_codec::{Decode, Encode};
use codec::{Decode, Encode};
use futures::sync::oneshot;
use polkadot_primitives::{Block, SessionKey, Hash, Header};
use polkadot_primitives::{Block, Hash, Header};
use polkadot_primitives::parachain::{
Id as ParaId, BlockData, CollatorId, CandidateReceipt, Collation, PoVBlock,
StructuredUnroutedIngress,
StructuredUnroutedIngress, ValidatorId
};
use substrate_network::{
PeerId, RequestId, Context, StatusMessage as GenericFullStatus,
@@ -78,7 +78,7 @@ pub struct Status {
}
struct PoVBlockRequest {
attempted_peers: HashSet<SessionKey>,
attempted_peers: HashSet<ValidatorId>,
validation_session_parent: Hash,
candidate_hash: Hash,
block_data_hash: Hash,
@@ -115,8 +115,8 @@ enum CollatorState {
}
impl CollatorState {
fn send_key<F: FnMut(Message)>(&mut self, key: SessionKey, mut f: F) {
f(Message::SessionKey(key));
fn send_key<F: FnMut(Message)>(&mut self, key: ValidatorId, mut f: F) {
f(Message::ValidatorId(key));
if let CollatorState::RolePending(role) = *self {
f(Message::CollatorRole(role));
*self = CollatorState::Primed(Some(role));
@@ -160,7 +160,7 @@ pub enum Message {
/// As a validator, tell the peer your current session key.
// TODO: do this with a cryptographic proof of some kind
// https://github.com/paritytech/polkadot/issues/47
SessionKey(SessionKey),
ValidatorId(ValidatorId),
/// Requesting parachain proof-of-validation block (relay_parent, candidate_hash).
RequestPovBlock(RequestId, Hash, Hash),
/// Provide requested proof-of-validation block data by candidate hash or nothing if unknown.
@@ -186,7 +186,7 @@ pub struct PolkadotProtocol {
peers: HashMap<PeerId, PeerInfo>,
collating_for: Option<(CollatorId, ParaId)>,
collators: CollatorPool,
validators: HashMap<SessionKey, PeerId>,
validators: HashMap<ValidatorId, PeerId>,
local_collations: LocalCollations<Collation>,
live_validation_sessions: LiveValidationSessions,
in_flight: HashMap<(RequestId, PeerId), PoVBlockRequest>,
@@ -319,7 +319,7 @@ impl PolkadotProtocol {
fn on_polkadot_message(&mut self, ctx: &mut dyn Context<Block>, who: PeerId, msg: Message) {
trace!(target: "p_net", "Polkadot message from {}: {:?}", who, msg);
match msg {
Message::SessionKey(key) => self.on_session_key(ctx, who, key),
Message::ValidatorId(key) => self.on_session_key(ctx, who, key),
Message::RequestPovBlock(req_id, relay_parent, candidate_hash) => {
let pov_block = self.live_validation_sessions.with_pov_block(
&relay_parent,
@@ -352,7 +352,7 @@ impl PolkadotProtocol {
}
}
fn on_session_key(&mut self, ctx: &mut dyn Context<Block>, who: PeerId, key: SessionKey) {
fn on_session_key(&mut self, ctx: &mut dyn Context<Block>, who: PeerId, key: ValidatorId) {
{
let info = match self.peers.get_mut(&who) {
Some(peer) => peer,
@@ -473,12 +473,8 @@ impl Specialization<Block> for PolkadotProtocol {
}
fn on_connect(&mut self, ctx: &mut dyn Context<Block>, who: PeerId, status: FullStatus) {
let local_status = match Status::decode(&mut &status.chain_status[..]) {
Some(status) => status,
None => {
Status { collating_for: None }
}
};
let local_status = Status::decode(&mut &status.chain_status[..])
.unwrap_or_else(|_| Status { collating_for: None });
let validator = status.roles.contains(substrate_network::config::Roles::AUTHORITY);
@@ -575,11 +571,11 @@ impl Specialization<Block> for PolkadotProtocol {
message: Vec<u8>,
) {
match Message::decode(&mut &message[..]) {
Some(msg) => {
Ok(msg) => {
ctx.report_peer(who.clone(), benefit::VALID_FORMAT);
self.on_polkadot_message(ctx, who, msg)
},
None => {
Err(_) => {
trace!(target: "p_net", "Bad message from {}", who);
ctx.report_peer(who, cost::INVALID_FORMAT);
}
@@ -684,7 +680,7 @@ impl PolkadotProtocol {
&mut self,
ctx: &mut dyn Context<Block>,
relay_parent: Hash,
targets: HashSet<SessionKey>,
targets: HashSet<ValidatorId>,
collation: Collation,
) {
debug!(target: "p_net", "Importing local collation on relay parent {:?} and parachain {:?}",
+9 -11
View File
@@ -19,24 +19,22 @@
//! Collations are attempted to be repropagated when a new validator connects,
//! a validator changes his session key, or when they are generated.
use polkadot_primitives::{Hash, SessionKey};
use polkadot_primitives::{Hash, parachain::{ValidatorId}};
use crate::collator_pool::Role;
use std::collections::{HashMap, HashSet};
use std::time::{Duration, Instant};
const LIVE_FOR: Duration = Duration::from_secs(60 * 5);
struct LocalCollation<C> {
targets: HashSet<SessionKey>,
targets: HashSet<ValidatorId>,
collation: C,
live_since: Instant,
}
/// Tracker for locally collated values and which validators to send them to.
pub struct LocalCollations<C> {
primary_for: HashSet<SessionKey>,
primary_for: HashSet<ValidatorId>,
local_collations: HashMap<Hash, LocalCollation<C>>,
}
@@ -51,7 +49,7 @@ impl<C: Clone> LocalCollations<C> {
/// Validator gave us a new role. If the new role is "primary", this function might return
/// a set of collations to send to that validator.
pub fn note_validator_role(&mut self, key: SessionKey, role: Role) -> Vec<(Hash, C)> {
pub fn note_validator_role(&mut self, key: ValidatorId, role: Role) -> Vec<(Hash, C)> {
match role {
Role::Backup => {
self.primary_for.remove(&key);
@@ -70,7 +68,7 @@ impl<C: Clone> LocalCollations<C> {
/// Fresh session key from a validator. Returns a vector of collations to send
/// to the validator.
pub fn fresh_key(&mut self, old_key: &SessionKey, new_key: &SessionKey) -> Vec<(Hash, C)> {
pub fn fresh_key(&mut self, old_key: &ValidatorId, new_key: &ValidatorId) -> Vec<(Hash, C)> {
if self.primary_for.remove(old_key) {
self.primary_for.insert(new_key.clone());
@@ -81,7 +79,7 @@ impl<C: Clone> LocalCollations<C> {
}
/// Validator disconnected.
pub fn on_disconnect(&mut self, key: &SessionKey) {
pub fn on_disconnect(&mut self, key: &ValidatorId) {
self.primary_for.remove(key);
}
@@ -99,10 +97,10 @@ impl<C: Clone> LocalCollations<C> {
pub fn add_collation<'a>(
&'a mut self,
relay_parent: Hash,
targets: HashSet<SessionKey>,
targets: HashSet<ValidatorId>,
collation: C
)
-> impl Iterator<Item=(SessionKey, C)> + 'a
-> impl Iterator<Item=(ValidatorId, C)> + 'a
{
self.local_collations.insert(relay_parent, LocalCollation {
targets,
@@ -119,7 +117,7 @@ impl<C: Clone> LocalCollations<C> {
.map(move |k| (k.clone(), borrowed_collation.clone()))
}
fn collations_targeting(&self, key: &SessionKey) -> Vec<(Hash, C)> {
fn collations_targeting(&self, key: &ValidatorId) -> Vec<(Hash, C)> {
self.local_collations.iter()
.filter(|&(_, ref v)| v.targets.contains(key))
.map(|(h, v)| (*h, v.collation.clone()))
+15 -4
View File
@@ -199,13 +199,16 @@ impl<P: ProvideRuntimeApi + Send + Sync + 'static, E, N, T> Router<P, E, N, T> w
validated.extrinsic().cloned(),
);
// propagate the statement.
// consider something more targeted than gossip in the future.
let statement = GossipStatement::new(
parent_hash,
table.import_validated(validated),
match table.import_validated(validated) {
None => return,
Some(s) => s,
}
);
network.gossip_message(attestation_topic, statement.into());
})
.map_err(|e| debug!(target: "p_net", "Failed to produce statements: {:?}", e))
@@ -224,10 +227,18 @@ impl<P: ProvideRuntimeApi + Send, E, N, T> TableRouter for Router<P, E, N, T> wh
fn local_collation(&self, collation: Collation, extrinsic: Extrinsic) {
// produce a signed statement
let hash = collation.receipt.hash();
let validated = Validated::collated_local(collation.receipt, collation.pov.clone(), extrinsic.clone());
let validated = Validated::collated_local(
collation.receipt,
collation.pov.clone(),
extrinsic.clone(),
);
let statement = GossipStatement::new(
self.parent_hash(),
self.table.import_validated(validated),
match self.table.import_validated(validated) {
None => return,
Some(s) => s,
},
);
// give to network to make available.
+13 -13
View File
@@ -21,13 +21,13 @@ use super::{PolkadotProtocol, Status, Message, FullStatus};
use crate::validation::SessionParams;
use polkadot_validation::GenericStatement;
use polkadot_primitives::{Block, Hash, SessionKey};
use polkadot_primitives::{Block, Hash};
use polkadot_primitives::parachain::{
CandidateReceipt, HeadData, PoVBlock, BlockData, CollatorId, ValidatorId,
StructuredUnroutedIngress,
StructuredUnroutedIngress
};
use substrate_primitives::crypto::UncheckedInto;
use parity_codec::Encode;
use codec::Encode;
use substrate_network::{
PeerId, Context, config::Roles, message::generic::ConsensusMessage,
specialization::NetworkSpecialization,
@@ -96,7 +96,7 @@ fn make_status(status: &Status, roles: Roles) -> FullStatus {
}
}
fn make_validation_session(parent_hash: Hash, local_key: SessionKey) -> SessionParams {
fn make_validation_session(parent_hash: Hash, local_key: ValidatorId) -> SessionParams {
SessionParams {
local_session_key: Some(local_key),
parent_hash,
@@ -131,13 +131,13 @@ fn sends_session_key() {
let mut ctx = TestContext::default();
let params = make_validation_session(parent_hash, local_key.clone());
protocol.new_validation_session(&mut ctx, params);
assert!(ctx.has_message(peer_a, Message::SessionKey(local_key.clone())));
assert!(ctx.has_message(peer_a, Message::ValidatorId(local_key.clone())));
}
{
let mut ctx = TestContext::default();
protocol.on_connect(&mut ctx, peer_b.clone(), make_status(&collator_status, Roles::NONE));
assert!(ctx.has_message(peer_b.clone(), Message::SessionKey(local_key)));
assert!(ctx.has_message(peer_b.clone(), Message::ValidatorId(local_key)));
}
}
@@ -186,13 +186,13 @@ fn fetches_from_those_with_knowledge() {
{
let mut ctx = TestContext::default();
protocol.on_connect(&mut ctx, peer_a.clone(), make_status(&status, Roles::AUTHORITY));
assert!(ctx.has_message(peer_a.clone(), Message::SessionKey(local_key)));
assert!(ctx.has_message(peer_a.clone(), Message::ValidatorId(local_key)));
}
// peer A gives session key and gets asked for data.
{
let mut ctx = TestContext::default();
on_message(&mut protocol, &mut ctx, peer_a.clone(), Message::SessionKey(a_key.clone()));
on_message(&mut protocol, &mut ctx, peer_a.clone(), Message::ValidatorId(a_key.clone()));
assert!(protocol.validators.contains_key(&a_key));
assert!(ctx.has_message(peer_a.clone(), Message::RequestPovBlock(1, parent_hash, candidate_hash)));
}
@@ -203,7 +203,7 @@ fn fetches_from_those_with_knowledge() {
{
let mut ctx = TestContext::default();
protocol.on_connect(&mut ctx, peer_b.clone(), make_status(&status, Roles::AUTHORITY));
on_message(&mut protocol, &mut ctx, peer_b.clone(), Message::SessionKey(b_key.clone()));
on_message(&mut protocol, &mut ctx, peer_b.clone(), Message::ValidatorId(b_key.clone()));
assert!(!ctx.has_message(peer_b.clone(), Message::RequestPovBlock(2, parent_hash, candidate_hash)));
}
@@ -340,8 +340,8 @@ fn many_session_keys() {
let status = Status { collating_for: None };
protocol.on_connect(&mut ctx, peer_a.clone(), make_status(&status, Roles::AUTHORITY));
assert!(ctx.has_message(peer_a.clone(), Message::SessionKey(local_key_a.clone())));
assert!(ctx.has_message(peer_a, Message::SessionKey(local_key_b.clone())));
assert!(ctx.has_message(peer_a.clone(), Message::ValidatorId(local_key_a.clone())));
assert!(ctx.has_message(peer_a, Message::ValidatorId(local_key_b.clone())));
}
let peer_b = PeerId::random();
@@ -354,7 +354,7 @@ fn many_session_keys() {
let status = Status { collating_for: None };
protocol.on_connect(&mut ctx, peer_b.clone(), make_status(&status, Roles::AUTHORITY));
assert!(!ctx.has_message(peer_b.clone(), Message::SessionKey(local_key_a.clone())));
assert!(ctx.has_message(peer_b, Message::SessionKey(local_key_b.clone())));
assert!(!ctx.has_message(peer_b.clone(), Message::ValidatorId(local_key_a.clone())));
assert!(ctx.has_message(peer_b, Message::ValidatorId(local_key_b.clone())));
}
}
+10 -7
View File
@@ -23,11 +23,11 @@ use crate::gossip::GossipMessage;
use substrate_network::Context as NetContext;
use substrate_network::consensus_gossip::TopicNotification;
use substrate_primitives::{NativeOrEncoded, ExecutionContext};
use substrate_keyring::Ed25519Keyring;
use substrate_keyring::Sr25519Keyring;
use crate::PolkadotProtocol;
use polkadot_validation::{SharedTable, MessagesFrom, Network};
use polkadot_primitives::{SessionKey, Block, Hash, Header, BlockId};
use polkadot_primitives::{Block, Hash, Header, BlockId};
use polkadot_primitives::parachain::{
Id as ParaId, Chain, DutyRoster, ParachainHost, OutgoingMessage,
ValidatorId, StructuredUnroutedIngress, BlockIngressRoots, Status,
@@ -41,7 +41,7 @@ use sr_primitives::traits::{ApiRef, ProvideRuntimeApi};
use std::collections::HashMap;
use std::sync::Arc;
use futures::{prelude::*, sync::mpsc};
use parity_codec::Encode;
use codec::Encode;
use super::TestContext;
@@ -398,20 +398,23 @@ impl IngressBuilder {
}
}
fn make_table(data: &ApiData, local_key: &Ed25519Keyring, parent_hash: Hash) -> Arc<SharedTable> {
fn make_table(data: &ApiData, local_key: &Sr25519Keyring, parent_hash: Hash) -> Arc<SharedTable> {
use av_store::Store;
use substrate_primitives::crypto::Pair;
let sr_pair = local_key.pair();
let local_key = polkadot_primitives::parachain::ValidatorPair::from(local_key.pair());
let store = Store::new_in_memory();
let (group_info, _) = ::polkadot_validation::make_group_info(
DutyRoster { validator_duty: data.duties.clone() },
&data.validators, // only possible as long as parachain crypto === aura crypto
SessionKey::from(*local_key)
Some(sr_pair.public().into()),
).unwrap();
Arc::new(SharedTable::new(
data.validators.as_slice(),
data.validators.clone(),
group_info,
Arc::new(local_key.pair()),
Some(Arc::new(local_key)),
parent_hash,
store,
None,
+7 -7
View File
@@ -28,10 +28,10 @@ use substrate_network::consensus_gossip::{
use polkadot_validation::{
Network as ParachainNetwork, SharedTable, Collators, Statement, GenericStatement, SignedStatement,
};
use polkadot_primitives::{Block, BlockId, Hash, SessionKey};
use polkadot_primitives::{Block, BlockId, Hash};
use polkadot_primitives::parachain::{
Id as ParaId, Collation, Extrinsic, ParachainHost, CandidateReceipt, CollatorId,
ValidatorId, PoVBlock, ValidatorIndex,
ValidatorId, PoVBlock, ValidatorIndex
};
use futures::prelude::*;
@@ -54,7 +54,7 @@ use super::PolkadotProtocol;
pub use polkadot_validation::Incoming;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
/// An executor suitable for dispatching async consensus tasks.
pub trait Executor {
@@ -120,7 +120,7 @@ impl Stream for GossipMessageStream {
};
debug!(target: "validation", "Processing statement for live validation session");
if let Some(gmsg) = GossipMessage::decode(&mut &msg.message[..]) {
if let Ok(gmsg) = GossipMessage::decode(&mut &msg.message[..]) {
return Ok(Async::Ready(Some((gmsg, msg.sender))))
}
}
@@ -186,11 +186,11 @@ impl NetworkService for super::NetworkService {
/// Params to a current validation session.
pub struct SessionParams {
/// The local session key.
pub local_session_key: Option<SessionKey>,
pub local_session_key: Option<ValidatorId>,
/// The parent hash.
pub parent_hash: Hash,
/// The authorities.
pub authorities: Vec<SessionKey>,
pub authorities: Vec<ValidatorId>,
}
/// Wrapper around the network service
@@ -336,7 +336,7 @@ impl<P, E, N, T> ParachainNetwork for ValidationNetwork<P, E, N, T> where
let local_session_key = table.session_key();
let build_fetcher = self.instantiate_session(SessionParams {
local_session_key: Some(local_session_key),
local_session_key,
parent_hash,
authorities: authorities.to_vec(),
});
+12 -3
View File
@@ -6,11 +6,10 @@ description = "Types and utilities for creating and working with parachains"
edition = "2018"
[dependencies]
codec = { package = "parity-codec", version = "4.1", default-features = false, features = [ "derive" ] }
codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = [ "derive" ] }
wasmi = { version = "0.4.3", optional = true }
derive_more = { version = "0.14", optional = true }
serde = { version = "1.0", default-features = false, features = [ "derive" ] }
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
lazy_static = { version = "1.3.0", optional = true }
parking_lot = { version = "0.7.1", optional = true }
@@ -27,4 +26,14 @@ halt = { path = "../test-parachains/halt" }
[features]
default = ["std"]
wasm-api = []
std = [ "codec/std", "wasmi", "derive_more", "serde/std", "rstd/std", "shared_memory", "lazy_static", "parking_lot", "log" ]
std = [
"codec/std",
"wasmi",
"derive_more",
"serde/std",
"rstd/std",
"shared_memory",
"lazy_static",
"parking_lot",
"log"
]
+36 -30
View File
@@ -51,22 +51,9 @@ pub mod wasm_executor;
#[cfg(feature = "wasm-api")]
pub mod wasm_api;
use codec::{Encode, Decode};
use rstd::vec::Vec;
struct TrailingZeroInput<'a>(&'a [u8]);
impl<'a> codec::Input for TrailingZeroInput<'a> {
fn read(&mut self, into: &mut [u8]) -> usize {
let len = into.len().min(self.0.len());
into[..len].copy_from_slice(&self.0[..len]);
for i in &mut into[len..] {
*i = 0;
}
self.0 = &self.0[len..];
len
}
}
use codec::{Encode, Decode};
/// Validation parameters for evaluating the parachain validity function.
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
@@ -110,6 +97,40 @@ impl From<codec::Compact<Id>> for Id {
}
}
impl From<Id> for u32 {
fn from(x: Id) -> Self { x.0 }
}
impl From<u32> for Id {
fn from(x: u32) -> Self { Id(x) }
}
impl Id {
/// Convert this Id into its inner representation.
pub fn into_inner(self) -> u32 {
self.0
}
}
// TODO: Remove all of this, move sr-primitives::AccountIdConversion to own crate and and use that.
// #360
struct TrailingZeroInput<'a>(&'a [u8]);
impl<'a> codec::Input for TrailingZeroInput<'a> {
fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
Ok(None)
}
fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
let len = into.len().min(self.0.len());
into[..len].copy_from_slice(&self.0[..len]);
for i in &mut into[len..] {
*i = 0;
}
self.0 = &self.0[len..];
Ok(())
}
}
/// This type can be converted into and possibly from an AccountId (which itself is generic).
pub trait AccountIdConversion<AccountId>: Sized {
/// Convert into an account ID. This is infallible.
@@ -131,7 +152,7 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
x.using_encoded(|d| {
if &d[0..4] != b"para" { return None }
let mut cursor = &d[4..];
let result = Decode::decode(&mut cursor)?;
let result = Decode::decode(&mut cursor).ok()?;
if cursor.iter().all(|x| *x == 0) {
Some(result)
} else {
@@ -141,21 +162,6 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
}
}
impl From<Id> for u32 {
fn from(x: Id) -> Self { x.0 }
}
impl From<u32> for Id {
fn from(x: u32) -> Self { Id(x) }
}
impl Id {
/// Convert this Id into its inner representation.
pub fn into_inner(self) -> u32 {
self.0
}
}
/// An incoming message.
#[derive(PartialEq, Eq, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Encode))]
+2 -3
View File
@@ -431,7 +431,7 @@ pub fn validate_candidate_internal<E: Externalities>(
let len_offset = len_offset as usize;
let len = u32::decode(&mut &len_bytes[..])
.ok_or_else(|| Error::BadReturn)? as usize;
.map_err(|_| Error::BadReturn)? as usize;
let return_offset = if len > len_offset {
return Err(Error::BadReturn);
@@ -445,8 +445,7 @@ pub fn validate_candidate_internal<E: Externalities>(
}
ValidationResult::decode(&mut &mem[return_offset..][..len])
.ok_or_else(|| Error::BadReturn)
.map_err(Into::into)
.map_err(|_| Error::BadReturn.into())
})
}
_ => Err(Error::BadReturn),
@@ -95,7 +95,7 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
let (header_buf, rest) = data.split_at_mut(1024);
let mut header_buf: &[u8] = header_buf;
let header = ValidationHeader::decode(&mut header_buf)
.ok_or_else(|| format!("Error decoding validation request."))?;
.map_err(|_| format!("Error decoding validation request."))?;
debug!("Candidate header: {:?}", header);
let (code, rest) = rest.split_at_mut(MAX_CODE_MEM);
let (code, _) = code.split_at_mut(header.code_size as usize);
+1 -1
View File
@@ -169,7 +169,7 @@ fn processes_messages() {
};
let bad_message_data = vec![1];
assert!(AddMessage::decode(&mut &bad_message_data[..]).is_none());
assert!(AddMessage::decode(&mut &bad_message_data[..]).is_err());
let ret = parachain::wasm_executor::validate_candidate(
TEST_CODE,
+7 -4
View File
@@ -6,14 +6,16 @@ edition = "2018"
[dependencies]
serde = { version = "1.0", optional = true, features = ["derive"] }
parity-codec = { version = "4.1", default-features = false, features = ["bit-vec"] }
parity-scale-codec = { version = "1.0.5", default-features = false, features = ["bit-vec", "derive"] }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
application-crypto = { package = "substrate-application-crypto", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
substrate-client = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
sr-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
runtime_primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
polkadot-parachain = { path = "../parachain", default-features = false }
bitvec = { version = "0.11", default-features = false, features = ["alloc"] }
bitvec = { version = "0.14.0", default-features = false, features = ["alloc"] }
babe = { package = "srml-babe", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
[dev-dependencies]
substrate-serializer = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
@@ -22,7 +24,7 @@ pretty_assertions = "0.5.1"
[features]
default = ["std"]
std = [
"parity-codec/std",
"parity-scale-codec/std",
"primitives/std",
"substrate-client/std",
"rstd/std",
@@ -30,5 +32,6 @@ std = [
"runtime_primitives/std",
"serde",
"polkadot-parachain/std",
"bitvec/std"
"bitvec/std",
"babe/std"
]
+7 -27
View File
@@ -21,18 +21,19 @@
#![cfg_attr(not(feature = "std"), no_std)]
use runtime_primitives::{generic, AnySignature};
use primitives::ed25519;
pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT, Verify};
pub mod parachain;
pub use parity_codec::Compact;
pub use parity_scale_codec::Compact;
/// An index to a block.
/// 32-bits will allow for 136 years of blocks assuming 1 block per second.
/// TODO: switch to u32 (https://github.com/paritytech/polkadot/issues/221)
pub type BlockNumber = u64;
pub type BlockNumber = u32;
/// An instant or duration in time.
pub type Moment = u64;
/// Alias to 512-bit hash when used in the context of a signature on the relay chain.
/// Equipped with logic for possibly "unsigned" messages.
@@ -41,8 +42,7 @@ pub type Signature = AnySignature;
/// Alias to an sr25519 or ed25519 key.
pub type AccountId = <Signature as Verify>::Signer;
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
/// never know...
/// The type for looking up accounts. We don't expect more than 4 billion of them.
pub type AccountIndex = u32;
/// Identifier for a chain. 32-bit should be plenty.
@@ -52,13 +52,7 @@ pub type ChainId = u32;
pub type Hash = primitives::H256;
/// Index of a transaction in the relay chain. 32-bit should be plenty.
pub type Nonce = u64;
/// Signature with which authorities sign blocks.
pub type SessionSignature = ed25519::Signature;
/// Identity that authorities use.
pub type SessionKey = ed25519::Public;
pub type Nonce = u32;
/// The balance of an account.
/// 128-bits (or 38 significant decimal figures) will allow for 10m currency (10^7) at a resolution
@@ -69,20 +63,6 @@ pub type SessionKey = ed25519::Public;
/// that 32 bits may be multiplied with a balance in 128 bits without worrying about overflow.
pub type Balance = u128;
/// The aura crypto scheme defined via the keypair type.
#[cfg(feature = "std")]
pub type AuraPair = ed25519::Pair;
/// The Ed25519 pub key of an session that belongs to an Aura authority of the chain.
pub type AuraId = ed25519::Public;
/// The Parachain crypto scheme defined via the keypair type.
#[cfg(feature = "std")]
pub type ParachainPair = ed25519::Pair;
/// The Ed25519 public key used to authenticate signatures on parachain data.
pub type ParachainPublic = ed25519::Public;
/// Header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type.
+33 -9
View File
@@ -18,7 +18,7 @@
use rstd::prelude::*;
use rstd::cmp::Ordering;
use parity_codec::{Encode, Decode};
use parity_scale_codec::{Encode, Decode};
use bitvec::vec::BitVec;
use super::{Hash, Balance, BlockNumber};
@@ -27,32 +27,56 @@ use serde::{Serialize, Deserialize};
#[cfg(feature = "std")]
use primitives::bytes;
use primitives::ed25519;
use application_crypto::KeyTypeId;
pub use polkadot_parachain::{
Id, AccountIdConversion, ParachainDispatchOrigin, UpwardMessage,
};
/// The key type ID for a collator key.
pub const COLLATOR_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"coll");
mod collator_app {
use application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::COLLATOR_KEY_TYPE_ID);
}
/// Identity that collators use.
pub type CollatorId = ed25519::Public;
pub type CollatorId = collator_app::Public;
/// A Parachain collator keypair.
#[cfg(feature = "std")]
pub type CollatorPair = collator_app::Pair;
/// Signature on candidate's block data by a collator.
pub type CollatorSignature = ed25519::Signature;
pub type CollatorSignature = collator_app::Signature;
/// The key type ID for a parachain validator key.
pub const PARACHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"para");
mod validator_app {
use application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::PARACHAIN_KEY_TYPE_ID);
}
/// Identity that parachain validators use when signing validation messages.
///
/// For now we assert that parachain validator set is exactly equivalent to the (Aura) authority set, and
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
pub type ValidatorId = super::SessionKey;
pub type ValidatorId = validator_app::Public;
/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when appropriate.
pub type ValidatorIndex = u32;
/// A Parachain validator keypair.
#[cfg(feature = "std")]
pub type ValidatorPair = validator_app::Pair;
/// Signature with which parachain validators sign blocks.
///
/// For now we assert that parachain validator set is exactly equivalent to the (Aura) authority set, and
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
pub type ValidatorSignature = super::SessionSignature;
pub type ValidatorSignature = validator_app::Signature;
/// Identifier for a chain, either one of a number of parachains or the relay chain.
#[derive(Copy, Clone, PartialEq, Encode, Decode)]
@@ -143,7 +167,7 @@ impl CandidateReceipt {
/// Check integrity vs. provided block data.
pub fn check_signature(&self) -> Result<(), ()> {
use runtime_primitives::traits::Verify;
use runtime_primitives::traits::AppVerify;
if self.signature.verify(self.block_data_hash.as_ref(), &self.collator) {
Ok(())
@@ -292,11 +316,11 @@ pub enum ValidityAttestation {
/// implicit validity attestation by issuing.
/// This corresponds to issuance of a `Candidate` statement.
#[codec(index = "1")]
Implicit(CollatorSignature),
Implicit(ValidatorSignature),
/// An explicit attestation. This corresponds to issuance of a
/// `Valid` statement.
#[codec(index = "2")]
Explicit(CollatorSignature),
Explicit(ValidatorSignature),
}
/// An attested candidate.
+13 -8
View File
@@ -6,14 +6,14 @@ edition = "2018"
build = "build.rs"
[dependencies]
bitvec = { version = "0.11", default-features = false, features = ["alloc"] }
bitvec = { version = "0.14.0", default-features = false, features = ["alloc"] }
rustc-hex = { version = "2.0.1", default-features = false }
log = { version = "0.3", optional = true }
serde = { version = "1.0", default-features = false }
serde_derive = { version = "1.0", optional = true }
safe-mix = { version = "1.0", default-features = false}
primitives = { package = "polkadot-primitives", path = "../primitives", default-features = false }
parity-codec = { version = "4.1", default-features = false, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
substrate-serializer = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
sr-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
@@ -21,9 +21,7 @@ srml-support = { git = "https://github.com/paritytech/substrate", default-featur
substrate-primitives = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
client = { package = "substrate-client", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
inherents = { package = "substrate-inherents", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
consensus_aura = { package = "substrate-consensus-aura-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
offchain_primitives = { package = "substrate-offchain-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
aura = { package = "srml-aura", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
authorship = { package = "srml-authorship", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
balances = { package = "srml-balances", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
collective = { package = "srml-collective", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
@@ -32,7 +30,9 @@ democracy = { package = "srml-democracy", git = "https://github.com/paritytech/s
executive = { package = "srml-executive", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
finality-tracker = { package = "srml-finality-tracker", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
grandpa = { package = "srml-grandpa", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
im-online = { package = "srml-im-online", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
indices = { package = "srml-indices", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
membership = { package = "srml-membership", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
sr-primitives = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
session = { package = "srml-session", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
staking = { package = "srml-staking", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
@@ -41,6 +41,9 @@ system = { package = "srml-system", git = "https://github.com/paritytech/substra
timestamp = { package = "srml-timestamp", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
treasury = { package = "srml-treasury", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
version = { package = "sr-version", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
babe = { package = "srml-babe", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
babe-primitives = { package = "substrate-consensus-babe-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
substrate-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
[dev-dependencies]
hex-literal = "0.2.0"
@@ -48,7 +51,7 @@ libsecp256k1 = "0.2.1"
tiny-keccak = "1.4.2"
keyring = { package = "substrate-keyring", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
substrate-trie = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
trie-db = "0.14"
trie-db = "0.15"
[build-dependencies]
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.1" }
@@ -60,7 +63,7 @@ std = [
"bitvec/std",
"primitives/std",
"rustc-hex/std",
"parity-codec/std",
"codec/std",
"inherents/std",
"substrate-primitives/std",
"client/std",
@@ -68,7 +71,6 @@ std = [
"rstd/std",
"sr-io/std",
"srml-support/std",
"aura/std",
"authorship/std",
"balances/std",
"collective/std",
@@ -77,7 +79,9 @@ std = [
"executive/std",
"finality-tracker/std",
"grandpa/std",
"im-online/std",
"indices/std",
"membership/std",
"sr-primitives/std",
"session/std",
"staking/std",
@@ -90,5 +94,6 @@ std = [
"serde/std",
"log",
"safe-mix/std",
"consensus_aura/std",
"babe/std",
"babe-primitives/std",
]
+1 -1
View File
@@ -20,7 +20,7 @@
//! as well.
use rstd::prelude::*;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use srml_support::{decl_storage, decl_module, ensure};
use primitives::{Hash, parachain::{AttestedCandidate, CandidateReceipt, Id as ParaId}};
+8 -8
View File
@@ -21,7 +21,7 @@ use sr_io::{keccak_256, secp256k1_ecdsa_recover};
use srml_support::{StorageValue, StorageMap, decl_event, decl_storage, decl_module};
use srml_support::traits::{Currency, Get};
use system::ensure_none;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
#[cfg(feature = "std")]
use sr_primitives::traits::Zero;
use sr_primitives::{
@@ -200,7 +200,7 @@ mod tests {
use sr_io::with_externalities;
use substrate_primitives::{H256, Blake2Hasher};
use parity_codec::{Decode, Encode};
use codec::{Decode, Encode};
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup, ConvertInto}, testing::Header};
@@ -210,20 +210,20 @@ mod tests {
impl_outer_origin! {
pub enum Origin for Test {}
}
// For testing the module, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of modules we want to use.
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
}
impl system::Trait for Test {
type Origin = Origin;
type Call = ();
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -305,12 +305,12 @@ mod tests {
// This function basically just builds a genesis storage key/value store according to
// our desired mockup.
fn new_test_ext() -> sr_io::TestExternalities<Blake2Hasher> {
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap().0;
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap();
// We use default for brevity, but you can configure as desired if needed.
t.extend(balances::GenesisConfig::<Test>::default().build_storage().unwrap().0);
t.extend(GenesisConfig::<Test>{
balances::GenesisConfig::<Test>::default().assimilate_storage(&mut t).unwrap();
GenesisConfig::<Test>{
claims: vec![(alice_eth(), 100)],
}.build_storage().unwrap().0);
}.assimilate_storage(&mut t).unwrap();
t.into()
}
+20 -6
View File
@@ -19,17 +19,31 @@ pub mod currency {
use primitives::Balance;
pub const DOTS: Balance = 1_000_000_000_000;
pub const BUCKS: Balance = DOTS / 100;
pub const CENTS: Balance = BUCKS / 100;
pub const DOLLARS: Balance = DOTS / 100;
pub const CENTS: Balance = DOLLARS / 100;
pub const MILLICENTS: Balance = CENTS / 1_000;
}
/// Time.
pub mod time {
pub const SECS_PER_BLOCK: u64 = 6;
pub const MINUTES: u64 = 60 / SECS_PER_BLOCK;
pub const HOURS: u64 = MINUTES * 60;
pub const DAYS: u64 = HOURS * 24;
use primitives::{Moment, BlockNumber};
pub const MILLISECS_PER_BLOCK: Moment = 6000;
pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000;
pub const SLOT_DURATION: Moment = 1650;
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES;
pub const EPOCH_DURATION_IN_SLOTS: u64 = {
const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64;
(EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64
};
// These time units are defined in number of blocks.
pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
}
/// Fee-related.
+2 -2
View File
@@ -17,7 +17,7 @@
//! A module for manually curated GRANDPA set.
use {grandpa, system};
use parity_codec::Decode;
use codec::Decode;
use sr_primitives::traits::{Hash as HashT, BlakeTwo256, Zero};
use sr_primitives::weights::SimpleDispatchInfo;
use rstd::prelude::*;
@@ -79,7 +79,7 @@ decl_module! {
let offset = (i * 4 % 32) as usize;
// number of roles remaining to select from.
let remaining = (voter_count - i) as usize;
let remaining = rstd::cmp::max(1, (voter_count - i) as usize);
// 8 32-bit ints per 256-bit seed.
let voter_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
+109 -44
View File
@@ -30,8 +30,8 @@ mod slots;
use rstd::prelude::*;
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
use primitives::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, SessionKey, Signature,
parachain, AuraId
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
parachain,
};
use client::{
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
@@ -44,6 +44,7 @@ use sr_primitives::{
};
use version::RuntimeVersion;
use grandpa::{AuthorityId as GrandpaId, fg_primitives::{self, ScheduledChange}};
use babe_primitives::AuthorityId as BabeId;
use elections::VoteIndex;
#[cfg(any(feature = "std", test))]
use version::NativeVersion;
@@ -51,6 +52,7 @@ use substrate_primitives::OpaqueMetadata;
use srml_support::{
parameter_types, construct_runtime, traits::{SplitTwoWays, Currency}
};
use im_online::AuthorityId as ImOnlineId;
#[cfg(feature = "std")]
pub use staking::StakerStatus;
@@ -97,7 +99,7 @@ pub fn native_version() -> NativeVersion {
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: BlockNumber = 250;
pub const MaximumBlockWeight: Weight = 1_000_000_000;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
@@ -105,6 +107,7 @@ parameter_types! {
impl system::Trait for Runtime {
type Origin = Origin;
type Call = Call;
type Index = Nonce;
type BlockNumber = BlockNumber;
type Hash = Hash;
@@ -120,9 +123,14 @@ impl system::Trait for Runtime {
type AvailableBlockRatio = AvailableBlockRatio;
}
impl aura::Trait for Runtime {
type HandleReport = aura::StakingSlasher<Runtime>;
type AuthorityId = AuraId;
parameter_types! {
pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS;
pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
}
impl babe::Trait for Runtime {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
}
impl indices::Trait for Runtime {
@@ -165,22 +173,22 @@ impl balances::Trait for Runtime {
}
parameter_types! {
pub const MinimumPeriod: u64 = SECS_PER_BLOCK / 2;
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
}
impl timestamp::Trait for Runtime {
type Moment = u64;
type OnTimestampSet = Aura;
type OnTimestampSet = Babe;
type MinimumPeriod = MinimumPeriod;
}
parameter_types! {
pub const UncleGenerations: u64 = 0;
pub const UncleGenerations: u32 = 0;
}
// TODO: substrate#2986 implement this properly
impl authorship::Trait for Runtime {
type FindAuthor = ();
type FindAuthor = session::FindAccountFromAuthorIndex<Self, Babe>;
type UncleGenerations = UncleGenerations;
type FilterUncle = ();
type EventHandler = ();
@@ -191,11 +199,17 @@ parameter_types! {
pub const Offset: BlockNumber = 0;
}
type SessionHandlers = (Grandpa, Aura);
type SessionHandlers = (Grandpa, Babe, ImOnline, Parachains);
impl_opaque_keys! {
pub struct SessionKeys {
#[id(key_types::ED25519)]
pub ed25519: GrandpaId,
#[id(key_types::GRANDPA)]
pub grandpa: GrandpaId,
#[id(key_types::BABE)]
pub babe: BabeId,
#[id(key_types::IM_ONLINE)]
pub im_online: ImOnlineId,
#[id(parachain::PARACHAIN_KEY_TYPE_ID)]
pub parachain_validator: parachain::ValidatorId,
}
}
@@ -208,7 +222,7 @@ impl_opaque_keys! {
impl session::Trait for Runtime {
type OnSessionEnding = Staking;
type SessionHandler = SessionHandlers;
type ShouldEndSession = session::PeriodicSessions<Period, Offset>;
type ShouldEndSession = Babe;
type Event = Event;
type Keys = SessionKeys;
type SelectInitialValidators = Staking;
@@ -243,11 +257,9 @@ parameter_types! {
pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
pub const EmergencyVotingPeriod: BlockNumber = 3 * 24 * 60 * MINUTES;
pub const MinimumDeposit: Balance = 100 * BUCKS;
pub const MinimumDeposit: Balance = 100 * DOLLARS;
pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES;
pub const CooloffPeriod: BlockNumber = 30 * 24 * 60 * MINUTES;
pub const AttestationPeriod: BlockNumber = 60 * MINUTES * 3;
pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
}
impl democracy::Trait for Runtime {
@@ -259,26 +271,35 @@ impl democracy::Trait for Runtime {
type VotingPeriod = VotingPeriod;
type EmergencyVotingPeriod = EmergencyVotingPeriod;
type MinimumDeposit = MinimumDeposit;
type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilInstance>;
type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>;
type ExternalPushOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalInstance>;
type EmergencyOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilInstance>;
type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>;
type VetoOrigin = collective::EnsureMember<AccountId, CouncilInstance>;
/// A straight majority of the council can decide what their next motion is.
type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>;
/// A super-majority can have the next scheduled referendum be a straight majority-carries vote.
type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>;
/// A unanimous council can have the next scheduled referendum be a straight default-carries
/// (NTB) vote.
type ExternalDefaultOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>;
/// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
/// be tabled immediately and with a shorter voting/enactment period.
type FastTrackOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>;
// To cancel a proposal which has been passed, 2/3 of the council must agree to it.
type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>;
// Any single technical committee member may veto a coming council proposal, however they can
// only do it once and it lasts only for the cooloff period.
type VetoOrigin = collective::EnsureMember<AccountId, TechnicalCollective>;
type CooloffPeriod = CooloffPeriod;
}
type CouncilInstance = collective::Instance1;
impl collective::Trait<CouncilInstance> for Runtime {
type CouncilCollective = collective::Instance1;
impl collective::Trait<CouncilCollective> for Runtime {
type Origin = Origin;
type Proposal = Call;
type Event = Event;
}
parameter_types! {
pub const CandidacyBond: Balance = 10 * BUCKS;
pub const VotingBond: Balance = 1 * BUCKS;
pub const VotingFee: Balance = 2 * BUCKS;
pub const CandidacyBond: Balance = 10 * DOLLARS;
pub const VotingBond: Balance = 1 * DOLLARS;
pub const VotingFee: Balance = 2 * DOLLARS;
pub const PresentSlashPerVoter: Balance = 1 * CENTS;
pub const CarryCount: u32 = 6;
// one additional vote should go by before an inactive voter can be reaped.
@@ -305,24 +326,34 @@ impl elections::Trait for Runtime {
type DecayRatio = DecayRatio;
}
type TechnicalInstance = collective::Instance2;
impl collective::Trait<TechnicalInstance> for Runtime {
type TechnicalCollective = collective::Instance2;
impl collective::Trait<TechnicalCollective> for Runtime {
type Origin = Origin;
type Proposal = Call;
type Event = Event;
}
impl membership::Trait<membership::Instance1> for Runtime {
type Event = Event;
type AddOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
type RemoveOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
type SwapOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
type ResetOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>;
type MembershipInitialized = TechnicalCommittee;
type MembershipChanged = TechnicalCommittee;
}
parameter_types! {
pub const ProposalBond: Permill = Permill::from_percent(5);
pub const ProposalBondMinimum: Balance = 1 * BUCKS;
pub const ProposalBondMinimum: Balance = 1 * DOLLARS;
pub const SpendPeriod: BlockNumber = 1 * DAYS;
pub const Burn: Permill = Permill::from_percent(50);
}
impl treasury::Trait for Runtime {
type Currency = Balances;
type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilInstance>;
type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilInstance>;
type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilCollective>;
type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilCollective>;
type Event = Event;
type MintedForSpending = ();
type ProposalRejection = ();
@@ -332,6 +363,12 @@ impl treasury::Trait for Runtime {
type Burn = Burn;
}
impl im_online::Trait for Runtime {
type Call = Call;
type Event = Event;
type UncheckedExtrinsic = UncheckedExtrinsic;
}
impl grandpa::Trait for Runtime {
type Event = Event;
}
@@ -347,6 +384,10 @@ impl finality_tracker::Trait for Runtime {
type ReportLatency = ReportLatency;
}
parameter_types! {
pub const AttestationPeriod: BlockNumber = 50;
}
impl attestations::Trait for Runtime {
type AttestationPeriod = AttestationPeriod;
type ValidatorIdentities = parachains::ValidatorIdentities<Runtime>;
@@ -395,8 +436,8 @@ construct_runtime!(
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Module, Call, Storage, Config, Event},
Aura: aura::{Module, Config<T>, Inherent(Timestamp)},
Timestamp: timestamp::{Module, Call, Storage, Inherent},
Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
Authorship: authorship::{Module, Call, Storage},
Indices: indices,
Balances: balances,
@@ -406,6 +447,7 @@ construct_runtime!(
Council: collective::<Instance1>::{Module, Call, Storage, Origin<T>, Event<T>, Config<T>},
TechnicalCommittee: collective::<Instance2>::{Module, Call, Storage, Origin<T>, Event<T>, Config<T>},
Elections: elections::{Module, Call, Storage, Event<T>, Config<T>},
TechnicalMembership: membership::<Instance1>::{Module, Call, Storage, Event<T>, Config<T>},
FinalityTracker: finality_tracker::{Module, Call, Inherent},
Grandpa: grandpa::{Module, Call, Storage, Config, Event},
CuratedGrandpa: curated_grandpa::{Module, Call, Config<T>, Storage},
@@ -415,6 +457,7 @@ construct_runtime!(
Slots: slots::{Module, Call, Storage, Event<T>},
Claims: claims::{Module, Call, Storage, Event<T>, Config<T>, ValidateUnsigned},
Sudo: sudo,
ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config<T>},
}
);
@@ -430,6 +473,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (
system::CheckGenesis<Runtime>,
system::CheckEra<Runtime>,
system::CheckNonce<Runtime>,
system::CheckWeight<Runtime>,
@@ -499,7 +543,7 @@ impl_runtime_apis! {
impl parachain::ParachainHost<Block> for Runtime {
fn validators() -> Vec<parachain::ValidatorId> {
Aura::authorities() // only possible as long as parachain validator crypto === aura crypto
Parachains::authorities()
}
fn duty_roster() -> parachain::DutyRoster {
Parachains::calculate_duty_roster().0
@@ -531,19 +575,40 @@ impl_runtime_apis! {
None // disable forced changes.
}
fn grandpa_authorities() -> Vec<(SessionKey, u64)> {
fn grandpa_authorities() -> Vec<(GrandpaId, u64)> {
Grandpa::grandpa_authorities()
}
}
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> u64 {
Aura::slot_duration()
}
fn authorities() -> Vec<AuraId> {
Aura::authorities()
impl babe_primitives::BabeApi<Block> for Runtime {
fn startup_data() -> babe_primitives::BabeConfiguration {
// The choice of `c` parameter (where `1 - c` represents the
// probability of a slot being empty), is done in accordance to the
// slot duration and expected target block time, for safely
// resisting network delays of maximum two seconds.
// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
babe_primitives::BabeConfiguration {
median_required_blocks: 1000,
slot_duration: Babe::slot_duration(),
c: (278, 1000),
}
}
fn epoch() -> babe_primitives::Epoch {
babe_primitives::Epoch {
start_slot: Babe::epoch_start_slot(),
authorities: Babe::authorities(),
epoch_index: Babe::epoch_index(),
randomness: Babe::randomness(),
duration: EpochDuration::get(),
}
}
}
impl substrate_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string"));
SessionKeys::generate(seed)
}
}
}
+69 -49
View File
@@ -18,14 +18,14 @@
use rstd::prelude::*;
use rstd::collections::btree_map::BTreeMap;
use parity_codec::{Encode, Decode, HasCompact};
use codec::{Encode, Decode, HasCompact};
use srml_support::{decl_storage, decl_module, fail, ensure};
use sr_primitives::traits::{Hash as HashT, BlakeTwo256, Member, CheckedConversion, Saturating, One};
use sr_primitives::weights::SimpleDispatchInfo;
use primitives::{Hash, Balance, ParachainPublic, parachain::{
use primitives::{Hash, Balance, parachain::{
self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion,
ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots,
ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ValidatorId
}};
use {system, session};
use srml_support::{
@@ -33,9 +33,6 @@ use srml_support::{
traits::{Currency, Get, WithdrawReason, ExistenceRequirement}
};
#[cfg(feature = "std")]
use srml_support::storage::hashed::generator;
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
#[cfg(any(feature = "std", test))]
@@ -217,7 +214,7 @@ const WATERMARK_QUEUE_SIZE: usize = 20000;
decl_storage! {
trait Store for Module<T: Trait> as Parachains {
/// All authorities' keys at the moment.
pub Authorities get(authorities) config(authorities): Vec<ParachainPublic>;
pub Authorities get(authorities) config(authorities): Vec<ValidatorId>;
/// Vector of all parachain IDs.
pub Parachains get(active_parachains): Vec<ParaId>;
/// The parachains registered at present.
@@ -252,26 +249,32 @@ decl_storage! {
add_extra_genesis {
config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
config(_phdata): PhantomData<T>;
build(|storage: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, config: &GenesisConfig<T>| {
use sr_primitives::traits::Zero;
build(build::<T>);
}
}
#[cfg(feature = "std")]
fn build<T: Trait>(
storage: &mut (StorageOverlay, ChildrenStorageOverlay),
config: &GenesisConfig<T>
) {
let mut p = config.parachains.clone();
p.sort_unstable_by_key(|&(ref id, _, _)| *id);
p.dedup_by_key(|&mut (ref id, _, _)| *id);
let only_ids: Vec<_> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
let only_ids: Vec<ParaId> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
<Parachains as generator::StorageValue<_>>::put(&only_ids, storage);
sr_io::with_storage(storage, || {
Parachains::put(&only_ids);
for (id, code, genesis) in p {
// no ingress -- a chain cannot be routed to until it is live.
<Code as generator::StorageMap<_, _>>::insert(&id, &code, storage);
<Heads as generator::StorageMap<_, _>>::insert(&id, &genesis, storage);
<Watermarks<T> as generator::StorageMap<_, _>>::insert(&id, &Zero::zero(), storage);
Code::insert(&id, &code);
Heads::insert(&id, &genesis);
<Watermarks<T>>::insert(&id, &sr_primitives::traits::Zero::zero());
}
});
}
}
decl_module! {
/// Parachains module.
@@ -380,7 +383,7 @@ impl<T: Trait> Module<T> {
origin: ParachainDispatchOrigin,
data: &[u8],
) {
if let Some(message_call) = T::Call::decode(&mut &data[..]) {
if let Ok(message_call) = <T as Trait>::Call::decode(&mut &data[..]) {
let origin: <T as Trait>::Origin = match origin {
ParachainDispatchOrigin::Signed =>
system::RawOrigin::Signed(id.into_account()).into(),
@@ -528,6 +531,7 @@ impl<T: Trait> Module<T> {
pub fn calculate_duty_roster() -> (DutyRoster, [u8; 32]) {
let parachains = Self::active_parachains();
let parachain_count = parachains.len();
// TODO: use decode length. substrate #2794
let validator_count = Self::authorities().len();
let validators_per_parachain = if parachain_count != 0 { (validator_count - 1) / parachain_count } else { 0 };
@@ -561,12 +565,12 @@ impl<T: Trait> Module<T> {
let orig_seed = seed.clone().to_fixed_bytes();
// shuffle
for i in 0..(validator_count - 1) {
for i in 0..(validator_count.saturating_sub(1)) {
// 4 bytes of entropy used per cycle, 32 bytes entropy per hash
let offset = (i * 4 % 32) as usize;
// number of roles remaining to select from.
let remaining = (validator_count - i) as usize;
let remaining = rstd::cmp::max(1, (validator_count - i) as usize);
// 8 32-bit ints per 256-bit seed.
let val_index = u32::decode(&mut &seed[offset..offset + 4])
@@ -656,7 +660,7 @@ impl<T: Trait> Module<T> {
-> rstd::result::Result<IncludedBlocks<T>, &'static str>
{
use primitives::parachain::ValidityAttestation;
use sr_primitives::traits::Verify;
use sr_primitives::traits::AppVerify;
// returns groups of slices that have the same chain ID.
// assumes the inner slice is sorted by id.
@@ -834,7 +838,7 @@ impl<T: Trait> Module<T> {
}
impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
type Key = ParachainPublic;
type Key = ValidatorId;
fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued: I)
where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
@@ -881,10 +885,11 @@ mod tests {
testing::{UintAuthorityId, Header},
};
use primitives::{
parachain::{CandidateReceipt, HeadData, ValidityAttestation}, SessionKey,
BlockNumber, AuraId,
parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorId},
BlockNumber,
};
use keyring::Ed25519Keyring;
use crate::constants::time::*;
use keyring::Sr25519Keyring;
use srml_support::{
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
};
@@ -905,13 +910,14 @@ mod tests {
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
}
impl system::Trait for Test {
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -957,9 +963,14 @@ mod tests {
type MinimumPeriod = MinimumPeriod;
}
impl aura::Trait for Test {
type HandleReport = aura::StakingSlasher<Test>;
type AuthorityId = AuraId;
parameter_types! {
pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS;
pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK;
}
impl babe::Trait for Test {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
}
parameter_types! {
@@ -989,7 +1000,7 @@ mod tests {
parameter_types! {
pub const SessionsPerEra: session::SessionIndex = 6;
pub const BondingDuration: staking::EraIndex = 24 * 28;
pub const AttestationPeriod: u64 = 100;
pub const AttestationPeriod: BlockNumber = 100;
}
impl staking::Trait for Test {
@@ -1021,17 +1032,19 @@ mod tests {
fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
use staking::StakerStatus;
use babe::AuthorityId as BabeAuthorityId;
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap();
let (mut t, mut c) = system::GenesisConfig::default().build_storage::<Test>().unwrap();
let authority_keys = [
Ed25519Keyring::Alice,
Ed25519Keyring::Bob,
Ed25519Keyring::Charlie,
Ed25519Keyring::Dave,
Ed25519Keyring::Eve,
Ed25519Keyring::Ferdie,
Ed25519Keyring::One,
Ed25519Keyring::Two,
Sr25519Keyring::Alice,
Sr25519Keyring::Bob,
Sr25519Keyring::Charlie,
Sr25519Keyring::Dave,
Sr25519Keyring::Eve,
Sr25519Keyring::Ferdie,
Sr25519Keyring::One,
Sr25519Keyring::Two,
];
// stashes are the index.
@@ -1039,7 +1052,11 @@ mod tests {
.map(|(i, _k)| (i as u64, UintAuthorityId(i as u64)))
.collect();
let authorities: Vec<_> = authority_keys.iter().map(|k| SessionKey::from(*k)).collect();
let authorities: Vec<_> = authority_keys.iter().map(|k| ValidatorId::from(k.public())).collect();
let babe_authorities: Vec<_> = authority_keys.iter()
.map(|k| BabeAuthorityId::from(k.public()))
.map(|k| (k, 1))
.collect();
// controllers are the index + 1000
let stakers: Vec<_> = (0..authority_keys.len()).map(|i| (
@@ -1051,23 +1068,24 @@ mod tests {
let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
session::GenesisConfig::<Test> {
keys: session_keys,
}.assimilate_storage(&mut t, &mut c).unwrap();
GenesisConfig::<Test> {
parachains,
authorities: authorities.clone(),
_phdata: Default::default(),
}.assimilate_storage(&mut t, &mut c).unwrap();
}.assimilate_storage(&mut t).unwrap();
aura::GenesisConfig::<Test> {
authorities,
}.assimilate_storage(&mut t, &mut c).unwrap();
session::GenesisConfig::<Test> {
keys: session_keys,
}.assimilate_storage(&mut t).unwrap();
babe::GenesisConfig {
authorities: babe_authorities,
}.assimilate_storage(&mut t).unwrap();
balances::GenesisConfig::<Test> {
balances,
vesting: vec![],
}.assimilate_storage(&mut t, &mut c).unwrap();
}.assimilate_storage(&mut t).unwrap();
staking::GenesisConfig::<Test> {
current_era: 0,
@@ -1077,7 +1095,7 @@ mod tests {
offline_slash: Perbill::from_percent(5),
offline_slash_grace: 0,
invulnerables: vec![],
}.assimilate_storage(&mut t, &mut c).unwrap();
}.assimilate_storage(&mut t).unwrap();
t.into()
}
@@ -1094,8 +1112,10 @@ mod tests {
let candidate_hash = candidate.candidate.hash();
let authorities = Parachains::authorities();
let extract_key = |public: SessionKey| {
Ed25519Keyring::from_raw_public(public.0).unwrap()
let extract_key = |public: ValidatorId| {
let mut raw_public = [0; 32];
raw_public.copy_from_slice(public.as_ref());
Sr25519Keyring::from_raw_public(raw_public).unwrap()
};
let validation_entries = duty_roster.validator_duty.iter()
+1 -1
View File
@@ -19,7 +19,7 @@
use rstd::{result, ops::Add, convert::{TryFrom, TryInto}};
use sr_primitives::traits::CheckedSub;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
/// Total number of possible sub ranges of slots.
pub const SLOT_RANGE_COUNT: usize = 10;
+6 -5
View File
@@ -21,7 +21,7 @@
use rstd::{prelude::*, mem::swap, convert::TryInto};
use sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash};
use sr_primitives::weights::SimpleDispatchInfo;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use srml_support::{
decl_module, decl_storage, decl_event, StorageValue, StorageMap, ensure,
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get}
@@ -813,13 +813,14 @@ mod tests {
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
}
impl system::Trait for Test {
type Origin = Origin;
type Call = ();
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -926,11 +927,11 @@ mod tests {
// This function basically just builds a genesis storage key/value store according to
// our desired mock up.
fn new_test_ext() -> sr_io::TestExternalities<Blake2Hasher> {
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap().0;
t.extend(balances::GenesisConfig::<Test>{
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap();
balances::GenesisConfig::<Test>{
balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)],
vesting: vec![],
}.build_storage().unwrap().0);
}.assimilate_storage(&mut t).unwrap();
t.into()
}
+6 -1
View File
@@ -8,6 +8,8 @@ edition = "2018"
parking_lot = "0.9.0"
lazy_static = "1.0"
log = "0.4.6"
futures = "0.1"
exit-future = "0.1"
slog = "^2"
hex-literal = "0.2"
av_store = { package = "polkadot-availability-store", path = "../availability-store" }
@@ -20,7 +22,6 @@ sr-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-ma
sr-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
client = { package = "substrate-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
aura = { package = "substrate-consensus-aura", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
consensus_common = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
grandpa = { package = "substrate-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
grandpa_primitives = { package = "substrate-finality-grandpa-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
@@ -29,3 +30,7 @@ service = { package = "substrate-service", git = "https://github.com/paritytech/
telemetry = { package = "substrate-telemetry", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
transaction_pool = { package = "substrate-transaction-pool", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
substrate-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
srml_babe = { package = "srml-babe", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
im-online = { package = "srml-im-online", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
babe = { package = "substrate-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
babe-primitives = { package = "substrate-consensus-babe-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
+115 -66
View File
@@ -16,17 +16,20 @@
//! Polkadot chain configurations.
use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto};
use polkadot_primitives::{AccountId, SessionKey};
use primitives::{Pair, Public, crypto::UncheckedInto};
use polkadot_primitives::{AccountId, parachain::ValidatorId};
use polkadot_runtime::{
GenesisConfig, CouncilConfig, ElectionsConfig, DemocracyConfig, SystemConfig, AuraConfig,
GenesisConfig, CouncilConfig, ElectionsConfig, DemocracyConfig, SystemConfig, BabeConfig,
SessionConfig, StakingConfig, BalancesConfig, Perbill, SessionKeys, TechnicalCommitteeConfig,
GrandpaConfig, SudoConfig, IndicesConfig, CuratedGrandpaConfig, StakerStatus, WASM_BINARY,
ClaimsConfig,
ClaimsConfig, ImOnlineConfig, ParachainsConfig
};
use polkadot_runtime::constants::{currency::DOTS, time::*};
use telemetry::TelemetryEndpoints;
use hex_literal::hex;
use babe_primitives::AuthorityId as BabeId;
use grandpa::AuthorityId as GrandpaId;
use im_online::AuthorityId as ImOnlineId;
const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
const DEFAULT_PROTOCOL_ID: &str = "dot";
@@ -34,34 +37,58 @@ const DEFAULT_PROTOCOL_ID: &str = "dot";
/// Specialised `ChainSpec`.
pub type ChainSpec = ::service::ChainSpec<GenesisConfig>;
pub fn poc_3_testnet_config() -> Result<ChainSpec, String> {
ChainSpec::from_embedded(include_bytes!("../res/alexander.json"))
pub fn kusama_config() -> Result<ChainSpec, String> {
ChainSpec::from_json_bytes(&include_bytes!("../res/kusama.json")[..])
}
fn session_keys(
babe: BabeId,
grandpa: GrandpaId,
im_online: ImOnlineId,
parachain_validator: ValidatorId
) -> SessionKeys {
SessionKeys { babe, grandpa, im_online, parachain_validator }
}
fn staging_testnet_config_genesis() -> GenesisConfig {
// subkey inspect "$SECRET"
let endowed_accounts = vec![
hex!["42d69e4222c08885a4d6ff65f01852ba4a1599b683ad66286e4603d825e26b49"].unchecked_into(), // 5DaLmkrGTFvSTHBpShqqqRYaydw1sT4u3NCogYiE8Q1LqUUp
hex!["12b782529c22032ed4694e0f6e7d486be7daa6d12088f6bc74d593b3900b8438"].unchecked_into(), // 5CVFESwfkk7NmhQ6FwHCM9roBvr9BGa4vJHFYU8DnGQxrXvz
];
// for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; done
// for i in 1 2 3 4; do for j in session; do subkey -e inspect "$SECRET//$i//$j"; done; done
let initial_authorities: Vec<(AccountId, AccountId, SessionKey)> = vec![(
hex!["543cf15f6a0289e48eb4f30d451d1731c5fb0e1b2c5a4b99439c11808af3432d"].unchecked_into(), // 5Dy9yz2mjwDmTgjkDFxjPBpovKmKAgTndiRiTp4DfrTEdUvi
hex!["8a6ea654337e4a28ce7be124f73ad84702619942722d01cc271e5b421653c56d"].unchecked_into(), // 5FCDLPUMZpZPRfouRfQDZp74typV9SjSxPgG6ymwe5Z3Sbko
hex!["03644a181bc4e4197914aa109f3c97b6fe8c4787a82a1ddfab54e4ebedd8ab20"].unchecked_into(), // 5C99nwu8Ucq1yUJfajviwbqMAejpmaERHpmkPVWiFdxiF6yg
// for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
// for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; done; done
// for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
// for i in 1 2 3 4; do for j in parachains; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
let initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId)> = vec![(
hex!["32a5718e87d16071756d4b1370c411bbbb947eb62f0e6e0b937d5cbfc0ea633b"].unchecked_into(), // 5DD7Q4VEfPTLEdn11CnThoHT5f9xKCrnofWJL5SsvpTghaAT
hex!["bee39fe862c85c91aaf343e130d30b643c6ea0b4406a980206f1df8331f7093b"].unchecked_into(), // 5GNzaEqhrZAtUQhbMe2gn9jBuNWfamWFZHULryFwBUXyd1cG
hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
hex!["76620f7c98bce8619979c2b58cf2b0aff71824126d2b039358729dad993223db"].unchecked_into(), // 5EjvdwATjyFFikdZibVvx1q5uBHhphS2Mnsq5c7yfaYK25vm
hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
),(
hex!["c4957aa922910004f3b006d638b034070407dcb21e0905cb5cca9b58aec7fa3e"].unchecked_into(), // 5GWTeVF49JR9dAMVe4rRAAMXuhEjRAhSiYqQV4LbwpHTDLei
hex!["1adea46f5c3d272cd6426b338dd77d5bca3aff615338c82a0f02f4c62d89280f"].unchecked_into(), // 5CfwEv8TQKnszHNhYPuij6EtLZHCcaN3DgzfPCozcS9oxZzB
hex!["d739e1bb4c2b13ea1fff9be72e72d3bb1b364eb3b26176ab9a9512d386b7510b"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
hex!["b496c98a405ceab59b9e970e59ef61acd7765a19b704e02ab06c1cdfe171e40f"].unchecked_into(), // 5G9VGb8ESBeS8Ca4or43RfhShzk9y7T5iTmxHk5RJsjZwsRx
hex!["86d3a7571dd60139d297e55d8238d0c977b2e208c5af088f7f0136b565b0c103"].unchecked_into(), // 5F7V9Y5FcxKXe1aroqvPeRiUmmeQwTFcL3u9rrPXcMuMiCNx
hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
hex!["e2234d661bee4a04c38392c75d1566200aa9e6ae44dd98ee8765e4cc9af63cb7"].unchecked_into(), // 5HBDAaybNqjmY7ww8ZcZZY1L5LHxvpnyfqJwoB7HhR6raTmG
hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
),(
hex!["6c3d14686e97d393814a09bea4246b9f273dcdbdef6731dcab3430b36820f135"].unchecked_into(), // 5EWdAzp9aJseLKVNeWJwE2K8PD47qzMbKVysCXr67xnEohYL
hex!["7a73b9fcb97cee5c2240d88ca9baea06758fac450efe6f90a72014c939d41857"].unchecked_into(), // 5EqG5RSujgrtSBB5DQvR1Z2EMxAe92sAdWNTNHtX4nL2MkPi
hex!["145791f7187d91398d8b445598f62be39b766d6e33e9d57b69c4d23fca218d7f"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
hex!["ae12f70078a22882bf5135d134468f77301927aa67c376e8c55b7ff127ace115"].unchecked_into(), // 5FzwpgGvk2kk9agow6KsywLYcPzjYc8suKej2bne5G5b9YU3
hex!["7addb914ec8486bbc60643d2647685dcc06373401fa80e09813b630c5831d54b"].unchecked_into(), // 5EqoZhVC2BcsM4WjvZNidu2muKAbu5THQTBKe3EjvxXkdP7A
hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
hex!["5b57ed1443c8967f461db1f6eb2ada24794d163a668f1cf9d9ce3235dfad8799"].unchecked_into(), // 5E8ULLQrDAtWhfnVfZmX41Yux86zNAwVJYguWJZVWrJvdhBe
hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
),(
hex!["be6726c17ad7b5844c9e0ab6a1698d00d88bf183f0f82d8ec9627531c9ddc934"].unchecked_into(), // 5GNMbce1P2FfjvcPcoUxzjj6bYSRdQ2RpsbCyF9ozwMxx3NS
hex!["123b9048ba61265547ad3f336dfa48c16851ba1a96691e5d1ab3be1725db0614"].unchecked_into(), // 5CUcQvAgMzXMpQSz8mgzeiswDFHED88NiEK4byfS5TLaTJow
hex!["8abecfa66704176be23df099bf441ea65444992d63b3ced3e76a17a4d38b0b0e"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
hex!["0867dbb49721126df589db100dda728dc3b475cbf414dad8f72a1d5e84897252"].unchecked_into(), // 5CFj6Kg9rmVn1vrqpyjau2ztyBzKeVdRKwNPiA3tqhB5HPqq
hex!["26ab2b4b2eba2263b1e55ceb48f687bb0018130a88df0712fbdaf6a347d50e2a"].unchecked_into(), // 5CwQXP6nvWzigFqNhh2jvCaW9zWVzkdveCJY3tz2MhXMjTon
hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
hex!["e60d23f49e93c1c1f2d7c115957df5bbd7faf5ebf138d1e9d02e8b39a1f63df0"].unchecked_into(), // 5HGLmrZsiTFTPp3QoS1W8w9NxByt8PVq79reqvdxNcQkByqK
hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
)];
const ENDOWMENT: u128 = 1_000_000 * DOTS;
@@ -87,7 +114,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
session: Some(SessionConfig {
keys: initial_authorities.iter().map(|x| (
x.0.clone(),
SessionKeys { ed25519: x.2.clone() },
session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
)).collect::<Vec<_>>(),
}),
staking: Some(StakingConfig {
@@ -114,16 +141,25 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
term_duration: 28 * DAYS,
desired_seats: 0,
}),
membership_Instance1: Some(Default::default()),
babe: Some(BabeConfig {
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(),
}),
im_online: Some(ImOnlineConfig {
gossip_at: 0,
keys: initial_authorities.iter().map(|x| x.4.clone()).collect(),
}),
parachains: Some(ParachainsConfig {
authorities: initial_authorities.iter().map(|x| x.5.clone()).collect(),
parachains: vec![],
_phdata: Default::default(),
}),
sudo: Some(SudoConfig {
key: endowed_accounts[0].clone(),
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
aura: Some(AuraConfig {
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
}),
parachains: Some(Default::default()),
curated_grandpa: Some(CuratedGrandpaConfig {
shuffle_period: 1024,
}),
@@ -148,49 +184,53 @@ pub fn staging_testnet_config() -> ChainSpec {
)
}
/// Helper function to generate AccountId from seed
pub fn get_account_id_from_seed(seed: &str) -> AccountId {
sr25519::Pair::from_string(&format!("//{}", seed), None)
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// Helper function to generate SessionKey from seed
pub fn get_session_key_from_seed(seed: &str) -> SessionKey {
ed25519::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, SessionKey) {
pub fn get_authority_keys_from_seed(seed: &str) -> (
AccountId,
AccountId,
BabeId,
GrandpaId,
ImOnlineId,
ValidatorId
) {
(
get_account_id_from_seed(&format!("{}//stash", seed)),
get_account_id_from_seed(seed),
get_session_key_from_seed(seed),
get_from_seed::<AccountId>(&format!("{}//stash", seed)),
get_from_seed::<AccountId>(seed),
get_from_seed::<BabeId>(seed),
get_from_seed::<GrandpaId>(seed),
get_from_seed::<ImOnlineId>(seed),
get_from_seed::<ValidatorId>(seed),
)
}
/// Helper function to create GenesisConfig for testing
pub fn testnet_genesis(
initial_authorities: Vec<(AccountId, AccountId, SessionKey)>,
initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> GenesisConfig {
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
vec![
get_account_id_from_seed("Alice"),
get_account_id_from_seed("Bob"),
get_account_id_from_seed("Charlie"),
get_account_id_from_seed("Dave"),
get_account_id_from_seed("Eve"),
get_account_id_from_seed("Ferdie"),
get_account_id_from_seed("Alice//stash"),
get_account_id_from_seed("Bob//stash"),
get_account_id_from_seed("Charlie//stash"),
get_account_id_from_seed("Dave//stash"),
get_account_id_from_seed("Eve//stash"),
get_account_id_from_seed("Ferdie//stash"),
get_from_seed::<AccountId>("Alice"),
get_from_seed::<AccountId>("Bob"),
get_from_seed::<AccountId>("Charlie"),
get_from_seed::<AccountId>("Dave"),
get_from_seed::<AccountId>("Eve"),
get_from_seed::<AccountId>("Ferdie"),
get_from_seed::<AccountId>("Alice//stash"),
get_from_seed::<AccountId>("Bob//stash"),
get_from_seed::<AccountId>("Charlie//stash"),
get_from_seed::<AccountId>("Dave//stash"),
get_from_seed::<AccountId>("Eve//stash"),
get_from_seed::<AccountId>("Ferdie//stash"),
]
});
@@ -214,7 +254,7 @@ pub fn testnet_genesis(
session: Some(SessionConfig {
keys: initial_authorities.iter().map(|x| (
x.0.clone(),
SessionKeys { ed25519: x.2.clone() },
session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
)).collect::<Vec<_>>(),
}),
staking: Some(StakingConfig {
@@ -240,22 +280,31 @@ pub fn testnet_genesis(
elections: Some(ElectionsConfig {
members: endowed_accounts.iter()
.filter(|&endowed| initial_authorities.iter()
.find(|&(_, controller, _)| controller == endowed)
.find(|&(_, controller, _, _, _, _)| controller == endowed)
.is_none()
).map(|a| (a.clone(), 1000000)).collect(),
presentation_duration: 10,
term_duration: 1000000,
desired_seats,
}),
parachains: Some(Default::default()),
sudo: Some(SudoConfig {
key: root_key,
}),
grandpa: Some(GrandpaConfig {
membership_Instance1: Some(Default::default()),
babe: Some(BabeConfig {
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
aura: Some(AuraConfig {
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(),
}),
im_online: Some(ImOnlineConfig {
gossip_at: 0,
keys: initial_authorities.iter().map(|x| x.4.clone()).collect(),
}),
parachains: Some(ParachainsConfig {
authorities: initial_authorities.iter().map(|x| x.5.clone()).collect(),
parachains: vec![],
_phdata: Default::default(),
}),
sudo: Some(SudoConfig {
key: root_key,
}),
curated_grandpa: Some(CuratedGrandpaConfig {
shuffle_period: 1024,
@@ -272,7 +321,7 @@ fn development_config_genesis() -> GenesisConfig {
vec![
get_authority_keys_from_seed("Alice"),
],
get_account_id_from_seed("Alice"),
get_from_seed::<AccountId>("Alice"),
None,
)
}
@@ -297,7 +346,7 @@ fn local_testnet_genesis() -> GenesisConfig {
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
],
get_account_id_from_seed("Alice"),
get_from_seed::<AccountId>("Alice"),
None,
)
}
+192 -121
View File
@@ -18,18 +18,21 @@
pub mod chain_spec;
use futures::prelude::*;
use client::LongestChain;
use consensus_common::SelectChain;
use std::sync::Arc;
use std::time::Duration;
use grandpa_primitives::AuthorityPair as GrandpaPair;
use polkadot_primitives::{parachain, Block, Hash, BlockId, AuraPair};
use polkadot_primitives::{parachain, Block, Hash, BlockId};
use polkadot_runtime::{GenesisConfig, RuntimeApi};
use polkadot_network::gossip::{self as network_gossip, Known};
use primitives::{ed25519, Pair};
use service::{FactoryFullConfiguration, FullBackend, LightBackend, FullExecutor, LightExecutor};
use service::{
FactoryFullConfiguration, FullBackend, LightBackend, FullExecutor, LightExecutor,
error::Error as ServiceError, TelemetryOnConnect
};
use transaction_pool::txpool::{Pool as TransactionPool};
use aura::{import_queue, start_aura, AuraImportQueue, SlotDuration};
use babe::{import_queue, start_babe, BabeImportQueue, Config};
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
use inherents::InherentDataProviders;
use log::info;
pub use service::{
@@ -49,6 +52,20 @@ pub use consensus::run_validation_worker;
/// All configuration for the polkadot node.
pub type Configuration = FactoryFullConfiguration<Factory>;
type BabeBlockImportForService<F> = babe::BabeBlockImport<
FullBackend<F>,
FullExecutor<F>,
<F as crate::ServiceFactory>::Block,
grandpa::BlockImportForService<F>,
<F as crate::ServiceFactory>::RuntimeApi,
client::Client<
FullBackend<F>,
FullExecutor<F>,
<F as crate::ServiceFactory>::Block,
<F as crate::ServiceFactory>::RuntimeApi
>,
>;
/// Polkadot-specific configuration.
pub struct CustomConfiguration {
/// Set to `Some` with a collator `CollatorId` and desired parachain
@@ -58,11 +75,15 @@ pub struct CustomConfiguration {
/// Intermediate state during setup. Will be removed in future. Set to `None`.
// FIXME: rather than putting this on the config, let's have an actual intermediate setup state
// https://github.com/paritytech/substrate/issues/1134
pub grandpa_import_setup: Option<(
grandpa::BlockImportForService<Factory>,
grandpa::LinkHalfForService<Factory>
pub import_setup: Option<(
BabeBlockImportForService<Factory>,
grandpa::LinkHalfForService<Factory>,
babe::BabeLink,
)>,
/// Tasks that were created by previous setup steps and should be spawned.
pub tasks_to_spawn: Option<Vec<Box<dyn Future<Item = (), Error = ()> + Send>>>,
/// Maximal `block_data` size.
pub max_block_data_size: Option<u64>,
@@ -73,8 +94,9 @@ impl Default for CustomConfiguration {
fn default() -> Self {
Self {
collating_for: None,
grandpa_import_setup: None,
import_setup: None,
inherent_data_providers: InherentDataProviders::new(),
tasks_to_spawn: None,
max_block_data_size: None,
}
}
@@ -150,93 +172,37 @@ impl PolkadotService for Service<LightComponents<Factory>> {
service::construct_service_factory! {
struct Factory {
Block = Block,
ConsensusPair = AuraPair,
FinalityPair = GrandpaPair,
RuntimeApi = RuntimeApi,
NetworkProtocol = PolkadotProtocol {
|config: &Configuration| Ok(PolkadotProtocol::new(config.custom.collating_for.clone()))
},
NetworkProtocol = PolkadotProtocol { |config: &Configuration| Ok(PolkadotProtocol::new(config.custom.collating_for.clone())) },
RuntimeDispatch = polkadot_executor::Executor,
FullTransactionPoolApi = TxChainApi<FullBackend<Self>, FullExecutor<Self>>
{ |config, client| Ok(TransactionPool::new(config, TxChainApi::new(client))) },
LightTransactionPoolApi = TxChainApi<LightBackend<Self>, LightExecutor<Self>>
{ |config, client| Ok(TransactionPool::new(config, TxChainApi::new(client))) },
FullTransactionPoolApi = transaction_pool::ChainApi<client::Client<FullBackend<Self>, FullExecutor<Self>, Block, RuntimeApi>, Block>
{ |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) },
LightTransactionPoolApi = transaction_pool::ChainApi<client::Client<LightBackend<Self>, LightExecutor<Self>, Block, RuntimeApi>, Block>
{ |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) },
Genesis = GenesisConfig,
Configuration = CustomConfiguration,
FullService = FullComponents<Self>
{ |config: FactoryFullConfiguration<Self>| {
FullComponents::<Factory>::new(config)
} },
AuthoritySetup = { |mut service: Self::FullService| {
use polkadot_network::validation::ValidationNetwork;
let (block_import, link_half) = service.config.custom.grandpa_import_setup.take()
FullService = FullComponents<Self> { |config: FactoryFullConfiguration<Self>| FullComponents::<Factory>::new(config) },
AuthoritySetup = {
|mut service: Self::FullService| {
let (block_import, link_half, babe_link) = service.config_mut().custom.import_setup.take()
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
// always run GRANDPA in order to sync.
{
let grandpa_key = if service.config.disable_grandpa {
None
} else {
service.authority_key()
};
let config = grandpa::Config {
local_key: grandpa_key.map(Arc::new),
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
justification_period: 4096,
name: Some(service.config.name.clone())
};
match config.local_key {
None => {
service.spawn_task(grandpa::run_grandpa_observer(
config,
link_half,
service.network(),
service.on_exit(),
)?);
},
Some(_) => {
use service::TelemetryOnConnect;
let telemetry_on_connect = TelemetryOnConnect {
telemetry_connection_sinks: service.telemetry_on_connect_stream(),
};
let grandpa_config = grandpa::GrandpaParams {
config: config,
link: link_half,
network: service.network(),
inherent_data_providers: service.config.custom.inherent_data_providers.clone(),
on_exit: service.on_exit(),
telemetry_on_connect: Some(telemetry_on_connect),
};
service.spawn_task(grandpa::run_grandpa_voter(grandpa_config)?);
},
// spawn any futures that were created in the previous setup steps
if let Some(tasks) = service.config_mut().custom.tasks_to_spawn.take() {
for task in tasks {
service.spawn_task(
task.select(service.on_exit())
.map(|_| ())
.map_err(|_| ())
);
}
}
let extrinsic_store = {
use std::path::PathBuf;
if service.config().roles != service::Roles::AUTHORITY {
return Ok(service);
}
let mut path = PathBuf::from(service.config.database_path.clone());
path.push("availability");
av_store::Store::new(::av_store::Config {
cache_size: None,
path,
})?
};
// run authorship only if authority.
let aura_key = match service.authority_key() {
Some(key) => Arc::new(key),
None => return Ok(service),
};
if service.config.custom.collating_for.is_some() {
if service.config().custom.collating_for.is_some() {
info!(
"The node cannot start as an authority because it is also configured to run as a collator."
);
@@ -275,6 +241,19 @@ service::construct_service_factory! {
},
);
use polkadot_network::validation::ValidationNetwork;
let extrinsic_store = {
use std::path::PathBuf;
let mut path = PathBuf::from(service.config().database_path.clone());
path.push("availability");
av_store::Store::new(::av_store::Config {
cache_size: None,
path,
})?
};
// collator connections and validation network both fulfilled by this
let validation_network = ValidationNetwork::new(
service.network(),
@@ -283,63 +262,150 @@ service::construct_service_factory! {
service.client(),
polkadot_network::validation::WrappedExecutor(service.spawn_task_handle()),
);
let proposer_factory = consensus::ProposerFactory::new(
let proposer = consensus::ProposerFactory::new(
client.clone(),
select_chain.clone(),
validation_network.clone(),
validation_network,
service.transaction_pool(),
Arc::new(service.spawn_task_handle()),
aura_key.clone(),
service.keystore(),
extrinsic_store,
SlotDuration::get_or_compute(&*client)?,
service.config.custom.max_block_data_size,
polkadot_runtime::constants::time::SLOT_DURATION,
service.config().custom.max_block_data_size,
);
info!("Using authority key {}", aura_key.public());
let task = start_aura(
SlotDuration::get_or_compute(&*client)?,
aura_key,
client.clone(),
let client = service.client();
let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?;
let babe_config = babe::BabeParams {
config: Config::get_or_compute(&*client)?,
keystore: service.keystore(),
client,
select_chain,
block_import,
Arc::new(proposer_factory),
service.network(),
service.config.custom.inherent_data_providers.clone(),
service.config.force_authoring,
)?;
env: proposer,
sync_oracle: service.network(),
inherent_data_providers: service.config().custom.inherent_data_providers.clone(),
force_authoring: service.config().force_authoring,
time_source: babe_link,
};
let babe = start_babe(babe_config)?;
let select = babe.select(service.on_exit()).then(|_| Ok(()));
service.spawn_task(Box::new(select));
let config = grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
justification_period: 4096,
name: Some(service.config().name.clone()),
keystore: Some(service.keystore()),
};
match (service.config().roles.is_authority(), service.config().disable_grandpa) {
(false, false) => {
// start the lightweight GRANDPA observer
service.spawn_task(Box::new(grandpa::run_grandpa_observer(
config,
link_half,
service.network(),
service.on_exit(),
)?));
},
(true, false) => {
// start the full GRANDPA voter
let telemetry_on_connect = TelemetryOnConnect {
telemetry_connection_sinks: service.telemetry_on_connect_stream(),
};
let grandpa_config = grandpa::GrandpaParams {
config: config,
link: link_half,
network: service.network(),
inherent_data_providers: service.config().custom.inherent_data_providers.clone(),
on_exit: service.on_exit(),
telemetry_on_connect: Some(telemetry_on_connect),
};
service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?));
},
(_, true) => {
grandpa::setup_disabled_grandpa(
service.client(),
&service.config().custom.inherent_data_providers,
service.network(),
)?;
},
}
// let config = grandpa::Config {
// // FIXME #1578 make this available through chainspec
// gossip_duration: Duration::from_millis(333),
// justification_period: 4096,
// name: Some(service.config().name.clone()),
// keystore: Some(service.keystore()),
// };
// if !service.config().disable_grandpa {
// if service.config().roles.is_authority() {
// let telemetry_on_connect = TelemetryOnConnect {
// telemetry_connection_sinks: service.telemetry_on_connect_stream(),
// };
// let grandpa_config = grandpa::GrandpaParams {
// config: config,
// link: link_half,
// network: service.network(),
// inherent_data_providers: service.config().custom.inherent_data_providers.clone(),
// on_exit: service.on_exit(),
// telemetry_on_connect: Some(telemetry_on_connect),
// };
// service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?));
// } else {
// service.spawn_task(Box::new(grandpa::run_grandpa_observer(
// config,
// link_half,
// service.network(),
// service.on_exit(),
// )?));
// }
// }
// // regardless of whether grandpa is started or not, when
// // authoring blocks we expect inherent data regarding what our
// // last finalized block is, to be available.
// grandpa::register_finality_tracker_inherent_data_provider(
// service.client(),
// &service.config().custom.inherent_data_providers,
// )?;
service.spawn_task(task);
Ok(service)
}},
}
},
LightService = LightComponents<Self>
{ |config| <LightComponents<Factory>>::new(config) },
FullImportQueue = AuraImportQueue<
Self::Block,
>
FullImportQueue = BabeImportQueue<Self::Block>
{ |config: &mut FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>, select_chain: Self::SelectChain| {
let slot_duration = SlotDuration::get_or_compute(&*client)?;
let (block_import, link_half) =
grandpa::block_import::<_, _, _, RuntimeApi, FullClient<Self>, _>(
client.clone(), client.clone(), select_chain
)?;
let justification_import = block_import.clone();
config.custom.grandpa_import_setup = Some((block_import.clone(), link_half));
import_queue::<_, _, ed25519::Pair>(
slot_duration,
Box::new(block_import),
let (import_queue, babe_link, babe_block_import, pruning_task) = import_queue(
Config::get_or_compute(&*client)?,
block_import,
Some(Box::new(justification_import)),
None,
client.clone(),
client,
config.custom.inherent_data_providers.clone(),
).map_err(Into::into)
)?;
config.custom.import_setup = Some((babe_block_import.clone(), link_half, babe_link));
config.custom.tasks_to_spawn = Some(vec![Box::new(pruning_task)]);
Ok(import_queue)
}},
LightImportQueue = AuraImportQueue<
Self::Block,
>
{ |config: &mut FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
LightImportQueue = BabeImportQueue<Self::Block>
{ |config: &FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
#[allow(deprecated)]
let fetch_checker = client.backend().blockchain().fetcher()
.upgrade()
@@ -348,17 +414,22 @@ service::construct_service_factory! {
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient<Self>>(
client.clone(), Arc::new(fetch_checker), client.clone()
)?;
let finality_proof_import = block_import.clone();
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
import_queue::<_, _, ed25519::Pair>(
SlotDuration::get_or_compute(&*client)?,
Box::new(block_import),
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
let (import_queue, ..) = import_queue(
Config::get_or_compute(&*client)?,
block_import,
None,
Some(Box::new(finality_proof_import)),
client.clone(),
client,
config.custom.inherent_data_providers.clone(),
).map_err(Into::into).map(|q| (q, finality_proof_request_builder))
)?;
Ok((import_queue, finality_proof_request_builder))
}},
SelectChain = LongestChain<FullBackend<Self>, Self::Block>
{ |config: &FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>| {
@@ -367,7 +438,7 @@ service::construct_service_factory! {
}
},
FinalityProofProvider = { |client: Arc<FullClient<Self>>| {
Ok(Some(Arc::new(grandpa::FinalityProofProvider::new(client.clone(), client)) as _))
Ok(Some(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) as _))
}},
}
}
+1 -1
View File
@@ -5,6 +5,6 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
parity-codec = { version = "4.1", features = ["derive"] }
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
primitives = { package = "polkadot-primitives", path = "../primitives" }
+1 -1
View File
@@ -28,7 +28,7 @@ use std::collections::hash_map::{HashMap, Entry};
use std::hash::Hash;
use std::fmt::Debug;
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
/// Context for the statement table.
pub trait Context {
+1 -1
View File
@@ -8,7 +8,7 @@ build = "build.rs"
[dependencies]
parachain = { package = "polkadot-parachain", path = "../../parachain/", default-features = false }
parity-codec = { version = "4.1", default-features = false, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
tiny-keccak = "1.5.0"
dlmalloc = { version = "0.1.3", features = ["global"], optional = true }
@@ -63,7 +63,7 @@ impl ParachainContext for AdderContext {
) -> Result<(BlockData, HeadData, Extrinsic), InvalidHead>
{
let adder_head = AdderHead::decode(&mut &status.head_data.0[..])
.ok_or(InvalidHead)?;
.map_err(|_| InvalidHead)?;
let mut db = self.db.lock();
+2 -2
View File
@@ -20,7 +20,7 @@
#![cfg_attr(feature = "no_std", feature(core_intrinsics, lang_items, core_panic_info, alloc_error_handler))]
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
#[cfg(feature = "no_std")]
mod wasm_validation;
@@ -80,7 +80,7 @@ pub fn process_messages<I, T>(iterable: I) -> u64
where I: IntoIterator<Item=T>, T: AsRef<[u8]>
{
iterable.into_iter()
.filter_map(|data| AddMessage::decode(&mut data.as_ref()))
.filter_map(|data| AddMessage::decode(&mut data.as_ref()).ok())
.fold(0u64, |a, c| a.overflowing_add(c.amount).0)
}
+5 -5
View File
@@ -13,24 +13,24 @@ tokio = "0.1.7"
derive_more = "0.14.0"
log = "0.4.6"
exit-future = "0.1"
parity-codec = "4.1"
codec = { package = "parity-scale-codec", version = "~1.0.0", default-features = false, features = ["derive"] }
extrinsic_store = { package = "polkadot-availability-store", path = "../availability-store" }
parachain = { package = "polkadot-parachain", path = "../parachain" }
polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
table = { package = "polkadot-statement-table", path = "../statement-table" }
aura = { package = "substrate-consensus-aura", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
aura_primitives = { package = "substrate-consensus-aura-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
grandpa = { package = "substrate-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
inherents = { package = "substrate-inherents", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
consensus = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
transaction_pool = { package = "substrate-transaction-pool", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
runtime_aura = { package = "srml-aura", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
client = { package = "substrate-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
trie = { package = "substrate-trie", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
runtime_primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
bitvec = { version = "0.11", default-features = false, features = ["alloc"] }
bitvec = { version = "0.14.0", default-features = false, features = ["alloc"] }
runtime_babe = { package = "srml-babe", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
babe-primitives = { package = "substrate-consensus-babe-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
keystore = { package = "substrate-keystore", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
[dev-dependencies]
substrate-keyring = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
+10 -9
View File
@@ -33,11 +33,11 @@ use extrinsic_store::Store as ExtrinsicStore;
use futures::prelude::*;
use futures03::{TryStreamExt as _, StreamExt as _};
use log::error;
use primitives::ed25519;
use polkadot_primitives::{Block, BlockId, AuraId};
use polkadot_primitives::{Block, BlockId};
use polkadot_primitives::parachain::{CandidateReceipt, ParachainHost};
use runtime_primitives::traits::{ProvideRuntimeApi, Header as HeaderT};
use aura::AuraApi;
use babe_primitives::BabeApi;
use keystore::KeyStorePtr;
use tokio::{timer::Interval, runtime::current_thread::Runtime as LocalRuntime};
use log::{warn, debug};
@@ -50,14 +50,14 @@ type TaskExecutor = Arc<dyn futures::future::Executor<Box<dyn Future<Item = (),
pub(crate) fn fetch_candidates<P: BlockBody<Block>>(client: &P, block: &BlockId)
-> ClientResult<Option<impl Iterator<Item=CandidateReceipt>>>
{
use parity_codec::{Encode, Decode};
use codec::{Encode, Decode};
use polkadot_runtime::{Call, ParachainsCall, UncheckedExtrinsic as RuntimeExtrinsic};
let extrinsics = client.block_body(block)?;
Ok(match extrinsics {
Some(extrinsics) => extrinsics
.into_iter()
.filter_map(|ex| RuntimeExtrinsic::decode(&mut ex.encode().as_slice()))
.filter_map(|ex| RuntimeExtrinsic::decode(&mut ex.encode().as_slice()).ok())
.filter_map(|ex| match ex.function {
Call::Parachains(ParachainsCall::set_heads(heads)) => {
Some(heads.into_iter().map(|c| c.candidate))
@@ -114,7 +114,7 @@ pub(crate) fn start<C, N, P, SC>(
select_chain: SC,
parachain_validation: Arc<crate::ParachainValidation<C, N, P>>,
thread_pool: TaskExecutor,
key: Arc<ed25519::Pair>,
keystore: KeyStorePtr,
extrinsic_store: ExtrinsicStore,
max_block_data_size: Option<u64>,
) -> ServiceHandle
@@ -123,7 +123,7 @@ pub(crate) fn start<C, N, P, SC>(
<C::Collation as IntoFuture>::Future: Send + 'static,
P: BlockchainEvents<Block> + BlockBody<Block>,
P: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block> + BlockBuilder<Block> + AuraApi<Block, AuraId>,
P::Api: ParachainHost<Block> + BlockBuilder<Block> + BabeApi<Block>,
N: Network + Send + Sync + 'static,
N::TableRouter: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
@@ -138,7 +138,8 @@ pub(crate) fn start<C, N, P, SC>(
let notifications = {
let client = client.clone();
let validation = parachain_validation.clone();
let key = key.clone();
let keystore = keystore.clone();
client.import_notification_stream()
.map(|v| Ok::<_, ()>(v)).compat()
@@ -148,7 +149,7 @@ pub(crate) fn start<C, N, P, SC>(
let res = validation.get_or_instantiate(
parent_hash,
notification.header.parent_hash().clone(),
key.clone(),
&keystore,
max_block_data_size,
);
+2 -2
View File
@@ -27,7 +27,7 @@ use polkadot_primitives::{Block, Hash, BlockId, Balance, parachain::{
}};
use runtime_primitives::traits::ProvideRuntimeApi;
use parachain::{wasm_executor::{self, ExternalitiesError, ExecutionMode}, MessageRef, UpwardMessageRef};
use trie::TrieConfiguration;
use futures::prelude::*;
use log::debug;
@@ -186,7 +186,7 @@ impl std::error::Error for Error {
pub fn message_queue_root<A, I: IntoIterator<Item=A>>(messages: I) -> Hash
where A: AsRef<[u8]>
{
::trie::ordered_trie_root::<primitives::Blake2Hasher, _, _>(messages)
::trie::trie_types::Layout::<primitives::Blake2Hasher>::ordered_trie_root(messages)
}
/// Compute the set of egress roots for all given outgoing messages.
+2 -2
View File
@@ -17,7 +17,7 @@
//! Errors that can occur during the validation process.
use runtime_primitives::RuntimeString;
use primitives::ed25519::Public as AuthorityId;
use polkadot_primitives::parachain::ValidatorId;
/// Error type for validation
#[derive(Debug, derive_more::Display, derive_more::From)]
@@ -35,7 +35,7 @@ pub enum Error {
},
/// Local account not a validator at this block
#[display(fmt = "Local account ID ({:?}) not a validator at this block.", _0)]
NotValidator(AuthorityId),
NotValidator(ValidatorId),
/// Unexpected error checking inherents
#[display(fmt = "Unexpected error while checking inherents: {}", _0)]
InherentError(RuntimeString),
+1 -1
View File
@@ -18,7 +18,7 @@
use super::MAX_TRANSACTIONS_SIZE;
use parity_codec::Encode;
use codec::Encode;
use polkadot_primitives::{Block, Hash, BlockNumber};
use polkadot_primitives::parachain::Id as ParaId;
+68 -60
View File
@@ -31,21 +31,21 @@
use std::{collections::{HashMap, HashSet}, pin::Pin, sync::Arc, time::{self, Duration, Instant}};
use aura::{SlotDuration, AuraApi};
use babe_primitives::BabeApi;
use client::{BlockchainEvents, BlockBody};
use client::blockchain::HeaderBackend;
use client::block_builder::api::BlockBuilder as BlockBuilderApi;
use parity_codec::Encode;
use codec::Encode;
use consensus::SelectChain;
use extrinsic_store::Store as ExtrinsicStore;
use parking_lot::Mutex;
use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header, SessionKey, AuraId};
use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header};
use polkadot_primitives::parachain::{
Id as ParaId, Chain, DutyRoster, Extrinsic as ParachainExtrinsic, CandidateReceipt,
ParachainHost, AttestedCandidate, Statement as PrimitiveStatement, Message, OutgoingMessage,
CollatorSignature, Collation, PoVBlock,
Collation, PoVBlock, ValidatorSignature, ValidatorPair, ValidatorId
};
use primitives::{Pair, ed25519};
use primitives::Pair;
use runtime_primitives::{
traits::{ProvideRuntimeApi, Header as HeaderT, DigestFor}, ApplyError
};
@@ -58,10 +58,9 @@ use futures03::{future::{self, Either, FutureExt}, task::Context, stream::Stream
use collation::CollationFetch;
use dynamic_inclusion::DynamicInclusion;
use inherents::InherentData;
use runtime_aura::timestamp::TimestampInherentData;
use runtime_babe::timestamp::TimestampInherentData;
use log::{info, debug, warn, trace, error};
use ed25519::Public as AuthorityId;
use keystore::KeyStorePtr;
type TaskExecutor = Arc<dyn futures::future::Executor<Box<dyn Future<Item = (), Error = ()> + Send>> + Send + Sync>;
@@ -145,7 +144,7 @@ pub trait Network {
fn communication_for(
&self,
table: Arc<SharedTable>,
authorities: &[SessionKey],
authorities: &[ValidatorId],
exit: exit_future::Exit,
) -> Self::BuildTableRouter;
}
@@ -154,7 +153,7 @@ pub trait Network {
#[derive(Debug, Clone, Default)]
pub struct GroupInfo {
/// Authorities meant to check validity of candidates.
validity_guarantors: HashSet<SessionKey>,
validity_guarantors: HashSet<ValidatorId>,
/// Number of votes needed for validity.
needed_validity: usize,
}
@@ -162,32 +161,32 @@ pub struct GroupInfo {
/// Sign a table statement against a parent hash.
/// The actual message signed is the encoded statement concatenated with the
/// parent hash.
pub fn sign_table_statement(statement: &Statement, key: &ed25519::Pair, parent_hash: &Hash) -> CollatorSignature {
pub fn sign_table_statement(statement: &Statement, key: &ValidatorPair, parent_hash: &Hash) -> ValidatorSignature {
// we sign using the primitive statement type because that's what the runtime
// expects. These types probably encode the same way so this clone could be optimized
// out in the future.
let mut encoded = PrimitiveStatement::from(statement.clone()).encode();
encoded.extend(parent_hash.as_ref());
key.sign(&encoded).into()
key.sign(&encoded)
}
/// Check signature on table statement.
pub fn check_statement(statement: &Statement, signature: &CollatorSignature, signer: SessionKey, parent_hash: &Hash) -> bool {
use runtime_primitives::traits::Verify;
pub fn check_statement(statement: &Statement, signature: &ValidatorSignature, signer: ValidatorId, parent_hash: &Hash) -> bool {
use runtime_primitives::traits::AppVerify;
let mut encoded = PrimitiveStatement::from(statement.clone()).encode();
encoded.extend(parent_hash.as_ref());
signature.verify(&encoded[..], &signer.into())
signature.verify(&encoded[..], &signer)
}
/// Compute group info out of a duty roster and a local authority set.
pub fn make_group_info(
roster: DutyRoster,
authorities: &[AuthorityId],
local_id: AuthorityId,
) -> Result<(HashMap<ParaId, GroupInfo>, LocalDuty), Error> {
authorities: &[ValidatorId],
local_id: Option<ValidatorId>,
) -> Result<(HashMap<ParaId, GroupInfo>, Option<LocalDuty>), Error> {
if roster.validator_duty.len() != authorities.len() {
return Err(Error::InvalidDutyRosterLength {
expected: authorities.len(),
@@ -200,7 +199,7 @@ pub fn make_group_info(
let duty_iter = authorities.iter().zip(&roster.validator_duty);
for (authority, v_duty) in duty_iter {
if authority == &local_id {
if Some(authority) == local_id.as_ref() {
local_validation = Some(v_duty.clone());
}
@@ -219,16 +218,24 @@ pub fn make_group_info(
live_group.needed_validity = validity_len / 2 + validity_len % 2;
}
match local_validation {
Some(local_validation) => {
let local_duty = LocalDuty {
validation: local_validation,
};
let local_duty = local_validation.map(|v| LocalDuty {
validation: v
});
Ok((map, local_duty))
}
None => return Err(Error::NotValidator(local_id)),
}
// finds the first key we are capable of signing with out of the given set of validators,
// if any.
fn signing_key(validators: &[ValidatorId], keystore: &KeyStorePtr) -> Option<Arc<ValidatorPair>> {
let keystore = keystore.read();
validators.iter()
.find_map(|v| {
keystore.key_pair::<ValidatorPair>(&v).ok()
})
.map(|pair| Arc::new(pair))
}
/// Constructs parachain-agreement instances.
@@ -252,7 +259,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
C: Collators + Send + 'static,
N: Network,
P: ProvideRuntimeApi + HeaderBackend<Block> + BlockBody<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block> + AuraApi<Block, AuraId>,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
@@ -268,7 +275,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
&self,
parent_hash: Hash,
grandparent_hash: Hash,
sign_with: Arc<ed25519::Pair>,
keystore: &KeyStorePtr,
max_block_data_size: Option<u64>,
)
-> Result<Arc<AttestationTracker>, Error>
@@ -280,7 +287,8 @@ impl<C, N, P> ParachainValidation<C, N, P> where
let id = BlockId::hash(parent_hash);
let authorities = self.client.runtime_api().authorities(&id)?;
let validators = self.client.runtime_api().validators(&id)?;
let sign_with = signing_key(&validators[..], keystore);
// compute the parent candidates, if we know of them.
// this will allow us to circulate outgoing messages to other peers as necessary.
@@ -312,14 +320,14 @@ impl<C, N, P> ParachainValidation<C, N, P> where
let (group_info, local_duty) = make_group_info(
duty_roster,
&authorities,
sign_with.public(),
&validators,
sign_with.as_ref().map(|k| k.public()),
)?;
info!(
"Starting parachain attestation session on top of parent {:?}. Local parachain duty is {:?}",
parent_hash,
local_duty.validation,
local_duty,
);
let active_parachains = self.client.runtime_api().active_parachains(&id)?;
@@ -327,9 +335,9 @@ impl<C, N, P> ParachainValidation<C, N, P> where
debug!(target: "validation", "Active parachains: {:?}", active_parachains);
let table = Arc::new(SharedTable::new(
&authorities,
validators.clone(),
group_info,
sign_with.clone(),
sign_with,
parent_hash,
self.extrinsic_store.clone(),
max_block_data_size,
@@ -339,11 +347,11 @@ impl<C, N, P> ParachainValidation<C, N, P> where
let router = self.network.communication_for(
table.clone(),
&authorities,
&validators,
exit.clone(),
);
if let Chain::Parachain(id) = local_duty.validation {
if let Some(Chain::Parachain(id)) = local_duty.as_ref().map(|d| d.validation) {
self.launch_work(parent_hash, id, router, max_block_data_size, exit);
}
@@ -446,9 +454,9 @@ struct AttestationTracker {
pub struct ProposerFactory<C, N, P, SC, TxApi: PoolChainApi> {
parachain_validation: Arc<ParachainValidation<C, N, P>>,
transaction_pool: Arc<Pool<TxApi>>,
key: Arc<ed25519::Pair>,
keystore: KeyStorePtr,
_service_handle: ServiceHandle,
aura_slot_duration: SlotDuration,
babe_slot_duration: u64,
_select_chain: SC,
max_block_data_size: Option<u64>,
}
@@ -458,7 +466,7 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
<C::Collation as IntoFuture>::Future: Send + 'static,
P: BlockchainEvents<Block> + BlockBody<Block>,
P: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block> + AuraApi<Block, AuraId>,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block> + BabeApi<Block>,
N: Network + Send + Sync + 'static,
N::TableRouter: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
@@ -473,9 +481,9 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
collators: C,
transaction_pool: Arc<Pool<TxApi>>,
thread_pool: TaskExecutor,
key: Arc<ed25519::Pair>,
keystore: KeyStorePtr,
extrinsic_store: ExtrinsicStore,
aura_slot_duration: SlotDuration,
babe_slot_duration: u64,
max_block_data_size: Option<u64>,
) -> Self {
let parachain_validation = Arc::new(ParachainValidation {
@@ -492,7 +500,7 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
_select_chain.clone(),
parachain_validation.clone(),
thread_pool,
key.clone(),
keystore.clone(),
extrinsic_store,
max_block_data_size,
);
@@ -500,9 +508,9 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
ProposerFactory {
parachain_validation,
transaction_pool,
key,
keystore,
_service_handle: service_handle,
aura_slot_duration,
babe_slot_duration,
_select_chain,
max_block_data_size,
}
@@ -514,7 +522,7 @@ impl<C, N, P, SC, TxApi> consensus::Environment<Block> for ProposerFactory<C, N,
N: Network,
TxApi: PoolChainApi<Block=Block>,
P: ProvideRuntimeApi + HeaderBackend<Block> + BlockBody<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block> + AuraApi<Block, AuraId>,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block> + BabeApi<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
@@ -524,16 +532,16 @@ impl<C, N, P, SC, TxApi> consensus::Environment<Block> for ProposerFactory<C, N,
type Error = Error;
fn init(
&self,
&mut self,
parent_header: &Header,
) -> Result<Self::Proposer, Error> {
let parent_hash = parent_header.hash();
let parent_id = BlockId::hash(parent_hash);
let sign_with = self.key.clone();
let tracker = self.parachain_validation.get_or_instantiate(
parent_hash,
parent_header.parent_hash().clone(),
sign_with,
&self.keystore,
self.max_block_data_size,
)?;
@@ -544,12 +552,13 @@ impl<C, N, P, SC, TxApi> consensus::Environment<Block> for ProposerFactory<C, N,
parent_id,
parent_number: parent_header.number,
transaction_pool: self.transaction_pool.clone(),
slot_duration: self.aura_slot_duration,
slot_duration: self.babe_slot_duration,
})
}
}
/// The local duty of a validator.
#[derive(Debug)]
pub struct LocalDuty {
validation: Chain,
}
@@ -564,7 +573,7 @@ pub struct Proposer<C: Send + Sync, TxApi: PoolChainApi> where
parent_number: BlockNumber,
tracker: Arc<AttestationTracker>,
transaction_pool: Arc<Pool<TxApi>>,
slot_duration: SlotDuration,
slot_duration: u64,
}
impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
@@ -575,7 +584,7 @@ impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
type Error = Error;
type Create = Either<CreateProposal<C, TxApi>, future::Ready<Result<Block, Error>>>;
fn propose(&self,
fn propose(&mut self,
inherent_data: InherentData,
inherent_digests: DigestFor<Block>,
max_duration: Duration,
@@ -589,7 +598,7 @@ impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
let dynamic_inclusion = DynamicInclusion::new(
self.tracker.table.num_parachains(),
self.tracker.started,
Duration::from_secs(self.slot_duration.get() / SLOT_DURATION_DENOMINATOR),
Duration::from_millis(self.slot_duration / SLOT_DURATION_DENOMINATOR),
);
let enough_candidates = dynamic_inclusion.acceptable_in(
@@ -607,7 +616,7 @@ impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
let delay_future = if current_timestamp >= believed_timestamp {
None
} else {
Some(Delay::new(Duration::from_secs(current_timestamp - believed_timestamp)))
Some(Delay::new(Duration::from_millis (current_timestamp - believed_timestamp)))
};
let timing = ProposalTiming {
@@ -638,8 +647,7 @@ impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
fn current_timestamp() -> u64 {
time::SystemTime::now().duration_since(time::UNIX_EPOCH)
.expect("now always later than unix epoch; qed")
.as_secs()
.into()
.as_millis() as u64
}
struct ProposalTiming {
@@ -811,17 +819,17 @@ impl<C, TxApi> futures03::Future for CreateProposal<C, TxApi> where
#[cfg(test)]
mod tests {
use super::*;
use substrate_keyring::Ed25519Keyring;
use substrate_keyring::Sr25519Keyring;
#[test]
fn sign_and_check_statement() {
let statement: Statement = GenericStatement::Valid([1; 32].into());
let parent_hash = [2; 32].into();
let sig = sign_table_statement(&statement, &Ed25519Keyring::Alice.pair(), &parent_hash);
let sig = sign_table_statement(&statement, &Sr25519Keyring::Alice.pair().into(), &parent_hash);
assert!(check_statement(&statement, &sig, Ed25519Keyring::Alice.into(), &parent_hash));
assert!(!check_statement(&statement, &sig, Ed25519Keyring::Alice.into(), &[0xff; 32].into()));
assert!(!check_statement(&statement, &sig, Ed25519Keyring::Bob.into(), &parent_hash));
assert!(check_statement(&statement, &sig, Sr25519Keyring::Alice.public().into(), &parent_hash));
assert!(!check_statement(&statement, &sig, Sr25519Keyring::Alice.public().into(), &[0xff; 32].into()));
assert!(!check_statement(&statement, &sig, Sr25519Keyring::Bob.public().into(), &parent_hash));
}
}
+70 -95
View File
@@ -22,9 +22,10 @@ use std::sync::Arc;
use extrinsic_store::{Data, Store as ExtrinsicStore};
use table::{self, Table, Context as TableContextTrait};
use polkadot_primitives::{Block, BlockId, Hash, SessionKey};
use polkadot_primitives::parachain::{Id as ParaId, Collation, Extrinsic, CandidateReceipt,
AttestedCandidate, ParachainHost, PoVBlock, ValidatorIndex,
use polkadot_primitives::{Block, BlockId, Hash};
use polkadot_primitives::parachain::{
Id as ParaId, Collation, Extrinsic, CandidateReceipt, ValidatorPair, ValidatorId,
AttestedCandidate, ParachainHost, PoVBlock, ValidatorIndex
};
use parking_lot::Mutex;
@@ -34,7 +35,7 @@ use bitvec::bitvec;
use super::{GroupInfo, TableRouter};
use self::includable::IncludabilitySender;
use primitives::{ed25519, Pair};
use primitives::Pair;
use runtime_primitives::traits::ProvideRuntimeApi;
mod includable;
@@ -45,14 +46,14 @@ pub use table::generic::Statement as GenericStatement;
struct TableContext {
parent_hash: Hash,
key: Arc<ed25519::Pair>,
key: Option<Arc<ValidatorPair>>,
groups: HashMap<ParaId, GroupInfo>,
index_mapping: HashMap<ValidatorIndex, SessionKey>,
validators: Vec<ValidatorId>,
}
impl table::Context for TableContext {
fn is_member_of(&self, authority: ValidatorIndex, group: &ParaId) -> bool {
let key = match self.index_mapping.get(&authority) {
let key = match self.validators.get(authority as usize) {
Some(val) => val,
None => return false,
};
@@ -66,28 +67,26 @@ impl table::Context for TableContext {
}
impl TableContext {
fn local_id(&self) -> SessionKey {
self.key.public().into()
fn local_id(&self) -> Option<ValidatorId> {
self.key.as_ref().map(|k| k.public())
}
fn local_index(&self) -> ValidatorIndex {
let id = self.local_id();
self
.index_mapping
fn local_index(&self) -> Option<ValidatorIndex> {
self.local_id().and_then(|id|
self.validators
.iter()
.enumerate()
.find(|(_, k)| k == &&id)
.map(|(i, _)| *i)
.unwrap()
.map(|(i, _)| i as ValidatorIndex)
)
}
fn sign_statement(&self, statement: table::Statement) -> table::SignedStatement {
let signature = crate::sign_table_statement(&statement, &self.key, &self.parent_hash).into();
table::SignedStatement {
statement,
signature,
sender: self.local_index(),
}
fn sign_statement(&self, statement: table::Statement) -> Option<table::SignedStatement> {
self.local_index().and_then(move |sender|
self.key.as_ref()
.map(|key| crate::sign_table_statement(&statement, key, &self.parent_hash).into())
.map(move |signature| table::SignedStatement { statement, signature, sender })
)
}
}
@@ -142,15 +141,10 @@ impl SharedTableInner {
) -> Option<ParachainWork<
<R::FetchValidationProof as IntoFuture>::Future,
>> {
let summary = match self.table.import_statement(context, statement) {
Some(summary) => summary,
None => return None,
};
let summary = self.table.import_statement(context, statement)?;
self.update_trackers(&summary.candidate, context);
let local_index = context.local_index();
let local_index = context.local_index()?;
let para_member = context.is_member_of(local_index, &summary.group_id);
let digest = &summary.candidate;
@@ -399,16 +393,15 @@ impl SharedTable {
/// Provide the key to sign with, and the parent hash of the relay chain
/// block being built.
pub fn new(
authorities: &[ed25519::Public],
validators: Vec<ValidatorId>,
groups: HashMap<ParaId, GroupInfo>,
key: Arc<ed25519::Pair>,
key: Option<Arc<ValidatorPair>>,
parent_hash: Hash,
extrinsic_store: ExtrinsicStore,
max_block_data_size: Option<u64>,
) -> Self {
let index_mapping = authorities.iter().enumerate().map(|(i, k)| (i as ValidatorIndex, k.clone())).collect();
Self {
context: Arc::new(TableContext { groups, key, parent_hash, index_mapping, }),
SharedTable {
context: Arc::new(TableContext { groups, key, parent_hash, validators: validators.clone(), }),
max_block_data_size,
inner: Arc::new(Mutex::new(SharedTableInner {
table: Table::default(),
@@ -425,7 +418,7 @@ impl SharedTable {
}
/// Get the local validator session key.
pub fn session_key(&self) -> SessionKey {
pub fn session_key(&self) -> Option<ValidatorId> {
self.context.local_id()
}
@@ -482,9 +475,10 @@ impl SharedTable {
}).collect()
}
/// Sign and import the result of candidate validation.
/// Sign and import the result of candidate validation. Returns `None` if the table
/// was instantiated without a local key.
pub fn import_validated(&self, validated: Validated)
-> SignedStatement
-> Option<SignedStatement>
{
let digest = match validated.statement {
GenericStatement::Candidate(ref c) => c.hash(),
@@ -493,9 +487,11 @@ impl SharedTable {
let signed_statement = self.context.sign_statement(validated.statement);
if let Some(ref signed) = signed_statement {
let mut inner = self.inner.lock();
inner.table.import_statement(&*self.context, signed_statement.clone());
inner.table.import_statement(&*self.context, signed.clone());
inner.validated.insert(digest, ValidationWork::Done(validated.result));
}
signed_statement
}
@@ -576,15 +572,15 @@ impl SharedTable {
}
/// Returns id of the validator corresponding to the given index.
pub fn index_to_id(&self, index: ValidatorIndex) -> Option<SessionKey> {
self.context.index_mapping.get(&index).cloned()
pub fn index_to_id(&self, index: ValidatorIndex) -> Option<ValidatorId> {
self.context.validators.get(index as usize).cloned()
}
}
#[cfg(test)]
mod tests {
use super::*;
use substrate_keyring::Ed25519Keyring;
use substrate_keyring::Sr25519Keyring;
use primitives::crypto::UncheckedInto;
use polkadot_primitives::parachain::{BlockData, ConsolidatedIngress};
use futures::future;
@@ -617,11 +613,12 @@ mod tests {
let para_id = ParaId::from(1);
let parent_hash = Default::default();
let local_key = Arc::new(Ed25519Keyring::Alice.pair());
let local_id = local_key.public();
let local_key = Sr25519Keyring::Alice.pair();
let local_id: ValidatorId = local_key.public().into();
let local_key: Arc<ValidatorPair> = Arc::new(local_key.into());
let validity_other_key = Ed25519Keyring::Bob.pair();
let validity_other = validity_other_key.public();
let validity_other_key = Sr25519Keyring::Bob.pair();
let validity_other: ValidatorId = validity_other_key.public().into();
let validity_other_index = 1;
groups.insert(para_id, GroupInfo {
@@ -630,9 +627,9 @@ mod tests {
});
let shared_table = SharedTable::new(
&[local_id, validity_other],
[local_id, validity_other].to_vec(),
groups,
local_key.clone(),
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
None,
@@ -651,7 +648,7 @@ mod tests {
let candidate_statement = GenericStatement::Candidate(candidate);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key, &parent_hash);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key.into(), &parent_hash);
let signed_statement = ::table::generic::SignedStatement {
statement: candidate_statement,
signature: signature.into(),
@@ -671,11 +668,12 @@ mod tests {
let para_id = ParaId::from(1);
let parent_hash = Default::default();
let local_key = Arc::new(Ed25519Keyring::Alice.pair());
let local_id = local_key.public();
let local_key = Sr25519Keyring::Alice.pair();
let local_id: ValidatorId = local_key.public().into();
let local_key: Arc<ValidatorPair> = Arc::new(local_key.into());
let validity_other_key = Ed25519Keyring::Bob.pair();
let validity_other = validity_other_key.public();
let validity_other_key = Sr25519Keyring::Bob.pair();
let validity_other: ValidatorId = validity_other_key.public().into();
let validity_other_index = 1;
groups.insert(para_id, GroupInfo {
@@ -684,9 +682,9 @@ mod tests {
});
let shared_table = SharedTable::new(
&[local_id, validity_other],
[local_id, validity_other].to_vec(),
groups,
local_key.clone(),
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
None,
@@ -705,7 +703,7 @@ mod tests {
let candidate_statement = GenericStatement::Candidate(candidate);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key, &parent_hash);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key.into(), &parent_hash);
let signed_statement = ::table::generic::SignedStatement {
statement: candidate_statement,
signature: signature.into(),
@@ -806,11 +804,12 @@ mod tests {
let para_id = ParaId::from(1);
let parent_hash = Default::default();
let local_key = Arc::new(Ed25519Keyring::Alice.pair());
let local_id = local_key.public();
let local_key = Sr25519Keyring::Alice.pair();
let local_id: ValidatorId = local_key.public().into();
let local_key: Arc<ValidatorPair> = Arc::new(local_key.into());
let validity_other_key = Ed25519Keyring::Bob.pair();
let validity_other = validity_other_key.public();
let validity_other_key = Sr25519Keyring::Bob.pair();
let validity_other: ValidatorId = validity_other_key.public().into();
let validity_other_index = 1;
groups.insert(para_id, GroupInfo {
@@ -819,9 +818,9 @@ mod tests {
});
let shared_table = SharedTable::new(
&[local_id, validity_other],
[local_id, validity_other].to_vec(),
groups,
local_key.clone(),
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
None,
@@ -841,7 +840,7 @@ mod tests {
let hash = candidate.hash();
let candidate_statement = GenericStatement::Candidate(candidate);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key, &parent_hash);
let signature = crate::sign_table_statement(&candidate_statement, &validity_other_key.into(), &parent_hash);
let signed_statement = ::table::generic::SignedStatement {
statement: candidate_statement,
signature: signature.into(),
@@ -872,11 +871,12 @@ mod tests {
let extrinsic = Extrinsic { outgoing_messages: Vec::new() };
let parent_hash = Default::default();
let local_key = Arc::new(Ed25519Keyring::Alice.pair());
let local_id = local_key.public();
let local_key = Sr25519Keyring::Alice.pair();
let local_id: ValidatorId = local_key.public().into();
let local_key: Arc<ValidatorPair> = Arc::new(local_key.into());
let validity_other_key = Ed25519Keyring::Bob.pair();
let validity_other = validity_other_key.public();
let validity_other_key = Sr25519Keyring::Bob.pair();
let validity_other: ValidatorId = validity_other_key.public().into();
groups.insert(para_id, GroupInfo {
validity_guarantors: [local_id.clone(), validity_other.clone()].iter().cloned().collect(),
@@ -884,9 +884,9 @@ mod tests {
});
let shared_table = SharedTable::new(
&[local_id, validity_other],
[local_id, validity_other].to_vec(),
groups,
local_key.clone(),
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
None,
@@ -908,7 +908,7 @@ mod tests {
candidate,
pov_block,
extrinsic,
));
)).unwrap();
assert!(shared_table.inner.lock().validated.get(&hash).expect("validation has started").is_done());
@@ -919,29 +919,4 @@ mod tests {
assert!(a.is_none());
}
#[test]
fn index_mapping_from_authorities() {
let authorities_set: &[&[_]] = &[
&[],
&[Ed25519Keyring::Alice.pair().public()],
&[Ed25519Keyring::Alice.pair().public(), Ed25519Keyring::Bob.pair().public()],
&[Ed25519Keyring::Bob.pair().public(), Ed25519Keyring::Alice.pair().public()],
&[Ed25519Keyring::Alice.pair().public(), Ed25519Keyring::Bob.pair().public(), Ed25519Keyring::Charlie.pair().public()],
&[Ed25519Keyring::Charlie.pair().public(), Ed25519Keyring::Bob.pair().public(), Ed25519Keyring::Alice.pair().public()],
];
for authorities in authorities_set {
let shared_table = SharedTable::new(
authorities,
HashMap::new(),
Arc::new(Ed25519Keyring::Alice.pair()),
Default::default(),
ExtrinsicStore::new_in_memory(),
None,
);
let expected_mapping = authorities.iter().enumerate().map(|(i, k)| (i as ValidatorIndex, k.clone())).collect();
assert_eq!(shared_table.context.index_mapping, expected_mapping);
}
}
}