Check in block authoring that we can author with current authoring version (#4201)

* Check in block authoring that we can author with current authoring version

* Update client/consensus/pow/src/lib.rs

Co-Authored-By: André Silva <andre.beat@gmail.com>

* Fix compilation
This commit is contained in:
Bastian Köcher
2019-11-29 11:01:11 +01:00
committed by GitHub
parent 0b52f194f5
commit accc678640
18 changed files with 187 additions and 62 deletions
+1
View File
@@ -3177,6 +3177,7 @@ dependencies = [
"substrate-client 2.0.0", "substrate-client 2.0.0",
"substrate-consensus-aura 2.0.0", "substrate-consensus-aura 2.0.0",
"substrate-consensus-aura-primitives 2.0.0", "substrate-consensus-aura-primitives 2.0.0",
"substrate-consensus-common 2.0.0",
"substrate-executor 2.0.0", "substrate-executor 2.0.0",
"substrate-finality-grandpa 2.0.0", "substrate-finality-grandpa 2.0.0",
"substrate-finality-grandpa-primitives 2.0.0", "substrate-finality-grandpa-primitives 2.0.0",
+1
View File
@@ -29,6 +29,7 @@ txpool-api = { package = "sp-transaction-pool-api", path = "../../primitives/tra
network = { package = "substrate-network", path = "../../client/network" } network = { package = "substrate-network", path = "../../client/network" }
aura = { package = "substrate-consensus-aura", path = "../../client/consensus/aura" } aura = { package = "substrate-consensus-aura", path = "../../client/consensus/aura" }
aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../../primitives/consensus/aura" } aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../../primitives/consensus/aura" }
consensus-common = { package = "substrate-consensus-common", path = "../../primitives/consensus/common" }
grandpa = { package = "substrate-finality-grandpa", path = "../../client/finality-grandpa" } grandpa = { package = "substrate-finality-grandpa", path = "../../client/finality-grandpa" }
grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../../primitives/finality-grandpa" } grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../../primitives/finality-grandpa" }
substrate-client = { path = "../../client/" } substrate-client = { path = "../../client/" }
+5 -1
View File
@@ -111,7 +111,10 @@ pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisCon
let select_chain = service.select_chain() let select_chain = service.select_chain()
.ok_or(ServiceError::SelectChainRequired)?; .ok_or(ServiceError::SelectChainRequired)?;
let aura = aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>( let can_author_with =
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
let aura = aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>(
aura::SlotDuration::get_or_compute(&*client)?, aura::SlotDuration::get_or_compute(&*client)?,
client, client,
select_chain, select_chain,
@@ -121,6 +124,7 @@ pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisCon
inherent_data_providers.clone(), inherent_data_providers.clone(),
force_authoring, force_authoring,
service.keystore(), service.keystore(),
can_author_with,
)?; )?;
// the AURA authoring task is considered essential, i.e. if it // the AURA authoring task is considered essential, i.e. if it
+1 -1
View File
@@ -61,6 +61,7 @@ substrate-basic-authorship = { path = "../../../client/basic-authorship" }
substrate-service = { path = "../../../client/service", default-features = false } substrate-service = { path = "../../../client/service", default-features = false }
substrate-telemetry = { package = "substrate-telemetry", path = "../../../client/telemetry" } substrate-telemetry = { package = "substrate-telemetry", path = "../../../client/telemetry" }
authority-discovery = { package = "substrate-authority-discovery", path = "../../../client/authority-discovery"} authority-discovery = { package = "substrate-authority-discovery", path = "../../../client/authority-discovery"}
consensus-common = { package = "substrate-consensus-common", path = "../../../primitives/consensus/common" }
# frame dependencies # frame dependencies
indices = { package = "pallet-indices", path = "../../../frame/indices" } indices = { package = "pallet-indices", path = "../../../frame/indices" }
@@ -99,7 +100,6 @@ rand6 = { package = "rand", version = "0.6", features = ["wasm-bindgen"], option
[dev-dependencies] [dev-dependencies]
keystore = { package = "substrate-keystore", path = "../../../client/keystore" } keystore = { package = "substrate-keystore", path = "../../../client/keystore" }
babe = { package = "substrate-consensus-babe", path = "../../../client/consensus/babe", features = ["test-helpers"] } babe = { package = "substrate-consensus-babe", path = "../../../client/consensus/babe", features = ["test-helpers"] }
consensus-common = { package = "substrate-consensus-common", path = "../../../primitives/consensus/common" }
service-test = { package = "substrate-service-test", path = "../../../client/service/test" } service-test = { package = "substrate-service-test", path = "../../../client/service/test" }
futures = "0.3.1" futures = "0.3.1"
tempfile = "3.1.0" tempfile = "3.1.0"
+4
View File
@@ -169,6 +169,9 @@ macro_rules! new_full {
let select_chain = service.select_chain() let select_chain = service.select_chain()
.ok_or(substrate_service::Error::SelectChainRequired)?; .ok_or(substrate_service::Error::SelectChainRequired)?;
let can_author_with =
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
let babe_config = babe::BabeParams { let babe_config = babe::BabeParams {
keystore: service.keystore(), keystore: service.keystore(),
client, client,
@@ -179,6 +182,7 @@ macro_rules! new_full {
inherent_data_providers: inherent_data_providers.clone(), inherent_data_providers: inherent_data_providers.clone(),
force_authoring, force_authoring,
babe_link, babe_link,
can_author_with,
}; };
let babe = babe::start_babe(babe_config)?; let babe = babe::start_babe(babe_config)?;
+10 -6
View File
@@ -31,9 +31,9 @@
use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug, pin::Pin}; use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug, pin::Pin};
use codec::{Encode, Decode, Codec}; use codec::{Encode, Decode, Codec};
use consensus_common::{self, BlockImport, Environment, Proposer, use consensus_common::{
ForkChoiceStrategy, BlockImportParams, BlockOrigin, Error as ConsensusError, self, BlockImport, Environment, Proposer, CanAuthorWith, ForkChoiceStrategy, BlockImportParams,
SelectChain, BlockOrigin, Error as ConsensusError, SelectChain,
}; };
use consensus_common::import_queue::{ use consensus_common::import_queue::{
Verifier, BasicQueue, BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport, Verifier, BasicQueue, BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport,
@@ -143,7 +143,7 @@ impl SlotCompatible for AuraSlotCompatible {
} }
/// Start the aura worker. The returned future should be run in a futures executor. /// Start the aura worker. The returned future should be run in a futures executor.
pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>( pub fn start_aura<B, C, SC, E, I, P, SO, CAW, Error, H>(
slot_duration: SlotDuration, slot_duration: SlotDuration,
client: Arc<C>, client: Arc<C>,
select_chain: SC, select_chain: SC,
@@ -153,6 +153,7 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
inherent_data_providers: InherentDataProviders, inherent_data_providers: InherentDataProviders,
force_authoring: bool, force_authoring: bool,
keystore: KeyStorePtr, keystore: KeyStorePtr,
can_author_with: CAW,
) -> Result<impl futures01::Future<Item = (), Error = ()>, consensus_common::Error> where ) -> Result<impl futures01::Future<Item = (), Error = ()>, consensus_common::Error> where
B: BlockT<Header=H>, B: BlockT<Header=H>,
C: ProvideRuntimeApi + BlockOf + ProvideCache<B> + AuxStore + Send + Sync, C: ProvideRuntimeApi + BlockOf + ProvideCache<B> + AuxStore + Send + Sync,
@@ -168,6 +169,7 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
I: BlockImport<B> + Send + Sync + 'static, I: BlockImport<B> + Send + Sync + 'static,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static, Error: ::std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
SO: SyncOracle + Send + Sync + Clone, SO: SyncOracle + Send + Sync + Clone,
CAW: CanAuthorWith<B> + Send,
{ {
let worker = AuraWorker { let worker = AuraWorker {
client: client.clone(), client: client.clone(),
@@ -182,13 +184,14 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
&inherent_data_providers, &inherent_data_providers,
slot_duration.0.slot_duration() slot_duration.0.slot_duration()
)?; )?;
Ok(slots::start_slot_worker::<_, _, _, _, _, AuraSlotCompatible>( Ok(slots::start_slot_worker::<_, _, _, _, _, AuraSlotCompatible, _>(
slot_duration.0, slot_duration.0,
select_chain, select_chain,
worker, worker,
sync_oracle, sync_oracle,
inherent_data_providers, inherent_data_providers,
AuraSlotCompatible, AuraSlotCompatible,
can_author_with,
).map(|()| Ok::<(), ()>(())).compat()) ).map(|()| Ok::<(), ()>(())).compat())
} }
@@ -864,7 +867,7 @@ mod tests {
&inherent_data_providers, slot_duration.get() &inherent_data_providers, slot_duration.get()
).expect("Registers aura inherent data provider"); ).expect("Registers aura inherent data provider");
let aura = start_aura::<_, _, _, _, _, AuthorityPair, _, _, _>( let aura = start_aura::<_, _, _, _, _, AuthorityPair, _, _, _, _>(
slot_duration, slot_duration,
client.clone(), client.clone(),
select_chain, select_chain,
@@ -874,6 +877,7 @@ mod tests {
inherent_data_providers, inherent_data_providers,
false, false,
keystore, keystore,
consensus_common::AlwaysCanAuthor,
).expect("Starts aura"); ).expect("Starts aura");
runtime.spawn(aura); runtime.spawn(aura);
+10 -4
View File
@@ -65,7 +65,7 @@ pub use babe_primitives::{
pub use consensus_common::SyncOracle; pub use consensus_common::SyncOracle;
use std::{collections::HashMap, sync::Arc, u64, pin::Pin, time::{Instant, Duration}}; use std::{collections::HashMap, sync::Arc, u64, pin::Pin, time::{Instant, Duration}};
use babe_primitives; use babe_primitives;
use consensus_common::ImportResult; use consensus_common::{ImportResult, CanAuthorWith};
use consensus_common::import_queue::{ use consensus_common::import_queue::{
BoxJustificationImport, BoxFinalityProofImport, BoxJustificationImport, BoxFinalityProofImport,
}; };
@@ -241,7 +241,7 @@ impl std::ops::Deref for Config {
} }
/// Parameters for BABE. /// Parameters for BABE.
pub struct BabeParams<B: BlockT, C, E, I, SO, SC> { pub struct BabeParams<B: BlockT, C, E, I, SO, SC, CAW> {
/// The keystore that manages the keys of the node. /// The keystore that manages the keys of the node.
pub keystore: KeyStorePtr, pub keystore: KeyStorePtr,
@@ -270,10 +270,13 @@ pub struct BabeParams<B: BlockT, C, E, I, SO, SC> {
/// The source of timestamps for relative slots /// The source of timestamps for relative slots
pub babe_link: BabeLink<B>, pub babe_link: BabeLink<B>,
/// Checks if the current native implementation can author with a runtime at a given block.
pub can_author_with: CAW,
} }
/// Start the babe worker. The returned future should be run in a tokio runtime. /// Start the babe worker. The returned future should be run in a tokio runtime.
pub fn start_babe<B, C, SC, E, I, SO, Error>(BabeParams { pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
keystore, keystore,
client, client,
select_chain, select_chain,
@@ -283,7 +286,8 @@ pub fn start_babe<B, C, SC, E, I, SO, Error>(BabeParams {
inherent_data_providers, inherent_data_providers,
force_authoring, force_authoring,
babe_link, babe_link,
}: BabeParams<B, C, E, I, SO, SC>) -> Result< can_author_with,
}: BabeParams<B, C, E, I, SO, SC, CAW>) -> Result<
impl futures01::Future<Item=(), Error=()>, impl futures01::Future<Item=(), Error=()>,
consensus_common::Error, consensus_common::Error,
> where > where
@@ -298,6 +302,7 @@ pub fn start_babe<B, C, SC, E, I, SO, Error>(BabeParams {
I: BlockImport<B,Error=ConsensusError> + Send + Sync + 'static, I: BlockImport<B,Error=ConsensusError> + Send + Sync + 'static,
Error: std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static, Error: std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
SO: SyncOracle + Send + Sync + Clone, SO: SyncOracle + Send + Sync + Clone,
CAW: CanAuthorWith<B> + Send,
{ {
let config = babe_link.config; let config = babe_link.config;
let worker = BabeWorker { let worker = BabeWorker {
@@ -326,6 +331,7 @@ pub fn start_babe<B, C, SC, E, I, SO, Error>(BabeParams {
sync_oracle, sync_oracle,
inherent_data_providers, inherent_data_providers,
babe_link.time_source, babe_link.time_source,
can_author_with,
); );
Ok(slot_worker.map(|_| Ok::<(), ()>(())).compat()) Ok(slot_worker.map(|_| Ok::<(), ()>(())).compat())
@@ -404,6 +404,7 @@ fn run_one_test(
force_authoring: false, force_authoring: false,
babe_link: data.link.clone(), babe_link: data.link.clone(),
keystore, keystore,
can_author_with: consensus_common::AlwaysCanAuthor,
}).expect("Starts babe")); }).expect("Starts babe"));
} }
+20 -4
View File
@@ -44,7 +44,7 @@ use primitives::H256;
use inherents::{InherentDataProviders, InherentData}; use inherents::{InherentDataProviders, InherentData};
use consensus_common::{ use consensus_common::{
BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer,
SelectChain, Error as ConsensusError SelectChain, Error as ConsensusError, CanAuthorWith,
}; };
use consensus_common::import_queue::{BoxBlockImport, BasicQueue, Verifier}; use consensus_common::import_queue::{BoxBlockImport, BasicQueue, Verifier};
use codec::{Encode, Decode}; use codec::{Encode, Decode};
@@ -372,7 +372,7 @@ pub fn import_queue<B, C, S, Algorithm>(
/// information, or just be a graffiti. `round` is for number of rounds the /// information, or just be a graffiti. `round` is for number of rounds the
/// CPU miner runs each time. This parameter should be tweaked so that each /// CPU miner runs each time. This parameter should be tweaked so that each
/// mining round is within sub-second time. /// mining round is within sub-second time.
pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>( pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S, CAW>(
mut block_import: BoxBlockImport<B>, mut block_import: BoxBlockImport<B>,
client: Arc<C>, client: Arc<C>,
algorithm: Algorithm, algorithm: Algorithm,
@@ -383,6 +383,7 @@ pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
build_time: std::time::Duration, build_time: std::time::Duration,
select_chain: Option<S>, select_chain: Option<S>,
inherent_data_providers: inherents::InherentDataProviders, inherent_data_providers: inherents::InherentDataProviders,
can_author_with: CAW,
) where ) where
C: HeaderBackend<B> + AuxStore + 'static, C: HeaderBackend<B> + AuxStore + 'static,
Algorithm: PowAlgorithm<B> + Send + Sync + 'static, Algorithm: PowAlgorithm<B> + Send + Sync + 'static,
@@ -390,6 +391,7 @@ pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
E::Error: std::fmt::Debug, E::Error: std::fmt::Debug,
SO: SyncOracle + Send + Sync + 'static, SO: SyncOracle + Send + Sync + 'static,
S: SelectChain<B> + 'static, S: SelectChain<B> + 'static,
CAW: CanAuthorWith<B> + Send + 'static,
{ {
if let Err(_) = register_pow_inherent_data_provider(&inherent_data_providers) { if let Err(_) = register_pow_inherent_data_provider(&inherent_data_providers) {
warn!("Registering inherent data provider for timestamp failed"); warn!("Registering inherent data provider for timestamp failed");
@@ -407,7 +409,8 @@ pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
&mut sync_oracle, &mut sync_oracle,
build_time.clone(), build_time.clone(),
select_chain.as_ref(), select_chain.as_ref(),
&inherent_data_providers &inherent_data_providers,
&can_author_with,
) { ) {
Ok(()) => (), Ok(()) => (),
Err(e) => error!( Err(e) => error!(
@@ -420,7 +423,7 @@ pub fn start_mine<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
}); });
} }
fn mine_loop<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>( fn mine_loop<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S, CAW>(
block_import: &mut BoxBlockImport<B>, block_import: &mut BoxBlockImport<B>,
client: &C, client: &C,
algorithm: &Algorithm, algorithm: &Algorithm,
@@ -431,6 +434,7 @@ fn mine_loop<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
build_time: std::time::Duration, build_time: std::time::Duration,
select_chain: Option<&S>, select_chain: Option<&S>,
inherent_data_providers: &inherents::InherentDataProviders, inherent_data_providers: &inherents::InherentDataProviders,
can_author_with: &CAW,
) -> Result<(), Error<B>> where ) -> Result<(), Error<B>> where
C: HeaderBackend<B> + AuxStore, C: HeaderBackend<B> + AuxStore,
Algorithm: PowAlgorithm<B>, Algorithm: PowAlgorithm<B>,
@@ -438,6 +442,7 @@ fn mine_loop<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
E::Error: std::fmt::Debug, E::Error: std::fmt::Debug,
SO: SyncOracle, SO: SyncOracle,
S: SelectChain<B>, S: SelectChain<B>,
CAW: CanAuthorWith<B>,
{ {
'outer: loop { 'outer: loop {
if sync_oracle.is_major_syncing() { if sync_oracle.is_major_syncing() {
@@ -461,6 +466,17 @@ fn mine_loop<B: BlockT<Hash=H256>, C, Algorithm, E, SO, S>(
(hash, header) (hash, header)
}, },
}; };
if can_author_with.can_author_with(&BlockId::Hash(best_hash)) {
debug!(
target: "pow",
"Skipping proposal `can_author_with` returned `false`. \
Probably a node update is required!"
);
std::thread::sleep(std::time::Duration::from_secs(1));
continue 'outer
}
let mut aux = PowAux::read(client, &best_hash)?; let mut aux = PowAux::read(client, &best_hash)?;
let mut proposer = env.init(&best_header) let mut proposer = env.init(&best_header)
.map_err(|e| Error::Environment(format!("{:?}", e)))?; .map_err(|e| Error::Environment(format!("{:?}", e)))?;
+23 -9
View File
@@ -31,7 +31,7 @@ use slots::Slots;
pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use consensus_common::{BlockImport, Proposer, SyncOracle, SelectChain}; use consensus_common::{BlockImport, Proposer, SyncOracle, SelectChain, CanAuthorWith};
use futures::{prelude::*, future::{self, Either}}; use futures::{prelude::*, future::{self, Either}};
use futures_timer::Delay; use futures_timer::Delay;
use inherents::{InherentData, InherentDataProviders}; use inherents::{InherentData, InherentDataProviders};
@@ -304,22 +304,24 @@ pub trait SlotCompatible {
/// ///
/// Every time a new slot is triggered, `worker.on_slot` is called and the future it returns is /// Every time a new slot is triggered, `worker.on_slot` is called and the future it returns is
/// polled until completion, unless we are major syncing. /// polled until completion, unless we are major syncing.
pub fn start_slot_worker<B, C, W, T, SO, SC>( pub fn start_slot_worker<B, C, W, T, SO, SC, CAW>(
slot_duration: SlotDuration<T>, slot_duration: SlotDuration<T>,
client: C, client: C,
mut worker: W, mut worker: W,
mut sync_oracle: SO, mut sync_oracle: SO,
inherent_data_providers: InherentDataProviders, inherent_data_providers: InherentDataProviders,
timestamp_extractor: SC, timestamp_extractor: SC,
can_author_with: CAW,
) -> impl Future<Output = ()> ) -> impl Future<Output = ()>
where where
B: BlockT, B: BlockT,
C: SelectChain<B> + Clone, C: SelectChain<B>,
W: SlotWorker<B>, W: SlotWorker<B>,
W::OnSlot: Unpin, W::OnSlot: Unpin,
SO: SyncOracle + Send + Clone, SO: SyncOracle + Send,
SC: SlotCompatible + Unpin, SC: SlotCompatible + Unpin,
T: SlotData + Clone, T: SlotData + Clone,
CAW: CanAuthorWith<B> + Send,
{ {
let SlotDuration(slot_duration) = slot_duration; let SlotDuration(slot_duration) = slot_duration;
@@ -346,11 +348,23 @@ where
} }
}; };
Either::Left(worker.on_slot(chain_head, slot_info).map_err( if can_author_with.can_author_with(&BlockId::Hash(chain_head.hash())) {
|e| { Either::Left(
warn!(target: "slots", "Encountered consensus error: {:?}", e); worker.on_slot(chain_head, slot_info)
}).or_else(|_| future::ready(Ok(()))) .map_err(|e| {
) warn!(target: "slots", "Encountered consensus error: {:?}", e);
})
.or_else(|_| future::ready(Ok(())))
)
} else {
warn!(
target: "slots",
"Unable to author block in slot {}. `can_author_with` returned `false`. \
Probably a node update is required!",
slot_num,
);
Either::Right(future::ready(Ok(())))
}
}).then(|res| { }).then(|res| {
if let Err(err) = res { if let Err(err) = res {
warn!(target: "slots", "Slots stream terminated with an error: {:?}", err); warn!(target: "slots", "Slots stream terminated with an error: {:?}", err);
+1 -4
View File
@@ -87,10 +87,7 @@ pub trait RuntimeInfo {
fn native_version(&self) -> &NativeVersion; fn native_version(&self) -> &NativeVersion;
/// Extract RuntimeVersion of given :code block /// Extract RuntimeVersion of given :code block
fn runtime_version<E: Externalities> ( fn runtime_version<E: Externalities> (&self, ext: &mut E) -> error::Result<RuntimeVersion>;
&self,
ext: &mut E,
) -> Option<RuntimeVersion>;
} }
#[cfg(test)] #[cfg(test)]
@@ -25,7 +25,7 @@ use codec::{Decode, Encode};
use primitives::{NativeOrEncoded, traits::{CodeExecutor, Externalities}}; use primitives::{NativeOrEncoded, traits::{CodeExecutor, Externalities}};
use log::{trace, warn}; use log::trace;
use std::{result, cell::RefCell, panic::{UnwindSafe, AssertUnwindSafe}}; use std::{result, cell::RefCell, panic::{UnwindSafe, AssertUnwindSafe}};
@@ -181,14 +181,8 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
fn runtime_version<E: Externalities>( fn runtime_version<E: Externalities>(
&self, &self,
ext: &mut E, ext: &mut E,
) -> Option<RuntimeVersion> { ) -> Result<RuntimeVersion> {
match self.with_runtime(ext, |_runtime, version, _ext| Ok(Ok(version.clone()))) { self.with_runtime(ext, |_runtime, version, _ext| Ok(Ok(version.clone())))
Ok(version) => Some(version),
Err(e) => {
warn!(target: "executor", "Failed to fetch runtime: {:?}", e);
None
}
}
} }
} }
@@ -547,7 +547,8 @@ fn runtime_version<Block: BlockT, F: Fetcher<Block>>(
Bytes(Vec::new()), Bytes(Vec::new()),
) )
.then(|version| ready(version.and_then(|version| .then(|version| ready(version.and_then(|version|
Decode::decode(&mut &version.0[..]).map_err(|_| client_err(ClientError::VersionInvalid)) Decode::decode(&mut &version.0[..])
.map_err(|e| client_err(ClientError::VersionInvalid(e.what().into())))
))) )))
} }
@@ -696,7 +697,7 @@ fn ignore_error<F, T>(future: F) -> impl std::future::Future<Output=Result<Optio
future.then(|result| ready(match result { future.then(|result| ready(match result {
Ok(result) => Ok(Some(result)), Ok(result) => Ok(Some(result)),
Err(()) => Ok(None), Err(()) => Ok(None),
})) }))
} }
#[cfg(test)] #[cfg(test)]
+23 -5
View File
@@ -63,10 +63,10 @@ impl<B, E> Clone for LocalCallExecutor<B, E> where E: Clone {
} }
impl<B, E, Block> CallExecutor<Block, Blake2Hasher> for LocalCallExecutor<B, E> impl<B, E, Block> CallExecutor<Block, Blake2Hasher> for LocalCallExecutor<B, E>
where where
B: backend::Backend<Block, Blake2Hasher>, B: backend::Backend<Block, Blake2Hasher>,
E: CodeExecutor + RuntimeInfo, E: CodeExecutor + RuntimeInfo,
Block: BlockT<Hash=H256>, Block: BlockT<Hash=H256>,
{ {
type Error = E::Error; type Error = E::Error;
@@ -202,7 +202,7 @@ where
let _lock = self.backend.get_import_lock().read(); let _lock = self.backend.get_import_lock().read();
self.backend.destroy_state(state)?; self.backend.destroy_state(state)?;
} }
version.ok_or(sp_blockchain::Error::VersionInvalid.into()) version.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into())
} }
fn call_at_state< fn call_at_state<
@@ -268,3 +268,21 @@ where
Some(self.executor.native_version()) Some(self.executor.native_version())
} }
} }
impl<B, E, Block> runtime_version::GetRuntimeVersion<Block> for LocalCallExecutor<B, E>
where
B: backend::Backend<Block, Blake2Hasher>,
E: CodeExecutor + RuntimeInfo,
Block: BlockT<Hash=H256>,
{
fn native_version(&self) -> &runtime_version::NativeVersion {
self.executor.native_version()
}
fn runtime_version(
&self,
at: &BlockId<Block>,
) -> Result<runtime_version::RuntimeVersion, String> {
CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e))
}
}
+4 -3
View File
@@ -1753,9 +1753,10 @@ where
} }
impl<BE, E, B, RA> consensus::block_validation::Chain<B> for Client<BE, E, B, RA> impl<BE, E, B, RA> consensus::block_validation::Chain<B> for Client<BE, E, B, RA>
where BE: backend::Backend<B, Blake2Hasher>, where
E: CallExecutor<B, Blake2Hasher>, BE: backend::Backend<B, Blake2Hasher>,
B: BlockT<Hash = H256> E: CallExecutor<B, Blake2Hasher>,
B: BlockT<Hash = H256>
{ {
fn block_status(&self, id: &BlockId<B>) -> Result<BlockStatus, Box<dyn std::error::Error + Send>> { fn block_status(&self, id: &BlockId<B>) -> Result<BlockStatus, Box<dyn std::error::Error + Send>> {
Client::block_status(self, id).map_err(|e| Box::new(e) as Box<_>) Client::block_status(self, id).map_err(|e| Box::new(e) as Box<_>)
+3 -10
View File
@@ -28,7 +28,6 @@ use parity_scale_codec::Error as CodecError;
/// Client Result type alias /// Client Result type alias
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
/// Error when the runtime failed to apply an extrinsic. /// Error when the runtime failed to apply an extrinsic.
#[derive(Debug, Display)] #[derive(Debug, Display)]
pub enum ApplyExtrinsicFailed { pub enum ApplyExtrinsicFailed {
@@ -72,8 +71,9 @@ pub enum Error {
#[display(fmt = "Current state of blockchain has invalid authorities set")] #[display(fmt = "Current state of blockchain has invalid authorities set")]
InvalidAuthoritiesSet, InvalidAuthoritiesSet,
/// Could not get runtime version. /// Could not get runtime version.
#[display(fmt = "On-chain runtime does not specify version")] #[display(fmt = "Failed to get runtime version: {}", _0)]
VersionInvalid, #[from(ignore)]
VersionInvalid(String),
/// Genesis config is invalid. /// Genesis config is invalid.
#[display(fmt = "Genesis config provided is invalid")] #[display(fmt = "Genesis config provided is invalid")]
GenesisInvalid, GenesisInvalid,
@@ -125,7 +125,6 @@ pub enum Error {
InvalidStateRoot, InvalidStateRoot,
/// A convenience variant for String /// A convenience variant for String
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
#[from(ignore)]
Msg(String), Msg(String),
} }
@@ -139,12 +138,6 @@ impl error::Error for Error {
} }
} }
impl From<String> for Error {
fn from(s: String) -> Self {
Error::Msg(s)
}
}
impl<'a> From<&'a str> for Error { impl<'a> From<&'a str> for Error {
fn from(s: &'a str) -> Self { fn from(s: &'a str) -> Self {
Error::Msg(s.into()) Error::Msg(s.into())
@@ -31,7 +31,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use sr_primitives::traits::{Block as BlockT, DigestFor}; use sr_primitives::{traits::{Block as BlockT, DigestFor}, generic::BlockId};
use futures::prelude::*; use futures::prelude::*;
pub use inherents::InherentData; pub use inherents::InherentData;
@@ -123,13 +123,59 @@ impl SyncOracle for NoNetwork {
fn is_offline(&mut self) -> bool { false } fn is_offline(&mut self) -> bool { false }
} }
impl<T> SyncOracle for Arc<T> impl<T> SyncOracle for Arc<T> where T: ?Sized, for<'r> &'r T: SyncOracle {
where T: ?Sized, for<'r> &'r T: SyncOracle
{
fn is_major_syncing(&mut self) -> bool { fn is_major_syncing(&mut self) -> bool {
<&T>::is_major_syncing(&mut &**self) <&T>::is_major_syncing(&mut &**self)
} }
fn is_offline(&mut self) -> bool { fn is_offline(&mut self) -> bool {
<&T>::is_offline(&mut &**self) <&T>::is_offline(&mut &**self)
} }
} }
/// Checks if the current active native block authoring implementation can author with the runtime
/// at the given block.
pub trait CanAuthorWith<Block: BlockT> {
/// See trait docs for more information.
fn can_author_with(&self, at: &BlockId<Block>) -> bool;
}
/// Checks if the node can author blocks by using
/// [`NativeVersion::can_author_with`](runtime_version::NativeVersion::can_author_with).
pub struct CanAuthorWithNativeVersion<T>(T);
impl<T> CanAuthorWithNativeVersion<T> {
/// Creates a new instance of `Self`.
pub fn new(inner: T) -> Self {
Self(inner)
}
}
impl<T: runtime_version::GetRuntimeVersion<Block>, Block: BlockT> CanAuthorWith<Block>
for CanAuthorWithNativeVersion<T>
{
fn can_author_with(&self, at: &BlockId<Block>) -> bool {
match self.0.runtime_version(at) {
Ok(version) => self.0.native_version().can_author_with(&version),
Err(e) => {
error!(
target: "CanAuthorWithNativeVersion",
"Failed to get runtime version at `{}` and will disable authoring. Error: {}",
at,
e,
);
false
}
}
}
}
/// Returns always `true` for `can_author_with`. This is useful for tests.
pub struct AlwaysCanAuthor;
impl<Block: BlockT> CanAuthorWith<Block> for AlwaysCanAuthor {
fn can_author_with(&self, _: &BlockId<Block>) -> bool {
true
}
}
@@ -33,6 +33,9 @@ use codec::Decode;
use sr_primitives::RuntimeString; use sr_primitives::RuntimeString;
pub use sr_primitives::create_runtime_str; pub use sr_primitives::create_runtime_str;
#[cfg(feature = "std")]
use sr_primitives::{traits::Block as BlockT, generic::BlockId};
/// The identity of a particular API interface that the runtime might provide. /// The identity of a particular API interface that the runtime might provide.
pub type ApiId = [u8; 8]; pub type ApiId = [u8; 8];
@@ -165,6 +168,27 @@ impl NativeVersion {
} }
} }
/// Something that can provide the runtime version at a given block and the native runtime version.
#[cfg(feature = "std")]
pub trait GetRuntimeVersion<Block: BlockT> {
/// Returns the version of the native runtime.
fn native_version(&self) -> &NativeVersion;
/// Returns the version of runtime at the given block.
fn runtime_version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, String>;
}
#[cfg(feature = "std")]
impl<T: GetRuntimeVersion<Block>, Block: BlockT> GetRuntimeVersion<Block> for std::sync::Arc<T> {
fn native_version(&self) -> &NativeVersion {
(&**self).native_version()
}
fn runtime_version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, String> {
(&**self).runtime_version(at)
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
mod apis_serialize { mod apis_serialize {
use super::*; use super::*;