mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
* Fix keystore types * Use SyncCryptoStorePtr * Borrow keystore * Fix unused imports * Fix polkadot service * Fix bitfield-distribution tests * Fix indentation * Fix backing tests * Fix tests * Fix provisioner tests * Removed SyncCryptoStorePtr * Fix services * Address PR feedback * Address PR feedback - 2 * Update CryptoStorePtr imports to be from sp_keystore * Typo * Fix CryptoStore import * Document the reason behind using filesystem keystore * Remove VALIDATORS * Fix duplicate dependency * Mark sp-keystore as optional * Fix availability distribution * Fix call to sign_with * Fix keystore usage * Remove tokio and fix parachains Cargo config * Typos * Fix keystore dereferencing * Fix CryptoStore import * Fix provisioner * Fix node backing * Update services * Cleanup dependencies * Use sync_keystore * Fix node service * Fix node service - 2 * Fix node service - 3 * Rename CryptoStorePtr to SyncCryptoStorePtr * "Update Substrate" * Apply suggestions from code review * Update node/core/backing/Cargo.toml * Update primitives/src/v0.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Fix wasm build * Update Cargo.lock Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Generated
+200
-146
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,9 @@ edition = "2018"
|
||||
[dependencies]
|
||||
futures = "0.3.5"
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
keystore = { package = "sc-keystore", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
polkadot-node-primitives = { path = "../../primitives" }
|
||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||
@@ -22,7 +22,9 @@ log = "0.4.8"
|
||||
|
||||
[dev-dependencies]
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
futures = { version = "0.3.5", features = ["thread-pool"] }
|
||||
assert_matches = "1.3.0"
|
||||
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||
|
||||
@@ -27,7 +27,7 @@ use futures::{
|
||||
Future, FutureExt, SinkExt, StreamExt,
|
||||
};
|
||||
|
||||
use keystore::KeyStorePtr;
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
use polkadot_primitives::v1::{
|
||||
CommittedCandidateReceipt, BackedCandidate, Id as ParaId, ValidatorId,
|
||||
ValidatorIndex, SigningContext, PoV,
|
||||
@@ -101,6 +101,7 @@ struct CandidateBackingJob {
|
||||
seconded: Option<Hash>,
|
||||
/// We have already reported misbehaviors for these validators.
|
||||
reported_misbehavior_for: HashSet<ValidatorIndex>,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
table: Table<TableContext>,
|
||||
table_context: TableContext,
|
||||
metrics: Metrics,
|
||||
@@ -328,9 +329,12 @@ impl CandidateBackingJob {
|
||||
};
|
||||
|
||||
let issued_statement = statement.is_some();
|
||||
if let Some(signed_statement) = statement.and_then(|s| self.sign_statement(s)) {
|
||||
self.import_statement(&signed_statement).await?;
|
||||
self.distribute_signed_statement(signed_statement).await?;
|
||||
|
||||
if let Some(statement) = statement {
|
||||
if let Some(signed_statement) = self.sign_statement(statement).await {
|
||||
self.import_statement(&signed_statement).await?;
|
||||
self.distribute_signed_statement(signed_statement).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(issued_statement)
|
||||
@@ -530,7 +534,7 @@ impl CandidateBackingJob {
|
||||
|
||||
self.issued_statements.insert(candidate_hash);
|
||||
|
||||
if let Some(signed_statement) = self.sign_statement(statement) {
|
||||
if let Some(signed_statement) = self.sign_statement(statement).await {
|
||||
self.distribute_signed_statement(signed_statement).await?;
|
||||
}
|
||||
|
||||
@@ -553,8 +557,13 @@ impl CandidateBackingJob {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sign_statement(&self, statement: Statement) -> Option<SignedFullStatement> {
|
||||
let signed = self.table_context.validator.as_ref()?.sign(statement);
|
||||
async fn sign_statement(&self, statement: Statement) -> Option<SignedFullStatement> {
|
||||
let signed = self.table_context
|
||||
.validator
|
||||
.as_ref()?
|
||||
.sign(self.keystore.clone(), statement)
|
||||
.await
|
||||
.ok()?;
|
||||
self.metrics.on_statement_signed();
|
||||
Some(signed)
|
||||
}
|
||||
@@ -694,14 +703,14 @@ impl util::JobTrait for CandidateBackingJob {
|
||||
type ToJob = ToJob;
|
||||
type FromJob = FromJob;
|
||||
type Error = Error;
|
||||
type RunArgs = KeyStorePtr;
|
||||
type RunArgs = SyncCryptoStorePtr;
|
||||
type Metrics = Metrics;
|
||||
|
||||
const NAME: &'static str = "CandidateBackingJob";
|
||||
|
||||
fn run(
|
||||
parent: Hash,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
metrics: Metrics,
|
||||
rx_to: mpsc::Receiver<Self::ToJob>,
|
||||
mut tx_from: mpsc::Sender<Self::FromJob>,
|
||||
@@ -748,7 +757,7 @@ impl util::JobTrait for CandidateBackingJob {
|
||||
&validators,
|
||||
signing_context,
|
||||
keystore.clone(),
|
||||
) {
|
||||
).await {
|
||||
Ok(v) => v,
|
||||
Err(util::Error::NotAValidator) => { return Ok(()) },
|
||||
Err(e) => {
|
||||
@@ -802,6 +811,7 @@ impl util::JobTrait for CandidateBackingJob {
|
||||
issued_statements: HashSet::new(),
|
||||
seconded: None,
|
||||
reported_misbehavior_for: HashSet::new(),
|
||||
keystore,
|
||||
table: Table::default(),
|
||||
table_context,
|
||||
metrics,
|
||||
@@ -859,17 +869,17 @@ impl metrics::Metrics for Metrics {
|
||||
}
|
||||
}
|
||||
|
||||
delegated_subsystem!(CandidateBackingJob(KeyStorePtr, Metrics) <- ToJob as CandidateBackingSubsystem);
|
||||
delegated_subsystem!(CandidateBackingJob(SyncCryptoStorePtr, Metrics) <- ToJob as CandidateBackingSubsystem);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use assert_matches::assert_matches;
|
||||
use futures::{executor, future, Future};
|
||||
use futures::{future, Future};
|
||||
use polkadot_primitives::v1::{
|
||||
ScheduledCore, BlockData, CandidateCommitments,
|
||||
PersistedValidationData, ValidationData, TransientValidationData, HeadData,
|
||||
ValidatorPair, ValidityAttestation, GroupRotationInfo,
|
||||
ValidityAttestation, GroupRotationInfo,
|
||||
};
|
||||
use polkadot_subsystem::{
|
||||
messages::RuntimeApiRequest,
|
||||
@@ -877,6 +887,8 @@ mod tests {
|
||||
};
|
||||
use polkadot_node_primitives::InvalidCandidate;
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStore};
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
|
||||
@@ -885,7 +897,7 @@ mod tests {
|
||||
|
||||
struct TestState {
|
||||
chain_ids: Vec<ParaId>,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
validators: Vec<Sr25519Keyring>,
|
||||
validator_public: Vec<ValidatorId>,
|
||||
validation_data: ValidationData,
|
||||
@@ -912,9 +924,9 @@ mod tests {
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
|
||||
let keystore = keystore::Store::new_in_memory();
|
||||
let keystore = Arc::new(sc_keystore::LocalKeystore::in_memory());
|
||||
// Make sure `Alice` key is in the keystore, so this mocked node will be a parachain validator.
|
||||
keystore.write().insert_ephemeral_from_seed::<ValidatorPair>(&validators[0].to_seed())
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, Some(&validators[0].to_seed()))
|
||||
.expect("Insert key into keystore");
|
||||
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
@@ -985,7 +997,7 @@ mod tests {
|
||||
virtual_overseer: polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle<CandidateBackingMessage>,
|
||||
}
|
||||
|
||||
fn test_harness<T: Future<Output=()>>(keystore: KeyStorePtr, test: impl FnOnce(TestHarness) -> T) {
|
||||
fn test_harness<T: Future<Output=()>>(keystore: SyncCryptoStorePtr, test: impl FnOnce(TestHarness) -> T) {
|
||||
let pool = sp_core::testing::TaskExecutor::new();
|
||||
|
||||
let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone());
|
||||
@@ -998,8 +1010,7 @@ mod tests {
|
||||
|
||||
futures::pin_mut!(test_fut);
|
||||
futures::pin_mut!(subsystem);
|
||||
|
||||
executor::block_on(future::select(test_fut, subsystem));
|
||||
futures::executor::block_on(future::select(test_fut, subsystem));
|
||||
}
|
||||
|
||||
fn make_erasure_root(test: &TestState, pov: PoV) -> Hash {
|
||||
@@ -1203,20 +1214,29 @@ mod tests {
|
||||
}.build();
|
||||
|
||||
let candidate_a_hash = candidate_a.hash();
|
||||
|
||||
let public0 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[0].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let public2 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[2].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let signed_a = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Seconded(candidate_a.clone()),
|
||||
&test_state.signing_context,
|
||||
2,
|
||||
&test_state.validators[2].pair().into(),
|
||||
);
|
||||
&public2.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let signed_b = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Valid(candidate_a_hash),
|
||||
&test_state.signing_context,
|
||||
0,
|
||||
&test_state.validators[0].pair().into(),
|
||||
);
|
||||
&public0.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let statement = CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone());
|
||||
|
||||
@@ -1330,27 +1350,37 @@ mod tests {
|
||||
}.build();
|
||||
|
||||
let candidate_a_hash = candidate_a.hash();
|
||||
|
||||
let public0 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[0].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let public2 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[2].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let signed_a = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Seconded(candidate_a.clone()),
|
||||
&test_state.signing_context,
|
||||
2,
|
||||
&test_state.validators[2].pair().into(),
|
||||
);
|
||||
&public2.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let signed_b = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Valid(candidate_a_hash),
|
||||
&test_state.signing_context,
|
||||
0,
|
||||
&test_state.validators[0].pair().into(),
|
||||
);
|
||||
&public0.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let signed_c = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Invalid(candidate_a_hash),
|
||||
&test_state.signing_context,
|
||||
0,
|
||||
&test_state.validators[0].pair().into(),
|
||||
);
|
||||
&public0.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let statement = CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone());
|
||||
|
||||
@@ -1600,12 +1630,18 @@ mod tests {
|
||||
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let validator2 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[2].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
|
||||
let signed_a = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Seconded(candidate.clone()),
|
||||
&test_state.signing_context,
|
||||
2,
|
||||
&test_state.validators[2].pair().into(),
|
||||
);
|
||||
&validator2.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
// Send in a `Statement` with a candidate.
|
||||
let statement = CandidateBackingMessage::Statement(
|
||||
@@ -1733,12 +1769,17 @@ mod tests {
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
let public2 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[2].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let signed_a = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Seconded(candidate.clone()),
|
||||
&test_state.signing_context,
|
||||
2,
|
||||
&test_state.validators[2].pair().into(),
|
||||
);
|
||||
&public2.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
// Send in a `Statement` with a candidate.
|
||||
let statement = CandidateBackingMessage::Statement(
|
||||
@@ -1869,12 +1910,17 @@ mod tests {
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
let public2 = CryptoStore::sr25519_generate_new(
|
||||
&*test_state.keystore,
|
||||
ValidatorId::ID, Some(&test_state.validators[2].to_seed())
|
||||
).await.expect("Insert key into keystore");
|
||||
let seconding = SignedFullStatement::sign(
|
||||
&test_state.keystore,
|
||||
Statement::Seconded(candidate_a.clone()),
|
||||
&test_state.signing_context,
|
||||
2,
|
||||
&test_state.validators[2].pair().into(),
|
||||
);
|
||||
&public2.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
let statement = CandidateBackingMessage::Statement(
|
||||
test_state.relay_parent,
|
||||
|
||||
@@ -12,5 +12,5 @@ log = "0.4.8"
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||
keystore = { package = "sc-keystore", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
wasm-timer = "0.2.4"
|
||||
|
||||
@@ -22,7 +22,7 @@ use futures::{
|
||||
prelude::*,
|
||||
stream, Future,
|
||||
};
|
||||
use keystore::KeyStorePtr;
|
||||
use sp_keystore::{Error as KeystoreError, SyncCryptoStorePtr};
|
||||
use polkadot_node_subsystem::{
|
||||
messages::{
|
||||
self, AllMessages, AvailabilityStoreMessage, BitfieldDistributionMessage,
|
||||
@@ -132,6 +132,9 @@ pub enum Error {
|
||||
/// the runtime API failed to return what we wanted
|
||||
#[from]
|
||||
Runtime(RuntimeApiError),
|
||||
/// the keystore failed to process signing request
|
||||
#[from]
|
||||
Keystore(KeystoreError),
|
||||
}
|
||||
|
||||
// if there is a candidate pending availability, query the Availability Store
|
||||
@@ -289,7 +292,7 @@ impl JobTrait for BitfieldSigningJob {
|
||||
type ToJob = ToJob;
|
||||
type FromJob = FromJob;
|
||||
type Error = Error;
|
||||
type RunArgs = KeyStorePtr;
|
||||
type RunArgs = SyncCryptoStorePtr;
|
||||
type Metrics = Metrics;
|
||||
|
||||
const NAME: &'static str = "BitfieldSigningJob";
|
||||
@@ -308,7 +311,7 @@ impl JobTrait for BitfieldSigningJob {
|
||||
|
||||
// now do all the work we can before we need to wait for the availability store
|
||||
// if we're not a validator, we can just succeed effortlessly
|
||||
let validator = match Validator::new(relay_parent, keystore, sender.clone()).await {
|
||||
let validator = match Validator::new(relay_parent, keystore.clone(), sender.clone()).await {
|
||||
Ok(validator) => validator,
|
||||
Err(util::Error::NotAValidator) => return Ok(()),
|
||||
Err(err) => return Err(Error::Util(err)),
|
||||
@@ -329,7 +332,10 @@ impl JobTrait for BitfieldSigningJob {
|
||||
Ok(bitfield) => bitfield,
|
||||
};
|
||||
|
||||
let signed_bitfield = validator.sign(bitfield);
|
||||
let signed_bitfield = validator
|
||||
.sign(keystore.clone(), bitfield)
|
||||
.await
|
||||
.map_err(|e| Error::Keystore(e))?;
|
||||
metrics.on_bitfield_signed();
|
||||
|
||||
// make an anonymous scope to contain some use statements to simplify creating the outbound message
|
||||
|
||||
@@ -16,4 +16,8 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4"
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
futures-timer = "3.0.2"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
@@ -549,36 +549,37 @@ mod tests {
|
||||
mod select_availability_bitfields {
|
||||
use super::super::*;
|
||||
use super::{default_bitvec, occupied_core};
|
||||
use lazy_static::lazy_static;
|
||||
use polkadot_primitives::v1::{SigningContext, ValidatorIndex, ValidatorPair};
|
||||
use sp_core::crypto::Pair;
|
||||
use std::sync::Mutex;
|
||||
use futures::executor::block_on;
|
||||
use std::sync::Arc;
|
||||
use polkadot_primitives::v1::{SigningContext, ValidatorIndex, ValidatorId};
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
||||
use sc_keystore::LocalKeystore;
|
||||
|
||||
lazy_static! {
|
||||
// we can use a normal mutex here, not a futures-aware one, because we don't use any futures-based
|
||||
// concurrency when accessing this. The risk of contention is that multiple tests are run in parallel,
|
||||
// in independent threads, in which case a standard mutex suffices.
|
||||
static ref VALIDATORS: Mutex<HashMap<ValidatorIndex, ValidatorPair>> = Mutex::new(HashMap::new());
|
||||
}
|
||||
|
||||
fn signed_bitfield(
|
||||
async fn signed_bitfield(
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
field: CoreAvailability,
|
||||
validator_idx: ValidatorIndex,
|
||||
) -> SignedAvailabilityBitfield {
|
||||
let mut lock = VALIDATORS.lock().unwrap();
|
||||
let validator = lock
|
||||
.entry(validator_idx)
|
||||
.or_insert_with(|| ValidatorPair::generate().0);
|
||||
let public = CryptoStore::sr25519_generate_new(&**keystore, ValidatorId::ID, None)
|
||||
.await
|
||||
.expect("generated sr25519 key");
|
||||
SignedAvailabilityBitfield::sign(
|
||||
&keystore,
|
||||
field.into(),
|
||||
&<SigningContext<Hash>>::default(),
|
||||
validator_idx,
|
||||
validator,
|
||||
)
|
||||
&public.into(),
|
||||
).await.expect("Should be signed")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_more_than_one_per_validator() {
|
||||
// Configure filesystem-based keystore as generating keys without seed
|
||||
// would trigger the key to be generated on the filesystem.
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||
.expect("Creates keystore"));
|
||||
let bitvec = default_bitvec();
|
||||
|
||||
let cores = vec![occupied_core(0), occupied_core(1)];
|
||||
@@ -586,9 +587,9 @@ mod tests {
|
||||
// we pass in three bitfields with two validators
|
||||
// this helps us check the postcondition that we get two bitfields back, for which the validators differ
|
||||
let bitfields = vec![
|
||||
signed_bitfield(bitvec.clone(), 0),
|
||||
signed_bitfield(bitvec.clone(), 1),
|
||||
signed_bitfield(bitvec, 1),
|
||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
||||
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
||||
];
|
||||
|
||||
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
||||
@@ -602,14 +603,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn each_corresponds_to_an_occupied_core() {
|
||||
// Configure filesystem-based keystore as generating keys without seed
|
||||
// would trigger the key to be generated on the filesystem.
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||
.expect("Creates keystore"));
|
||||
let bitvec = default_bitvec();
|
||||
|
||||
let cores = vec![CoreState::Free, CoreState::Scheduled(Default::default())];
|
||||
|
||||
let bitfields = vec![
|
||||
signed_bitfield(bitvec.clone(), 0),
|
||||
signed_bitfield(bitvec.clone(), 1),
|
||||
signed_bitfield(bitvec, 1),
|
||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
||||
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
||||
];
|
||||
|
||||
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
||||
@@ -621,6 +627,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn more_set_bits_win_conflicts() {
|
||||
// Configure filesystem-based keystore as generating keys without seed
|
||||
// would trigger the key to be generated on the filesystem.
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||
.expect("Creates keystore"));
|
||||
let bitvec_zero = default_bitvec();
|
||||
let bitvec_one = {
|
||||
let mut bitvec = bitvec_zero.clone();
|
||||
@@ -631,8 +642,8 @@ mod tests {
|
||||
let cores = vec![occupied_core(0)];
|
||||
|
||||
let bitfields = vec![
|
||||
signed_bitfield(bitvec_zero, 0),
|
||||
signed_bitfield(bitvec_one.clone(), 0),
|
||||
block_on(signed_bitfield(&keystore, bitvec_zero, 0)),
|
||||
block_on(signed_bitfield(&keystore, bitvec_one.clone(), 0)),
|
||||
];
|
||||
|
||||
// this test is probablistic: chances are excellent that it does what it claims to.
|
||||
|
||||
@@ -9,21 +9,23 @@ futures = "0.3.5"
|
||||
log = "0.4.11"
|
||||
streamunordered = "0.5.1"
|
||||
codec = { package="parity-scale-codec", version = "1.3.4", features = ["std"] }
|
||||
derive_more = "0.99.9"
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
polkadot-erasure-coding = { path = "../../../erasure-coding" }
|
||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||
polkadot-network-bridge = { path = "../../network/bridge" }
|
||||
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
derive_more = "0.99.9"
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[dev-dependencies]
|
||||
polkadot-subsystem-testhelpers = { package = "polkadot-node-subsystem-test-helpers", path = "../../subsystem-test-helpers" }
|
||||
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
parking_lot = "0.11.0"
|
||||
futures-timer = "3.0.2"
|
||||
env_logger = "0.7.1"
|
||||
|
||||
@@ -25,12 +25,8 @@
|
||||
use codec::{Decode, Encode};
|
||||
use futures::{channel::oneshot, FutureExt};
|
||||
|
||||
use keystore::KeyStorePtr;
|
||||
use sp_core::{
|
||||
crypto::Public,
|
||||
traits::BareCryptoStore,
|
||||
};
|
||||
use sc_keystore as keystore;
|
||||
use sp_core::crypto::Public;
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
||||
|
||||
use log::{trace, warn};
|
||||
use polkadot_erasure_coding::branch_hash;
|
||||
@@ -293,7 +289,7 @@ impl ProtocolState {
|
||||
/// which depends on the message type received.
|
||||
async fn handle_network_msg<Context>(
|
||||
ctx: &mut Context,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
state: &mut ProtocolState,
|
||||
metrics: &Metrics,
|
||||
bridge_message: NetworkBridgeEvent<protocol_v1::AvailabilityDistributionMessage>,
|
||||
@@ -332,7 +328,7 @@ where
|
||||
/// Handle the changes necessary when our view changes.
|
||||
async fn handle_our_view_change<Context>(
|
||||
ctx: &mut Context,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
state: &mut ProtocolState,
|
||||
view: View,
|
||||
metrics: &Metrics,
|
||||
@@ -353,7 +349,7 @@ where
|
||||
let validator_index = obtain_our_validator_index(
|
||||
&validators,
|
||||
keystore.clone(),
|
||||
);
|
||||
).await;
|
||||
state.add_relay_parent(ctx, added, validators, validator_index).await?;
|
||||
}
|
||||
|
||||
@@ -579,18 +575,16 @@ where
|
||||
/// Obtain the first key which has a signing key.
|
||||
/// Returns the index within the validator set as `ValidatorIndex`, if there exists one,
|
||||
/// otherwise, `None` is returned.
|
||||
fn obtain_our_validator_index(
|
||||
async fn obtain_our_validator_index(
|
||||
validators: &[ValidatorId],
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
) -> Option<ValidatorIndex> {
|
||||
let keystore = keystore.read();
|
||||
validators.iter().enumerate().find_map(|(idx, validator)| {
|
||||
if keystore.has_keys(&[(validator.to_raw_vec(), PARACHAIN_KEY_TYPE_ID)]) {
|
||||
Some(idx as ValidatorIndex)
|
||||
} else {
|
||||
None
|
||||
for (idx, validator) in validators.iter().enumerate() {
|
||||
if CryptoStore::has_keys(&*keystore, &[(validator.to_raw_vec(), PARACHAIN_KEY_TYPE_ID)]).await {
|
||||
return Some(idx as ValidatorIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Handle an incoming message from a peer.
|
||||
@@ -712,7 +706,7 @@ where
|
||||
/// The bitfield distribution subsystem.
|
||||
pub struct AvailabilityDistributionSubsystem {
|
||||
/// Pointer to a keystore, which is required for determining this nodes validator index.
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
/// Prometheus metrics.
|
||||
metrics: Metrics,
|
||||
}
|
||||
@@ -722,7 +716,7 @@ impl AvailabilityDistributionSubsystem {
|
||||
const K: usize = 3;
|
||||
|
||||
/// Create a new instance of the availability distribution.
|
||||
pub fn new(keystore: KeyStorePtr, metrics: Metrics) -> Self {
|
||||
pub fn new(keystore: SyncCryptoStorePtr, metrics: Metrics) -> Self {
|
||||
Self { keystore, metrics }
|
||||
}
|
||||
|
||||
@@ -741,7 +735,7 @@ impl AvailabilityDistributionSubsystem {
|
||||
} => {
|
||||
if let Err(e) = handle_network_msg(
|
||||
&mut ctx,
|
||||
self.keystore.clone(),
|
||||
&self.keystore.clone(),
|
||||
&mut state,
|
||||
&self.metrics,
|
||||
event,
|
||||
|
||||
@@ -20,7 +20,7 @@ use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks};
|
||||
use polkadot_primitives::v1::{
|
||||
AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GroupIndex,
|
||||
GroupRotationInfo, HeadData, PersistedValidationData, OccupiedCore,
|
||||
PoV, ScheduledCore, ValidatorPair,
|
||||
PoV, ScheduledCore,
|
||||
};
|
||||
use polkadot_subsystem_testhelpers::{self as test_helpers};
|
||||
use polkadot_node_subsystem_util::TimeoutExt;
|
||||
@@ -29,7 +29,10 @@ use polkadot_node_network_protocol::ObservedRole;
|
||||
use futures::{executor, future, Future};
|
||||
use futures_timer::Delay;
|
||||
use smallvec::smallvec;
|
||||
use std::time::Duration;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
||||
use sp_application_crypto::AppKey;
|
||||
|
||||
macro_rules! view {
|
||||
( $( $hash:expr ),* $(,)? ) => [
|
||||
@@ -57,7 +60,7 @@ struct TestHarness {
|
||||
}
|
||||
|
||||
fn test_harness<T: Future<Output = ()>>(
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
test: impl FnOnce(TestHarness) -> T,
|
||||
) {
|
||||
let _ = env_logger::builder()
|
||||
@@ -144,7 +147,7 @@ struct TestState {
|
||||
validator_index: Option<ValidatorIndex>,
|
||||
validator_groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo),
|
||||
head_data: HashMap<ParaId, HeadData>,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
relay_parent: Hash,
|
||||
ancestors: Vec<Hash>,
|
||||
availability_cores: Vec<CoreState>,
|
||||
@@ -170,11 +173,9 @@ impl Default for TestState {
|
||||
Sr25519Keyring::Dave,
|
||||
];
|
||||
|
||||
let keystore = keystore::Store::new_in_memory();
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
|
||||
keystore
|
||||
.write()
|
||||
.insert_ephemeral_from_seed::<ValidatorPair>(&validators[0].to_seed())
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, Some(&validators[0].to_seed()))
|
||||
.expect("Insert key into keystore");
|
||||
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
@@ -22,8 +22,12 @@ sc-network = { git = "https://github.com/paritytech/substrate", branch = "master
|
||||
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
parking_lot = "0.11.0"
|
||||
maplit = "1.0.2"
|
||||
smol = "0.3.3"
|
||||
env_logger = "0.7.1"
|
||||
assert_matches = "1.3.0"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
@@ -674,10 +674,13 @@ mod test {
|
||||
use bitvec::bitvec;
|
||||
use futures::executor;
|
||||
use maplit::hashmap;
|
||||
use polkadot_primitives::v1::{Signed, ValidatorPair, AvailabilityBitfield};
|
||||
use polkadot_primitives::v1::{Signed, AvailabilityBitfield};
|
||||
use polkadot_node_subsystem_test_helpers::make_subsystem_context;
|
||||
use polkadot_node_subsystem_util::TimeoutExt;
|
||||
use sp_core::crypto::Pair;
|
||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
||||
use sp_application_crypto::AppKey;
|
||||
use sc_keystore::LocalKeystore;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use assert_matches::assert_matches;
|
||||
use polkadot_node_network_protocol::ObservedRole;
|
||||
@@ -735,22 +738,28 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn state_with_view(view: View, relay_parent: Hash) -> (ProtocolState, SigningContext, ValidatorPair) {
|
||||
fn state_with_view(
|
||||
view: View,
|
||||
relay_parent: Hash,
|
||||
keystore_path: &tempfile::TempDir,
|
||||
) -> (ProtocolState, SigningContext, SyncCryptoStorePtr, ValidatorId) {
|
||||
let mut state = ProtocolState::default();
|
||||
|
||||
let (validator_pair, _seed) = ValidatorPair::generate();
|
||||
let validator = validator_pair.public();
|
||||
|
||||
let signing_context = SigningContext {
|
||||
session_index: 1,
|
||||
parent_hash: relay_parent.clone(),
|
||||
};
|
||||
|
||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||
.expect("Creates keystore"));
|
||||
let validator = SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, None)
|
||||
.expect("generating sr25519 key not to fail");
|
||||
|
||||
state.per_relay_parent = view.0.iter().map(|relay_parent| {(
|
||||
relay_parent.clone(),
|
||||
PerRelayParentData {
|
||||
signing_context: signing_context.clone(),
|
||||
validator_set: vec![validator.clone()],
|
||||
validator_set: vec![validator.clone().into()],
|
||||
one_per_validator: hashmap!{},
|
||||
message_received_from_peer: hashmap!{},
|
||||
message_sent_to_peer: hashmap!{},
|
||||
@@ -759,7 +768,7 @@ mod test {
|
||||
|
||||
state.view = view;
|
||||
|
||||
(state, signing_context, validator_pair)
|
||||
(state, signing_context, keystore, validator.into())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -780,16 +789,19 @@ mod test {
|
||||
parent_hash: hash_a.clone(),
|
||||
};
|
||||
|
||||
// validator 0 key pair
|
||||
let (validator_pair, _seed) = ValidatorPair::generate();
|
||||
let validator = validator_pair.public();
|
||||
|
||||
// another validator not part of the validatorset
|
||||
let (mallicious, _seed) = ValidatorPair::generate();
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||
.expect("Creates keystore"));
|
||||
let malicious = SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, None)
|
||||
.expect("Malicious key created");
|
||||
let validator = SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, None)
|
||||
.expect("Malicious key created");
|
||||
|
||||
let payload = AvailabilityBitfield(bitvec![bitvec::order::Lsb0, u8; 1u8; 32]);
|
||||
let signed =
|
||||
Signed::<AvailabilityBitfield>::sign(payload, &signing_context, 0, &mallicious);
|
||||
executor::block_on(Signed::<AvailabilityBitfield>::sign(&keystore, payload, &signing_context, 0, &malicious.into()))
|
||||
.expect("should be signed");
|
||||
|
||||
let msg = BitfieldGossipMessage {
|
||||
relay_parent: hash_a.clone(),
|
||||
@@ -801,7 +813,7 @@ mod test {
|
||||
make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
||||
|
||||
let mut state = prewarmed_state(
|
||||
validator.clone(),
|
||||
validator.into(),
|
||||
signing_context.clone(),
|
||||
msg.clone(),
|
||||
vec![peer_b.clone()],
|
||||
@@ -842,15 +854,17 @@ mod test {
|
||||
let peer_b = PeerId::random();
|
||||
assert_ne!(peer_a, peer_b);
|
||||
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
// validator 0 key pair
|
||||
let (mut state, signing_context, validator_pair) =
|
||||
state_with_view(view![hash_a, hash_b], hash_a.clone());
|
||||
let (mut state, signing_context, keystore, validator) =
|
||||
state_with_view(view![hash_a, hash_b], hash_a.clone(), &keystore_path);
|
||||
|
||||
state.peer_views.insert(peer_b.clone(), view![hash_a]);
|
||||
|
||||
let payload = AvailabilityBitfield(bitvec![bitvec::order::Lsb0, u8; 1u8; 32]);
|
||||
let signed =
|
||||
Signed::<AvailabilityBitfield>::sign(payload, &signing_context, 42, &validator_pair);
|
||||
executor::block_on(Signed::<AvailabilityBitfield>::sign(&keystore, payload, &signing_context, 42, &validator))
|
||||
.expect("should be signed");
|
||||
|
||||
let msg = BitfieldGossipMessage {
|
||||
relay_parent: hash_a.clone(),
|
||||
@@ -896,14 +910,16 @@ mod test {
|
||||
let peer_b = PeerId::random();
|
||||
assert_ne!(peer_a, peer_b);
|
||||
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
// validator 0 key pair
|
||||
let (mut state, signing_context, validator_pair) =
|
||||
state_with_view(view![hash_a, hash_b], hash_a.clone());
|
||||
let (mut state, signing_context, keystore, validator) =
|
||||
state_with_view(view![hash_a, hash_b], hash_a.clone(), &keystore_path);
|
||||
|
||||
// create a signed message by validator 0
|
||||
let payload = AvailabilityBitfield(bitvec![bitvec::order::Lsb0, u8; 1u8; 32]);
|
||||
let signed_bitfield =
|
||||
Signed::<AvailabilityBitfield>::sign(payload, &signing_context, 0, &validator_pair);
|
||||
executor::block_on(Signed::<AvailabilityBitfield>::sign(&keystore, payload, &signing_context, 0, &validator))
|
||||
.expect("should be signed");
|
||||
|
||||
let msg = BitfieldGossipMessage {
|
||||
relay_parent: hash_a.clone(),
|
||||
@@ -1007,13 +1023,16 @@ mod test {
|
||||
let peer_b = PeerId::random();
|
||||
assert_ne!(peer_a, peer_b);
|
||||
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
// validator 0 key pair
|
||||
let (mut state, signing_context, validator_pair) = state_with_view(view![hash_a, hash_b], hash_a.clone());
|
||||
let (mut state, signing_context, keystore, validator) =
|
||||
state_with_view(view![hash_a, hash_b], hash_a.clone(), &keystore_path);
|
||||
|
||||
// create a signed message by validator 0
|
||||
let payload = AvailabilityBitfield(bitvec![bitvec::order::Lsb0, u8; 1u8; 32]);
|
||||
let signed_bitfield =
|
||||
Signed::<AvailabilityBitfield>::sign(payload, &signing_context, 0, &validator_pair);
|
||||
executor::block_on(Signed::<AvailabilityBitfield>::sign(&keystore, payload, &signing_context, 0, &validator))
|
||||
.expect("should be signed");
|
||||
|
||||
let msg = BitfieldGossipMessage {
|
||||
relay_parent: hash_a.clone(),
|
||||
|
||||
@@ -27,3 +27,6 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||
assert_matches = "1.3.0"
|
||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -978,11 +978,15 @@ impl metrics::Metrics for Metrics {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::Arc;
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_application_crypto::AppKey;
|
||||
use node_primitives::Statement;
|
||||
use polkadot_primitives::v1::CommittedCandidateReceipt;
|
||||
use assert_matches::assert_matches;
|
||||
use futures::executor;
|
||||
use futures::executor::{self, block_on};
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr, SyncCryptoStore};
|
||||
use sc_keystore::LocalKeystore;
|
||||
|
||||
#[test]
|
||||
fn active_head_accepts_only_2_seconded_per_validator() {
|
||||
@@ -1022,13 +1026,22 @@ mod tests {
|
||||
|
||||
let mut head_data = ActiveHeadData::new(validators, session_index);
|
||||
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
let alice_public = SyncCryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Alice.to_seed())
|
||||
).unwrap();
|
||||
let bob_public = SyncCryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Bob.to_seed())
|
||||
).unwrap();
|
||||
|
||||
// note A
|
||||
let a_seconded_val_0 = SignedFullStatement::sign(
|
||||
let a_seconded_val_0 = block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate_a.clone()),
|
||||
&signing_context,
|
||||
0,
|
||||
&Sr25519Keyring::Alice.pair().into(),
|
||||
);
|
||||
&alice_public.into(),
|
||||
)).expect("should be signed");
|
||||
let noted = head_data.note_statement(a_seconded_val_0.clone());
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
@@ -1039,42 +1052,46 @@ mod tests {
|
||||
assert_matches!(noted, NotedStatement::UsefulButKnown);
|
||||
|
||||
// note B
|
||||
let noted = head_data.note_statement(SignedFullStatement::sign(
|
||||
let noted = head_data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate_b.clone()),
|
||||
&signing_context,
|
||||
0,
|
||||
&Sr25519Keyring::Alice.pair().into(),
|
||||
));
|
||||
&alice_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
|
||||
// note C (beyond 2 - ignored)
|
||||
let noted = head_data.note_statement(SignedFullStatement::sign(
|
||||
let noted = head_data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate_c.clone()),
|
||||
&signing_context,
|
||||
0,
|
||||
&Sr25519Keyring::Alice.pair().into(),
|
||||
));
|
||||
&alice_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::NotUseful);
|
||||
|
||||
// note B (new validator)
|
||||
let noted = head_data.note_statement(SignedFullStatement::sign(
|
||||
let noted = head_data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate_b.clone()),
|
||||
&signing_context,
|
||||
1,
|
||||
&Sr25519Keyring::Bob.pair().into(),
|
||||
));
|
||||
&bob_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
|
||||
// note C (new validator)
|
||||
let noted = head_data.note_statement(SignedFullStatement::sign(
|
||||
let noted = head_data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate_c.clone()),
|
||||
&signing_context,
|
||||
1,
|
||||
&Sr25519Keyring::Bob.pair().into(),
|
||||
));
|
||||
&bob_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
}
|
||||
@@ -1252,33 +1269,48 @@ mod tests {
|
||||
session_index,
|
||||
};
|
||||
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
|
||||
let alice_public = SyncCryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Alice.to_seed())
|
||||
).unwrap();
|
||||
let bob_public = SyncCryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Bob.to_seed())
|
||||
).unwrap();
|
||||
let charlie_public = SyncCryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Charlie.to_seed())
|
||||
).unwrap();
|
||||
|
||||
let new_head_data = {
|
||||
let mut data = ActiveHeadData::new(validators, session_index);
|
||||
|
||||
let noted = data.note_statement(SignedFullStatement::sign(
|
||||
let noted = data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate.clone()),
|
||||
&signing_context,
|
||||
0,
|
||||
&Sr25519Keyring::Alice.pair().into(),
|
||||
));
|
||||
&alice_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
|
||||
let noted = data.note_statement(SignedFullStatement::sign(
|
||||
let noted = data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Valid(candidate_hash),
|
||||
&signing_context,
|
||||
1,
|
||||
&Sr25519Keyring::Bob.pair().into(),
|
||||
));
|
||||
&bob_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
|
||||
let noted = data.note_statement(SignedFullStatement::sign(
|
||||
let noted = data.note_statement(block_on(SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Valid(candidate_hash),
|
||||
&signing_context,
|
||||
2,
|
||||
&Sr25519Keyring::Charlie.pair().into(),
|
||||
));
|
||||
&charlie_public.into(),
|
||||
)).expect("should be signed"));
|
||||
|
||||
assert_matches!(noted, NotedStatement::Fresh(_));
|
||||
|
||||
@@ -1399,12 +1431,18 @@ mod tests {
|
||||
session_index,
|
||||
};
|
||||
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
let alice_public = CryptoStore::sr25519_generate_new(
|
||||
&*keystore, ValidatorId::ID, Some(&Sr25519Keyring::Alice.to_seed())
|
||||
).await.unwrap();
|
||||
|
||||
let statement = SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Seconded(candidate),
|
||||
&signing_context,
|
||||
0,
|
||||
&Sr25519Keyring::Alice.pair().into(),
|
||||
);
|
||||
&alice_public.into(),
|
||||
).await.expect("should be signed");
|
||||
|
||||
StoredStatement {
|
||||
comparator: StoredStatementComparator {
|
||||
|
||||
@@ -169,7 +169,7 @@ fn new_partial<RuntimeApi, Executor>(config: &mut Configuration) -> Result<
|
||||
|
||||
let inherent_data_providers = inherents::InherentDataProviders::new();
|
||||
|
||||
let (client, backend, keystore, task_manager) =
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
|
||||
let client = Arc::new(client);
|
||||
|
||||
@@ -231,7 +231,7 @@ fn new_partial<RuntimeApi, Executor>(config: &mut Configuration) -> Result<
|
||||
|
||||
let rpc_extensions_builder = {
|
||||
let client = client.clone();
|
||||
let keystore = keystore.clone();
|
||||
let keystore = keystore_container.sync_keystore();
|
||||
let transaction_pool = transaction_pool.clone();
|
||||
let select_chain = select_chain.clone();
|
||||
|
||||
@@ -260,7 +260,7 @@ fn new_partial<RuntimeApi, Executor>(config: &mut Configuration) -> Result<
|
||||
};
|
||||
|
||||
Ok(service::PartialComponents {
|
||||
client, backend, task_manager, keystore, select_chain, import_queue, transaction_pool,
|
||||
client, backend, task_manager, keystore_container, select_chain, import_queue, transaction_pool,
|
||||
inherent_data_providers,
|
||||
other: (rpc_extensions_builder, import_setup, rpc_setup)
|
||||
})
|
||||
@@ -338,8 +338,6 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
|
||||
Executor: NativeExecutionDispatch + 'static,
|
||||
{
|
||||
use sp_core::traits::BareCryptoStorePtr;
|
||||
|
||||
let is_collator = collating_for.is_some();
|
||||
let role = config.role.clone();
|
||||
let is_authority = role.is_authority() && !is_collator;
|
||||
@@ -351,7 +349,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
client,
|
||||
backend,
|
||||
mut task_manager,
|
||||
keystore,
|
||||
keystore_container,
|
||||
select_chain,
|
||||
import_queue,
|
||||
transaction_pool,
|
||||
@@ -388,7 +386,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
config,
|
||||
backend: backend.clone(),
|
||||
client: client.clone(),
|
||||
keystore: keystore.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
network: network.clone(),
|
||||
rpc_extensions_builder: Box::new(rpc_extensions_builder),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
@@ -454,7 +452,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
);
|
||||
|
||||
let babe_config = babe::BabeParams {
|
||||
keystore: keystore.clone(),
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
client: client.clone(),
|
||||
select_chain,
|
||||
block_import,
|
||||
@@ -473,7 +471,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
// if the node isn't actively participating in consensus then it doesn't
|
||||
// need a keystore, regardless of which protocol we use below.
|
||||
let keystore_opt = if is_authority {
|
||||
Some(keystore.clone() as BareCryptoStorePtr)
|
||||
Some(keystore_container.sync_keystore())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -546,7 +544,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
Role::Authority { ref sentry_nodes } => (
|
||||
sentry_nodes.clone(),
|
||||
authority_discovery::Role::Authority (
|
||||
keystore.clone(),
|
||||
keystore_container.keystore(),
|
||||
),
|
||||
),
|
||||
Role::Sentry {..} => (
|
||||
@@ -560,17 +558,17 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
let dht_event_stream = network_event_stream.filter_map(|e| async move { match e {
|
||||
Event::Dht(e) => Some(e),
|
||||
_ => None,
|
||||
}}).boxed();
|
||||
}});
|
||||
let (authority_discovery_worker, _service) = authority_discovery::new_worker_and_service(
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
sentries,
|
||||
dht_event_stream,
|
||||
Box::pin(dht_event_stream),
|
||||
authority_discovery_role,
|
||||
prometheus_registry.clone(),
|
||||
);
|
||||
|
||||
task_manager.spawn_handle().spawn("authority-discovery-worker", authority_discovery_worker);
|
||||
task_manager.spawn_handle().spawn("authority-discovery-worker", authority_discovery_worker.run());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +596,7 @@ fn new_light<Runtime, Dispatch>(mut config: Configuration) -> Result<(TaskManage
|
||||
set_prometheus_registry(&mut config)?;
|
||||
use sc_client_api::backend::RemoteBackend;
|
||||
|
||||
let (client, backend, keystore, mut task_manager, on_demand) =
|
||||
let (client, backend, keystore_container, mut task_manager, on_demand) =
|
||||
service::new_light_parts::<Block, Runtime, Dispatch>(&config)?;
|
||||
|
||||
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
||||
@@ -686,7 +684,7 @@ fn new_light<Runtime, Dispatch>(mut config: Configuration) -> Result<(TaskManage
|
||||
task_manager: &mut task_manager,
|
||||
telemetry_connection_sinks: service::TelemetryConnectionSinks::default(),
|
||||
config,
|
||||
keystore,
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
backend,
|
||||
transaction_pool,
|
||||
client,
|
||||
|
||||
@@ -22,9 +22,10 @@ polkadot-node-subsystem = { path = "../subsystem" }
|
||||
polkadot-primitives = { path = "../../primitives" }
|
||||
polkadot-statement-table = { path = "../../statement-table" }
|
||||
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -37,16 +37,23 @@ use futures::{
|
||||
task,
|
||||
};
|
||||
use futures_timer::Delay;
|
||||
use sc_keystore::KeyStorePtr;
|
||||
use parity_scale_codec::Encode;
|
||||
use pin_project::{pin_project, pinned_drop};
|
||||
use polkadot_primitives::v1::{
|
||||
CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, PersistedValidationData,
|
||||
GroupRotationInfo, Hash, Id as ParaId, ValidationData, OccupiedCoreAssumption,
|
||||
SessionIndex, Signed, SigningContext, ValidationCode, ValidatorId, ValidatorIndex,
|
||||
ValidatorPair,
|
||||
};
|
||||
use sp_core::{Pair, traits::SpawnNamed};
|
||||
use sp_core::{
|
||||
traits::SpawnNamed,
|
||||
Public
|
||||
};
|
||||
use sp_application_crypto::AppKey;
|
||||
use sp_keystore::{
|
||||
CryptoStore,
|
||||
SyncCryptoStorePtr,
|
||||
Error as KeystoreError,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::{TryFrom, TryInto},
|
||||
@@ -281,11 +288,13 @@ specialize_requests_ctx! {
|
||||
}
|
||||
|
||||
/// From the given set of validators, find the first key we can sign with, if any.
|
||||
pub fn signing_key(validators: &[ValidatorId], keystore: &KeyStorePtr) -> Option<ValidatorPair> {
|
||||
let keystore = keystore.read();
|
||||
validators
|
||||
.iter()
|
||||
.find_map(|v| keystore.key_pair::<ValidatorPair>(&v).ok())
|
||||
pub async fn signing_key(validators: &[ValidatorId], keystore: SyncCryptoStorePtr) -> Option<ValidatorId> {
|
||||
for v in validators.iter() {
|
||||
if CryptoStore::has_keys(&*keystore, &[(v.to_raw_vec(), ValidatorId::ID)]).await {
|
||||
return Some(v.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Local validator information
|
||||
@@ -294,7 +303,7 @@ pub fn signing_key(validators: &[ValidatorId], keystore: &KeyStorePtr) -> Option
|
||||
/// relay chain block.
|
||||
pub struct Validator {
|
||||
signing_context: SigningContext,
|
||||
key: ValidatorPair,
|
||||
key: ValidatorId,
|
||||
index: ValidatorIndex,
|
||||
}
|
||||
|
||||
@@ -302,7 +311,7 @@ impl Validator {
|
||||
/// Get a struct representing this node's validator if this node is in fact a validator in the context of the given block.
|
||||
pub async fn new<FromJob>(
|
||||
parent: Hash,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
mut sender: mpsc::Sender<FromJob>,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
@@ -324,22 +333,22 @@ impl Validator {
|
||||
|
||||
let validators = validators?;
|
||||
|
||||
Self::construct(&validators, signing_context, keystore)
|
||||
Self::construct(&validators, signing_context, keystore).await
|
||||
}
|
||||
|
||||
/// Construct a validator instance without performing runtime fetches.
|
||||
///
|
||||
/// This can be useful if external code also needs the same data.
|
||||
pub fn construct(
|
||||
pub async fn construct(
|
||||
validators: &[ValidatorId],
|
||||
signing_context: SigningContext,
|
||||
keystore: KeyStorePtr,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
) -> Result<Self, Error> {
|
||||
let key = signing_key(validators, &keystore).ok_or(Error::NotAValidator)?;
|
||||
let key = signing_key(validators, keystore).await.ok_or(Error::NotAValidator)?;
|
||||
let index = validators
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, k)| k == &&key.public())
|
||||
.find(|(_, k)| k == &&key)
|
||||
.map(|(idx, _)| idx as ValidatorIndex)
|
||||
.expect("signing_key would have already returned NotAValidator if the item we're searching for isn't in this list; qed");
|
||||
|
||||
@@ -352,7 +361,7 @@ impl Validator {
|
||||
|
||||
/// Get this validator's id.
|
||||
pub fn id(&self) -> ValidatorId {
|
||||
self.key.public()
|
||||
self.key.clone()
|
||||
}
|
||||
|
||||
/// Get this validator's local index.
|
||||
@@ -366,11 +375,12 @@ impl Validator {
|
||||
}
|
||||
|
||||
/// Sign a payload with this validator
|
||||
pub fn sign<Payload: EncodeAs<RealPayload>, RealPayload: Encode>(
|
||||
pub async fn sign<Payload: EncodeAs<RealPayload>, RealPayload: Encode>(
|
||||
&self,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
payload: Payload,
|
||||
) -> Signed<Payload, RealPayload> {
|
||||
Signed::sign(payload, &self.signing_context, self.index, &self.key)
|
||||
) -> Result<Signed<Payload, RealPayload>, KeystoreError> {
|
||||
Signed::sign(&keystore, payload, &self.signing_context, self.index, &self.key).await
|
||||
}
|
||||
|
||||
/// Validate the payload with this validator
|
||||
|
||||
@@ -10,6 +10,7 @@ parity-scale-codec = { version = "1.3.4", default-features = false, features = [
|
||||
primitives = { package = "sp-core", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
application-crypto = { package = "sp-application-crypto", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
@@ -36,6 +37,8 @@ std = [
|
||||
"inherents/std",
|
||||
"trie/std",
|
||||
"sp-api/std",
|
||||
"sp-authority-discovery/std",
|
||||
"sp-keystore",
|
||||
"sp-std/std",
|
||||
"sp-version/std",
|
||||
"sp-staking/std",
|
||||
|
||||
@@ -18,18 +18,22 @@
|
||||
//! perspective.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_std::convert::TryInto;
|
||||
use sp_std::cmp::Ordering;
|
||||
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use bitvec::vec::BitVec;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::crypto::Pair;
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr, Error as KeystoreError};
|
||||
use primitives::RuntimeDebug;
|
||||
use runtime_primitives::traits::{AppVerify, Block as BlockT};
|
||||
use inherents::InherentIdentifier;
|
||||
#[cfg(feature = "std")]
|
||||
use application_crypto::AppKey;
|
||||
use application_crypto::KeyTypeId;
|
||||
|
||||
pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT, Verify, IdentifyAccount};
|
||||
@@ -863,20 +867,26 @@ impl<Payload: EncodeAs<RealPayload>, RealPayload: Encode> Signed<Payload, RealPa
|
||||
|
||||
/// Sign this payload with the given context and key, storing the validator index.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn sign<H: Encode>(
|
||||
pub async fn sign<H: Encode>(
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
payload: Payload,
|
||||
context: &SigningContext<H>,
|
||||
validator_index: ValidatorIndex,
|
||||
key: &ValidatorPair,
|
||||
) -> Self {
|
||||
key: &ValidatorId,
|
||||
) -> Result<Self, KeystoreError> {
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature = key.sign(&data);
|
||||
Self {
|
||||
let signature: ValidatorSignature = CryptoStore::sign_with(
|
||||
&**keystore,
|
||||
ValidatorId::ID,
|
||||
&key.into(),
|
||||
&data,
|
||||
).await?.try_into().map_err(|_| KeystoreError::KeyNotSupported(ValidatorId::ID))?;
|
||||
Ok(Self {
|
||||
payload,
|
||||
validator_index,
|
||||
signature,
|
||||
real_payload: std::marker::PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Validate the payload given the context and public key.
|
||||
|
||||
@@ -9,6 +9,7 @@ jsonrpc-core = "15.0.0"
|
||||
polkadot-primitives = { path = "../primitives" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -27,6 +27,7 @@ use sp_block_builder::BlockBuilder;
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error as BlockChainError};
|
||||
use sp_consensus::SelectChain;
|
||||
use sp_consensus_babe::BabeApi;
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
use sc_client_api::light::{Fetcher, RemoteBlockchain};
|
||||
use sc_consensus_babe::Epoch;
|
||||
use sc_finality_grandpa::FinalityProofProvider;
|
||||
@@ -54,7 +55,7 @@ pub struct BabeDeps {
|
||||
/// BABE pending epoch changes.
|
||||
pub shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges<Block, Epoch>,
|
||||
/// The keystore that manages the keys of the node.
|
||||
pub keystore: sc_keystore::KeyStorePtr,
|
||||
pub keystore: SyncCryptoStorePtr,
|
||||
}
|
||||
|
||||
/// Dependencies for GRANDPA
|
||||
|
||||
@@ -20,6 +20,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
|
||||
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||
|
||||
pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
@@ -40,6 +41,7 @@ rand = { version = "0.7", default-features = false }
|
||||
rand_chacha = { version = "0.2.2", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
futures = "0.3.4"
|
||||
hex-literal = "0.2.1"
|
||||
keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -51,6 +53,7 @@ pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "m
|
||||
serde_json = "1.0.41"
|
||||
libsecp256k1 = "0.3.2"
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master"}
|
||||
|
||||
|
||||
[features]
|
||||
@@ -67,6 +70,7 @@ std = [
|
||||
"inherents/std",
|
||||
"sp-core/std",
|
||||
"sp-api/std",
|
||||
"sp-keystore",
|
||||
"sp-std/std",
|
||||
"sp-io/std",
|
||||
"frame-support/std",
|
||||
|
||||
@@ -658,14 +658,18 @@ const fn availability_threshold(n_validators: usize) -> usize {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::sync::Arc;
|
||||
use futures::executor::block_on;
|
||||
use primitives::v0::PARACHAIN_KEY_TYPE_ID;
|
||||
use primitives::v1::{BlockNumber, Hash};
|
||||
use primitives::v1::{
|
||||
SignedAvailabilityBitfield, CompactStatement as Statement, ValidityAttestation, CollatorId,
|
||||
CandidateCommitments, SignedStatement, CandidateDescriptor, ValidationCode,
|
||||
};
|
||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
||||
use frame_support::traits::{OnFinalize, OnInitialize};
|
||||
use keyring::Sr25519Keyring;
|
||||
|
||||
use sc_keystore::LocalKeystore;
|
||||
use crate::mock::{
|
||||
new_test_ext, Configuration, Paras, System, Inclusion,
|
||||
GenesisConfig as MockGenesisConfig, Test,
|
||||
@@ -724,10 +728,11 @@ mod tests {
|
||||
assert!(candidate.descriptor().check_collator_signature().is_ok());
|
||||
}
|
||||
|
||||
fn back_candidate(
|
||||
async fn back_candidate(
|
||||
candidate: CommittedCandidateReceipt,
|
||||
validators: &[Sr25519Keyring],
|
||||
group: &[ValidatorIndex],
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
signing_context: &SigningContext,
|
||||
kind: BackingKind,
|
||||
) -> BackedCandidate {
|
||||
@@ -748,11 +753,12 @@ mod tests {
|
||||
*validator_indices.get_mut(idx_in_group).unwrap() = true;
|
||||
|
||||
let signature = SignedStatement::sign(
|
||||
&keystore,
|
||||
Statement::Valid(candidate_hash),
|
||||
signing_context,
|
||||
*val_idx,
|
||||
&key.pair().into(),
|
||||
).signature().clone();
|
||||
&key.public().into(),
|
||||
).await.unwrap().signature().clone();
|
||||
|
||||
validity_votes.push(ValidityAttestation::Explicit(signature).into());
|
||||
}
|
||||
@@ -823,7 +829,8 @@ mod tests {
|
||||
val_ids.iter().map(|v| v.public().into()).collect()
|
||||
}
|
||||
|
||||
fn sign_bitfield(
|
||||
async fn sign_bitfield(
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
key: &Sr25519Keyring,
|
||||
validator_index: ValidatorIndex,
|
||||
bitfield: AvailabilityBitfield,
|
||||
@@ -832,11 +839,12 @@ mod tests {
|
||||
-> SignedAvailabilityBitfield
|
||||
{
|
||||
SignedAvailabilityBitfield::sign(
|
||||
&keystore,
|
||||
bitfield,
|
||||
&signing_context,
|
||||
validator_index,
|
||||
&key.pair().into(),
|
||||
)
|
||||
&key.public().into(),
|
||||
).await.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -931,6 +939,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
@@ -953,12 +965,13 @@ mod tests {
|
||||
{
|
||||
let mut bare_bitfield = default_bitfield();
|
||||
bare_bitfield.0.push(false);
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed],
|
||||
@@ -969,12 +982,13 @@ mod tests {
|
||||
// duplicate.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed.clone(), signed],
|
||||
@@ -985,19 +999,21 @@ mod tests {
|
||||
// out of order.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
let signed_0 = sign_bitfield(
|
||||
let signed_0 = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield.clone(),
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
let signed_1 = sign_bitfield(
|
||||
let signed_1 = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[1],
|
||||
1,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed_1, signed_0],
|
||||
@@ -1009,12 +1025,13 @@ mod tests {
|
||||
{
|
||||
let mut bare_bitfield = default_bitfield();
|
||||
*bare_bitfield.0.get_mut(0).unwrap() = true;
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed],
|
||||
@@ -1025,12 +1042,13 @@ mod tests {
|
||||
// empty bitfield signed: always OK, but kind of useless.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed],
|
||||
@@ -1055,12 +1073,13 @@ mod tests {
|
||||
PendingAvailabilityCommitments::insert(chain_a, default_candidate.commitments);
|
||||
|
||||
*bare_bitfield.0.get_mut(0).unwrap() = true;
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
vec![signed],
|
||||
@@ -1087,12 +1106,13 @@ mod tests {
|
||||
});
|
||||
|
||||
*bare_bitfield.0.get_mut(0).unwrap() = true;
|
||||
let signed = sign_bitfield(
|
||||
let signed = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
0,
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
));
|
||||
|
||||
// no core is freed
|
||||
assert_eq!(
|
||||
@@ -1120,6 +1140,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
@@ -1200,12 +1224,13 @@ mod tests {
|
||||
return None
|
||||
};
|
||||
|
||||
Some(sign_bitfield(
|
||||
Some(block_on(sign_bitfield(
|
||||
&keystore,
|
||||
key,
|
||||
i as ValidatorIndex,
|
||||
to_sign,
|
||||
&signing_context,
|
||||
))
|
||||
)))
|
||||
}).collect();
|
||||
|
||||
assert!(Inclusion::process_bitfields(
|
||||
@@ -1251,6 +1276,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
@@ -1308,13 +1337,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1353,21 +1383,23 @@ mod tests {
|
||||
&mut candidate_b,
|
||||
);
|
||||
|
||||
let backed_a = back_candidate(
|
||||
let backed_a = block_on(back_candidate(
|
||||
candidate_a,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let backed_b = back_candidate(
|
||||
let backed_b = block_on(back_candidate(
|
||||
candidate_b,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(1)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
// out-of-order manifests as unscheduled.
|
||||
assert_eq!(
|
||||
@@ -1394,13 +1426,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Lacking,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1429,13 +1462,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1463,13 +1497,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(2)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1504,13 +1539,14 @@ mod tests {
|
||||
// change the candidate after signing.
|
||||
candidate.descriptor.pov_hash = Hash::from([2; 32]);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(2)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1537,13 +1573,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let candidate = TestCandidateBuilder::default().build();
|
||||
<PendingAvailability<Test>>::insert(&chain_a, CandidatePendingAvailability {
|
||||
@@ -1586,13 +1623,14 @@ mod tests {
|
||||
// this is not supposed to happen
|
||||
<PendingAvailabilityCommitments>::insert(&chain_a, candidate.commitments.clone());
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1622,13 +1660,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
Paras::schedule_code_upgrade(
|
||||
chain_a,
|
||||
@@ -1663,13 +1702,14 @@ mod tests {
|
||||
&mut candidate,
|
||||
);
|
||||
|
||||
let backed = back_candidate(
|
||||
let backed = block_on(back_candidate(
|
||||
candidate,
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
@@ -1697,6 +1737,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
@@ -1776,29 +1820,32 @@ mod tests {
|
||||
&mut candidate_c,
|
||||
);
|
||||
|
||||
let backed_a = back_candidate(
|
||||
let backed_a = block_on(back_candidate(
|
||||
candidate_a.clone(),
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let backed_b = back_candidate(
|
||||
let backed_b = block_on(back_candidate(
|
||||
candidate_b.clone(),
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(1)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let backed_c = back_candidate(
|
||||
let backed_c = block_on(back_candidate(
|
||||
candidate_c.clone(),
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(2)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let occupied_cores = Inclusion::process_candidates(
|
||||
vec![backed_a, backed_b, backed_c],
|
||||
@@ -1871,6 +1918,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
@@ -1909,13 +1960,14 @@ mod tests {
|
||||
&mut candidate_a,
|
||||
);
|
||||
|
||||
let backed_a = back_candidate(
|
||||
let backed_a = block_on(back_candidate(
|
||||
candidate_a.clone(),
|
||||
&validators,
|
||||
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||
&keystore,
|
||||
&signing_context,
|
||||
BackingKind::Threshold,
|
||||
);
|
||||
));
|
||||
|
||||
let occupied_cores = Inclusion::process_candidates(
|
||||
vec![backed_a],
|
||||
@@ -1958,6 +2010,10 @@ mod tests {
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Ferdie,
|
||||
];
|
||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||
for validator in validators.iter() {
|
||||
SyncCryptoStore::sr25519_generate_new(&*keystore, PARACHAIN_KEY_TYPE_ID, Some(&validator.to_seed())).unwrap();
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
|
||||
Reference in New Issue
Block a user