Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
2 changes: 2 additions & 0 deletions core/offchain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ futures-timer = "0.4.0"
hyper = "0.12.35"
hyper-tls = "0.3.2"
log = "0.4.8"
threadpool = "1.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest version is 1.7, can you update the numbers here?

num_cpus = "1.6"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
num_cpus = "1.6"
num_cpus = "1.10"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" }
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
parking_lot = "0.9.0"
Expand Down
247 changes: 124 additions & 123 deletions core/offchain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,20 @@

#![warn(missing_docs)]

use std::{
fmt,
marker::PhantomData,
sync::Arc,
};
extern crate num_cpus;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use edition = 2018, this is not needed.

Suggested change
extern crate num_cpus;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not be needed in 2018 edition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry I don't understand what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of extern crate xxx should not be needed anymore.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, just remove that line, fix the tests and we are good to go.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are build results below the comments section on github:
https://gitlab.parity.io/parity/substrate/-/jobs/249361

Actually it's not a test failing, but you need to run cargo check locally and commit changes in Cargo.lock file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have committed the change of Cargo.lock . But there is a trouble, when I run 'cargo check' in the path ' ~/substrate/ ' , it shows that futures-io-preview can't compile.

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:292:28
|
292 | -> Poll<Result<&[u8]>>;
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
|
559 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
571 | deref_async_buf_read!();
| ------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:559:32
|
559 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
575 | deref_async_buf_read!();
| ------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:584:28
|
584 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of cx's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
|
597 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
609 | delegate_async_buf_read_to_stdio!();
| ------------------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error[E0106]: missing lifetime specifier
--> /Users/ChenXinRan/.cargo/registry/src/code.aliyun.com-738b7dba08a2a41e/futures-io-preview-0.3.0-alpha.19/src/lib.rs:597:32
|
597 | -> Poll<Result<&[u8]>>
| ^ expected lifetime parameter
...
613 | delegate_async_buf_read_to_stdio!();
| ------------------------------------ in this macro invocation
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 2's 2 lifetimes it is borrowed from

error: aborting due to 6 previous errors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But your code seem to be compiling well on the CI machine.. Make sure you have the latest version of rustc and stable/nightly toolchains installed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my rust version.

rustc 1.38.0-nightly (69656fa4c 2019-07-13)
rustc 1.40.0-nightly (ddf43867a 2019-09-26)
rustup 1.19.0 (2af131cf9 2019-09-08)

use std::{fmt, marker::PhantomData, sync::Arc};

use client::runtime_api::ApiExt;
use futures::future::Future;
use log::{debug, warn};
use network::NetworkStateInfo;
use primitives::{offchain, ExecutionContext};
use sr_primitives::{generic::BlockId, traits::{self, ProvideRuntimeApi}};
use transaction_pool::txpool::{Pool, ChainApi};
use sr_primitives::{
generic::BlockId,
traits::{self, ProvideRuntimeApi},
};
use threadpool::ThreadPool;
use transaction_pool::txpool::{ChainApi, Pool};

mod api;

Expand All @@ -55,132 +56,132 @@ pub use offchain_primitives::OffchainWorkerApi;

/// An offchain workers manager.
pub struct OffchainWorkers<Client, Storage, Block: traits::Block> {
client: Arc<Client>,
db: Storage,
_block: PhantomData<Block>,
client: Arc<Client>,
db: Storage,
_block: PhantomData<Block>,
thread_pool: ThreadPool,
}

impl<Client, Storage, Block: traits::Block> OffchainWorkers<Client, Storage, Block> {
/// Creates new `OffchainWorkers`.
pub fn new(client: Arc<Client>, db: Storage) -> Self {
Self {
client,
db,
_block: PhantomData,
}
}
/// Creates new `OffchainWorkers`.
pub fn new(client: Arc<Client>, db: Storage) -> Self {
Self {
client,
db,
_block: PhantomData,
thread_pool: ThreadPool::new(num_cpus::get()),
}
}
}

impl<Client, Storage, Block: traits::Block> fmt::Debug for OffchainWorkers<
Client,
Storage,
Block,
> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("OffchainWorkers").finish()
}
impl<Client, Storage, Block: traits::Block> fmt::Debug for OffchainWorkers<Client, Storage, Block> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("OffchainWorkers").finish()
}
}

impl<Client, Storage, Block> OffchainWorkers<
Client,
Storage,
Block,
> where
Block: traits::Block,
Client: ProvideRuntimeApi + Send + Sync + 'static,
Client::Api: OffchainWorkerApi<Block>,
Storage: client::backend::OffchainStorage + 'static,
impl<Client, Storage, Block> OffchainWorkers<Client, Storage, Block>
where
Block: traits::Block,
Client: ProvideRuntimeApi + Send + Sync + 'static,
Client::Api: OffchainWorkerApi<Block>,
Storage: client::backend::OffchainStorage + 'static,
{
/// Start the offchain workers after given block.
#[must_use]
pub fn on_block_imported<A>(
&self,
number: &<Block::Header as traits::Header>::Number,
pool: &Arc<Pool<A>>,
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
is_validator: bool,
) -> impl Future<Output = ()> where A: ChainApi<Block=Block> + 'static {
let runtime = self.client.runtime_api();
let at = BlockId::number(*number);
let has_api = runtime.has_api::<dyn OffchainWorkerApi<Block>>(&at);
debug!("Checking offchain workers at {:?}: {:?}", at, has_api);

if has_api.unwrap_or(false) {
let (api, runner) = api::AsyncApi::new(
pool.clone(),
self.db.clone(),
at.clone(),
network_state.clone(),
is_validator,
);
debug!("Spawning offchain workers at {:?}", at);
let number = *number;
let client = self.client.clone();
spawn_worker(move || {
let runtime = client.runtime_api();
let api = Box::new(api);
debug!("Running offchain workers at {:?}", at);
let run = runtime.offchain_worker_with_context(
&at,
ExecutionContext::OffchainCall(Some((api, offchain::Capabilities::all()))),
number,
);
if let Err(e) = run {
log::error!("Error running offchain workers at {:?}: {:?}", at, e);
}
});
futures::future::Either::Left(runner.process())
} else {
futures::future::Either::Right(futures::future::ready(()))
}
}
}

