diff --git a/substrate/core/cli/src/lib.rs b/substrate/core/cli/src/lib.rs index 7dc9519fa8..297896bf83 100644 --- a/substrate/core/cli/src/lib.rs +++ b/substrate/core/cli/src/lib.rs @@ -436,6 +436,8 @@ where ), }; + let is_dev = cli.shared_params.dev; + let role = if cli.light { service::Roles::LIGHT } else { @@ -462,8 +464,6 @@ where config.roles = role; config.disable_grandpa = cli.no_grandpa; - let is_dev = cli.shared_params.dev; - let client_id = config.client_id(); fill_network_configuration( cli.network_config, diff --git a/substrate/core/executor/src/error.rs b/substrate/core/executor/src/error.rs index 7b8926d8e9..9bfa05ff5f 100644 --- a/substrate/core/executor/src/error.rs +++ b/substrate/core/executor/src/error.rs @@ -38,8 +38,8 @@ pub enum Error { #[display(fmt="Method not found: '{}'", _0)] MethodNotFound(String), /// Code is invalid (expected single byte) - #[display(fmt="Invalid Code")] - InvalidCode, + #[display(fmt="Invalid Code: {}", _0)] + InvalidCode(String), /// Could not get runtime version. #[display(fmt="On-chain runtime does not specify version")] VersionInvalid, diff --git a/substrate/core/executor/src/native_executor.rs b/substrate/core/executor/src/native_executor.rs index 765b9f076e..937e003353 100644 --- a/substrate/core/executor/src/native_executor.rs +++ b/substrate/core/executor/src/native_executor.rs @@ -22,7 +22,7 @@ use runtime_version::{NativeVersion, RuntimeVersion}; use codec::{Decode, Encode}; use crate::RuntimeInfo; use primitives::{Blake2Hasher, NativeOrEncoded}; -use log::trace; +use log::{trace, warn}; use crate::RuntimesCache; @@ -107,8 +107,14 @@ impl RuntimeInfo for NativeExecutor { ) -> Option { RUNTIMES_CACHE.with(|cache| { let cache = &mut cache.borrow_mut(); - cache.fetch_runtime(&self.fallback, ext, self.default_heap_pages) - .ok()?.version().clone() + + match cache.fetch_runtime(&self.fallback, ext, self.default_heap_pages) { + Ok(runtime) => runtime.version(), + Err(e) => { + warn!(target: "executor", "Failed to fetch runtime: {:?}", e); + None + } + } }) } } diff --git a/substrate/core/executor/src/wasm_executor.rs b/substrate/core/executor/src/wasm_executor.rs index 73ee2c40d7..185aaba513 100644 --- a/substrate/core/executor/src/wasm_executor.rs +++ b/substrate/core/executor/src/wasm_executor.rs @@ -876,6 +876,13 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(0) }, + ext_is_validator() -> u32 => { + Ok(if runtime_io::is_validator() { + 1 + } else { + 0 + }) + }, ext_submit_transaction(msg_data: *const u8, len: u32) -> u32 => { let extrinsic = this.memory.get(msg_data, len as usize) .map_err(|_| "OOB while ext_submit_transaction: wasm")?; diff --git a/substrate/core/executor/src/wasm_runtimes_cache.rs b/substrate/core/executor/src/wasm_runtimes_cache.rs index 812638126d..110a28fe7d 100644 --- a/substrate/core/executor/src/wasm_runtimes_cache.rs +++ b/substrate/core/executor/src/wasm_runtimes_cache.rs @@ -248,12 +248,12 @@ impl RuntimesCache { ) -> Result, Error> { let code_hash = ext .original_storage_hash(well_known_keys::CODE) - .ok_or(Error::InvalidCode)?; + .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?; // This is direct result from fighting with borrowck. let handle_result = |cached_result: &Result, CacheError>| match *cached_result { - Err(_) => Err(Error::InvalidCode), + Err(ref e) => Err(Error::InvalidCode(format!("{:?}", e))), Ok(ref cached_runtime) => Ok(Rc::clone(cached_runtime)), }; diff --git a/substrate/core/offchain/src/api.rs b/substrate/core/offchain/src/api.rs index 468e98a566..225e7c3f72 100644 --- a/substrate/core/offchain/src/api.rs +++ b/substrate/core/offchain/src/api.rs @@ -47,11 +47,15 @@ pub(crate) struct Api { db: Storage, network_state: Arc, _at: BlockId, + /// Is this node a potential validator? + is_validator: bool, } fn unavailable_yet(name: &str) -> R { - error!("The {:?} API is not available for offchain workers yet. Follow \ - https://github.com/paritytech/substrate/issues/1458 for details", name); + error!( + "The {:?} API is not available for offchain workers yet. Follow \ + https://github.com/paritytech/substrate/issues/1458 for details", name + ); Default::default() } @@ -63,6 +67,10 @@ where Storage: OffchainStorage, Block: traits::Block, { + fn is_validator(&self) -> bool { + self.is_validator + } + fn submit_transaction(&mut self, ext: Vec) -> Result<(), ()> { self.sender .unbounded_send(ExtMessage::SubmitExtrinsic(ext)) @@ -277,6 +285,7 @@ impl AsyncApi { db: S, at: BlockId, network_state: Arc, + is_validator: bool, ) -> (Api, AsyncApi) { let (sender, rx) = mpsc::unbounded(); @@ -285,6 +294,7 @@ impl AsyncApi { db, network_state, _at: at, + is_validator, }; let async_api = AsyncApi { @@ -362,6 +372,7 @@ mod tests { db, BlockId::Number(Zero::zero()), mock, + false, ) } diff --git a/substrate/core/offchain/src/lib.rs b/substrate/core/offchain/src/lib.rs index 075a2bd837..b38b202c62 100644 --- a/substrate/core/offchain/src/lib.rs +++ b/substrate/core/offchain/src/lib.rs @@ -98,9 +98,8 @@ impl OffchainWorkers< number: &::Number, pool: &Arc>, network_state: Arc, - ) -> impl Future where - A: ChainApi + 'static, - { + is_validator: bool, + ) -> impl Future where A: ChainApi + 'static { let runtime = self.client.runtime_api(); let at = BlockId::number(*number); let has_api = runtime.has_api::>(&at); @@ -112,6 +111,7 @@ impl OffchainWorkers< self.db.clone(), at.clone(), network_state.clone(), + is_validator, ); debug!("Spawning offchain workers at {:?}", at); let number = *number; @@ -177,7 +177,7 @@ mod tests { // when let offchain = OffchainWorkers::new(client, db); - futures::executor::block_on(offchain.on_block_imported(&0u64, &pool, network_state)); + futures::executor::block_on(offchain.on_block_imported(&0u64, &pool, network_state, false)); // then assert_eq!(pool.status().ready, 1); diff --git a/substrate/core/offchain/src/testing.rs b/substrate/core/offchain/src/testing.rs index e01e4f5f59..cdf2878c13 100644 --- a/substrate/core/offchain/src/testing.rs +++ b/substrate/core/offchain/src/testing.rs @@ -134,6 +134,10 @@ impl TestOffchainExt { } impl offchain::Externalities for TestOffchainExt { + fn is_validator(&self) -> bool { + unimplemented!("not needed in tests so far") + } + fn submit_transaction(&mut self, _ex: Vec) -> Result<(), ()> { unimplemented!("not needed in tests so far") } diff --git a/substrate/core/primitives/src/offchain.rs b/substrate/core/primitives/src/offchain.rs index 8ce5863e01..52dbf5fbee 100644 --- a/substrate/core/primitives/src/offchain.rs +++ b/substrate/core/primitives/src/offchain.rs @@ -232,6 +232,11 @@ impl Timestamp { /// An extended externalities for offchain workers. pub trait Externalities { + /// Returns if the local node is a potential validator. + /// + /// Even if this function returns `true`, it does not mean that any keys are configured + /// and that the validator is registered in the chain. + fn is_validator(&self) -> bool; /// Submit transaction. /// /// The transaction will end up in the pool and be propagated to others. @@ -349,6 +354,10 @@ pub trait Externalities { } impl Externalities for Box { + fn is_validator(&self) -> bool { + (& **self).is_validator() + } + fn submit_transaction(&mut self, ex: Vec) -> Result<(), ()> { (&mut **self).submit_transaction(ex) } diff --git a/substrate/core/service/src/components.rs b/substrate/core/service/src/components.rs index fb869df020..76387e6c88 100644 --- a/substrate/core/service/src/components.rs +++ b/substrate/core/service/src/components.rs @@ -268,6 +268,7 @@ pub trait OffchainWorker { >, pool: &Arc>, network_state: &Arc, + is_validator: bool, ) -> error::Result + Send>>; } @@ -284,8 +285,9 @@ impl OffchainWorker for C where >, pool: &Arc>, network_state: &Arc, + is_validator: bool, ) -> error::Result + Send>> { - let future = offchain.on_block_imported(number, pool, network_state.clone()) + let future = offchain.on_block_imported(number, pool, network_state.clone(), is_validator) .map(|()| Ok(())); Ok(Box::new(Compat::new(future))) } diff --git a/substrate/core/service/src/lib.rs b/substrate/core/service/src/lib.rs index 2940bde7cf..3b2d73c124 100644 --- a/substrate/core/service/src/lib.rs +++ b/substrate/core/service/src/lib.rs @@ -153,7 +153,7 @@ impl Service { pub fn new( mut config: FactoryFullConfiguration, ) -> Result { - let (signal, exit) = ::exit_future::signal(); + let (signal, exit) = exit_future::signal(); // List of asynchronous tasks to spawn. We collect them, then spawn them all at once. let (to_spawn_tx, to_spawn_rx) = @@ -250,6 +250,7 @@ impl Service { let offchain = offchain_workers.as_ref().map(Arc::downgrade); let to_spawn_tx_ = to_spawn_tx.clone(); let network_state_info: Arc = network.clone(); + let is_validator = config.roles.is_authority(); let events = client.import_notification_stream() .map(|v| Ok::<_, ()>(v)).compat() @@ -270,6 +271,7 @@ impl Service { &offchain, &txpool, &network_state_info, + is_validator, ).map_err(|e| warn!("Offchain workers error processing new block: {:?}", e))?; let _ = to_spawn_tx_.unbounded_send(future); } diff --git a/substrate/core/sr-io/src/lib.rs b/substrate/core/sr-io/src/lib.rs index cafdf8066e..425d9a714c 100644 --- a/substrate/core/sr-io/src/lib.rs +++ b/substrate/core/sr-io/src/lib.rs @@ -273,6 +273,11 @@ export_api! { export_api! { pub(crate) trait OffchainApi { + /// Returns if the local node is a potential validator. + /// + /// Even if this function returns `true`, it does not mean that any keys are configured + /// and that the validator is registered in the chain. + fn is_validator() -> bool; /// Submit transaction to the pool. /// /// The transaction will end up in the pool. diff --git a/substrate/core/sr-io/with_std.rs b/substrate/core/sr-io/with_std.rs index b1e55634fc..ec9d8f06f0 100644 --- a/substrate/core/sr-io/with_std.rs +++ b/substrate/core/sr-io/with_std.rs @@ -336,6 +336,12 @@ fn with_offchain(f: impl FnOnce(&mut dyn offchain::Externalities) -> R, msg: } impl OffchainApi for () { + fn is_validator() -> bool { + with_offchain(|ext| { + ext.is_validator() + }, "is_validator can be called only in the offchain worker context") + } + fn submit_transaction(data: &T) -> Result<(), ()> { with_offchain(|ext| { ext.submit_transaction(codec::Encode::encode(data)) diff --git a/substrate/core/sr-io/without_std.rs b/substrate/core/sr-io/without_std.rs index 7d26d3d23b..118a91819a 100644 --- a/substrate/core/sr-io/without_std.rs +++ b/substrate/core/sr-io/without_std.rs @@ -432,6 +432,12 @@ pub mod ext { // Offchain-worker Context //================================ + /// Returns if the local node is a potential validator. + /// + /// - `1` == `true` + /// - `0` == `false` + fn ext_is_validator() -> u32; + /// Submit transaction. /// /// # Returns @@ -964,6 +970,10 @@ impl CryptoApi for () { } impl OffchainApi for () { + fn is_validator() -> bool { + unsafe { ext_is_validator.get()() == 1 } + } + fn submit_transaction(data: &T) -> Result<(), ()> { let encoded_data = codec::Encode::encode(data); let ret = unsafe { diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index bd46e0935b..8c2046e591 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -263,6 +263,10 @@ impl NeverOffchainExt { } impl offchain::Externalities for NeverOffchainExt { + fn is_validator(&self) -> bool { + unreachable!() + } + fn submit_transaction(&mut self, _extrinsic: Vec) -> Result<(), ()> { unreachable!() } diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs index 554d3a16b6..813d23393b 100644 --- a/substrate/node/cli/src/service.rs +++ b/substrate/node/cli/src/service.rs @@ -138,15 +138,15 @@ construct_service_factory! { let select = babe.select(service.on_exit()).then(|_| Ok(())); service.spawn_task(Box::new(select)); - let config = grandpa::Config { - // FIXME #1578 make this available through chainspec - gossip_duration: Duration::from_millis(333), - justification_period: 4096, - name: Some(service.config().name.clone()), - keystore: Some(service.keystore()), - }; - if !service.config().disable_grandpa { + let config = grandpa::Config { + // FIXME #1578 make this available through chainspec + gossip_duration: Duration::from_millis(333), + justification_period: 4096, + name: Some(service.config().name.clone()), + keystore: Some(service.keystore()), + }; + if service.config().roles.is_authority() { let telemetry_on_connect = TelemetryOnConnect { telemetry_connection_sinks: service.telemetry_on_connect_stream(), diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 653c0858ff..8b6b4d55bd 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -80,8 +80,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 136, - impl_version: 136, + spec_version: 137, + impl_version: 137, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/im-online/src/lib.rs b/substrate/srml/im-online/src/lib.rs index 23345ea974..eff811d6ca 100644 --- a/substrate/srml/im-online/src/lib.rs +++ b/substrate/srml/im-online/src/lib.rs @@ -219,7 +219,10 @@ decl_module! { // Runs after every block. fn offchain_worker(now: T::BlockNumber) { - Self::offchain(now); + // Only send messages if we are a potential validator. + if sr_io::is_validator() { + Self::offchain(now); + } } } }