/// Spawns a new offchain worker.
///
/// We spawn offchain workers for each block in a separate thread,
/// since they can run for a significant amount of time
/// in a blocking fashion and we don't want to block the runtime.
///
/// Note that we should avoid that if we switch to future-based runtime in the future,
/// alternatively:
/// TODO [ToDr] (#1458) we can consider using a thread pool instead.
fn spawn_worker(f: impl FnOnce() -> () + Send + 'static) {
std::thread::spawn(f);
/// Start the offchain workers after given block.
#[must_use]
pub fn on_block_imported<A>(
&self,
number: &<Block::Header as traits::Header>::Number,
pool: &Arc<Pool<A>>,
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
is_validator: bool,
) -> impl Future<Output = ()>
where
A: ChainApi<Block = Block> + 'static,
{
let runtime = self.client.runtime_api();
let at = BlockId::number(*number);
let has_api = runtime.has_api::<dyn OffchainWorkerApi<Block>>(&at);
debug!("Checking offchain workers at {:?}: {:?}", at, has_api);

if has_api.unwrap_or(false) {
let (api, runner) = api::AsyncApi::new(
pool.clone(),
self.db.clone(),
at.clone(),
network_state.clone(),
is_validator,
);
debug!("Spawning offchain workers at {:?}", at);
let number = *number;
let client = self.client.clone();
self.spawn_worker(move || {
let runtime = client.runtime_api();
let api = Box::new(api);
debug!("Running offchain workers at {:?}", at);
let run = runtime.offchain_worker_with_context(
&at,
ExecutionContext::OffchainCall(Some((api, offchain::Capabilities::all()))),
number,
);
if let Err(e) = run {
log::error!("Error running offchain workers at {:?}: {:?}", at, e);
}
});
futures::future::Either::Left(runner.process())
} else {
futures::future::Either::Right(futures::future::ready(()))
}
}

/// Spawns a new offchain worker.
///
/// We spawn offchain workers for each block in a separate thread,
/// since they can run for a significant amount of time
/// in a blocking fashion and we don't want to block the runtime.
///
/// Note that we should avoid that if we switch to future-based runtime in the future,
/// alternatively:
fn spawn_worker(&self, f: impl FnOnce() -> () + Send + 'static) {
self.thread_pool.execute(f);
}
}

#[cfg(test)]
mod tests {
use super::*;
use network::{Multiaddr, PeerId};

struct MockNetworkStateInfo();

impl NetworkStateInfo for MockNetworkStateInfo {
fn external_addresses(&self) -> Vec<Multiaddr> {
Vec::new()
}

fn peer_id(&self) -> PeerId {
PeerId::random()
}
}

#[test]
fn should_call_into_runtime_and_produce_extrinsic() {
// given
let _ = env_logger::try_init();
let client = Arc::new(test_client::new());
let pool = Arc::new(Pool::new(Default::default(), transaction_pool::FullChainApi::new(client.clone())));
let db = client_db::offchain::LocalStorage::new_test();
let network_state = Arc::new(MockNetworkStateInfo());

// when
let offchain = OffchainWorkers::new(client, db);
futures::executor::block_on(offchain.on_block_imported(&0u64, &pool, network_state, false));

// then
assert_eq!(pool.status().ready, 1);
assert_eq!(pool.ready().next().unwrap().is_propagateable(), false);
}
use super::*;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use tabs in the codebase, please avoid reformattings.

use network::{Multiaddr, PeerId};

struct MockNetworkStateInfo();

impl NetworkStateInfo for MockNetworkStateInfo {
fn external_addresses(&self) -> Vec<Multiaddr> {
Vec::new()
}

fn peer_id(&self) -> PeerId {
PeerId::random()
}
}

#[test]
fn should_call_into_runtime_and_produce_extrinsic() {
// given
let _ = env_logger::try_init();
let client = Arc::new(test_client::new());
let pool = Arc::new(Pool::new(
Default::default(),
transaction_pool::FullChainApi::new(client.clone()),
));
let db = client_db::offchain::LocalStorage::new_test();
let network_state = Arc::new(MockNetworkStateInfo());

// when
let offchain = OffchainWorkers::new(client, db);
futures::executor::block_on(offchain.on_block_imported(&0u64, &pool, network_state, false));

// then
assert_eq!(pool.status().ready, 1);
assert_eq!(pool.ready().next().unwrap().is_propagateable(), false);
}
}