mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 00:01:09 +00:00
Run cargo fmt on the whole code base (#9394)
* Run cargo fmt on the whole code base * Second run * Add CI check * Fix compilation * More unnecessary braces * Handle weights * Use --all * Use correct attributes... * Fix UI tests * AHHHHHHHHH * 🤦 * Docs * Fix compilation * 🤷 * Please stop * 🤦 x 2 * More * make rustfmt.toml consistent with polkadot Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
@@ -16,25 +16,21 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
convert::TryFrom,
|
||||
thread::sleep,
|
||||
collections::HashSet,
|
||||
};
|
||||
use std::{collections::HashSet, convert::TryFrom, str::FromStr, sync::Arc, thread::sleep};
|
||||
|
||||
use crate::NetworkProvider;
|
||||
use codec::{Decode, Encode};
|
||||
use futures::Future;
|
||||
use sc_network::{PeerId, Multiaddr};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_core::OpaquePeerId;
|
||||
use sp_core::offchain::{
|
||||
self, HttpRequestId, Timestamp, HttpRequestStatus, HttpError,
|
||||
OffchainStorage, OpaqueNetworkState, OpaqueMultiaddr, StorageKind,
|
||||
pub use http::SharedClient;
|
||||
use sc_network::{Multiaddr, PeerId};
|
||||
use sp_core::{
|
||||
offchain::{
|
||||
self, HttpError, HttpRequestId, HttpRequestStatus, OffchainStorage, OpaqueMultiaddr,
|
||||
OpaqueNetworkState, StorageKind, Timestamp,
|
||||
},
|
||||
OpaquePeerId,
|
||||
};
|
||||
pub use sp_offchain::STORAGE_PREFIX;
|
||||
pub use http::SharedClient;
|
||||
|
||||
#[cfg(not(target_os = "unknown"))]
|
||||
mod http;
|
||||
@@ -71,16 +67,15 @@ impl<Storage: OffchainStorage> Db<Storage> {
|
||||
}
|
||||
|
||||
/// Create new instance of Offchain DB, backed by given backend.
|
||||
pub fn factory_from_backend<Backend, Block>(backend: &Backend) -> Option<
|
||||
Box<dyn sc_client_api::execution_extensions::DbExternalitiesFactory>
|
||||
> where
|
||||
pub fn factory_from_backend<Backend, Block>(
|
||||
backend: &Backend,
|
||||
) -> Option<Box<dyn sc_client_api::execution_extensions::DbExternalitiesFactory>>
|
||||
where
|
||||
Backend: sc_client_api::Backend<Block, OffchainStorage = Storage>,
|
||||
Block: sp_runtime::traits::Block,
|
||||
Storage: 'static,
|
||||
{
|
||||
sc_client_api::Backend::offchain_storage(backend).map(|db|
|
||||
Box::new(Self::new(db)) as _
|
||||
)
|
||||
sc_client_api::Backend::offchain_storage(backend).map(|db| Box::new(Self::new(db)) as _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +118,8 @@ impl<Storage: OffchainStorage> offchain::DbExternalities for Db<Storage> {
|
||||
old_value.as_ref().map(hex::encode),
|
||||
);
|
||||
match kind {
|
||||
StorageKind::PERSISTENT => {
|
||||
self.persistent.compare_and_set(STORAGE_PREFIX, key, old_value, new_value)
|
||||
},
|
||||
StorageKind::PERSISTENT =>
|
||||
self.persistent.compare_and_set(STORAGE_PREFIX, key, old_value, new_value),
|
||||
StorageKind::LOCAL => unavailable_yet(LOCAL_DB),
|
||||
}
|
||||
}
|
||||
@@ -167,10 +161,7 @@ impl offchain::Externalities for Api {
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
let external_addresses = self.network_provider.external_addresses();
|
||||
|
||||
let state = NetworkState::new(
|
||||
self.network_provider.local_peer_id(),
|
||||
external_addresses,
|
||||
);
|
||||
let state = NetworkState::new(self.network_provider.local_peer_id(), external_addresses);
|
||||
Ok(OpaqueNetworkState::from(state))
|
||||
}
|
||||
|
||||
@@ -190,7 +181,7 @@ impl offchain::Externalities for Api {
|
||||
&mut self,
|
||||
method: &str,
|
||||
uri: &str,
|
||||
_meta: &[u8]
|
||||
_meta: &[u8],
|
||||
) -> Result<HttpRequestId, ()> {
|
||||
self.http.request_start(method, uri)
|
||||
}
|
||||
@@ -199,7 +190,7 @@ impl offchain::Externalities for Api {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
name: &str,
|
||||
value: &str
|
||||
value: &str,
|
||||
) -> Result<(), ()> {
|
||||
self.http.request_add_header(request_id, name, value)
|
||||
}
|
||||
@@ -208,7 +199,7 @@ impl offchain::Externalities for Api {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
chunk: &[u8],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Result<(), HttpError> {
|
||||
self.http.request_write_body(request_id, chunk, deadline)
|
||||
}
|
||||
@@ -216,15 +207,12 @@ impl offchain::Externalities for Api {
|
||||
fn http_response_wait(
|
||||
&mut self,
|
||||
ids: &[HttpRequestId],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Vec<HttpRequestStatus> {
|
||||
self.http.response_wait(ids, deadline)
|
||||
}
|
||||
|
||||
fn http_response_headers(
|
||||
&mut self,
|
||||
request_id: HttpRequestId
|
||||
) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
self.http.response_headers(request_id)
|
||||
}
|
||||
|
||||
@@ -232,15 +220,14 @@ impl offchain::Externalities for Api {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Result<usize, HttpError> {
|
||||
self.http.response_read_body(request_id, buffer, deadline)
|
||||
}
|
||||
|
||||
fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool) {
|
||||
let peer_ids: HashSet<PeerId> = nodes.into_iter()
|
||||
.filter_map(|node| PeerId::from_bytes(&node.0).ok())
|
||||
.collect();
|
||||
let peer_ids: HashSet<PeerId> =
|
||||
nodes.into_iter().filter_map(|node| PeerId::from_bytes(&node.0).ok()).collect();
|
||||
|
||||
self.network_provider.set_authorized_peers(peer_ids);
|
||||
self.network_provider.set_authorized_only(authorized_only);
|
||||
@@ -256,10 +243,7 @@ pub struct NetworkState {
|
||||
|
||||
impl NetworkState {
|
||||
fn new(peer_id: PeerId, external_addresses: Vec<Multiaddr>) -> Self {
|
||||
NetworkState {
|
||||
peer_id,
|
||||
external_addresses,
|
||||
}
|
||||
NetworkState { peer_id, external_addresses }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,10 +261,7 @@ impl From<NetworkState> for OpaqueNetworkState {
|
||||
})
|
||||
.collect();
|
||||
|
||||
OpaqueNetworkState {
|
||||
peer_id,
|
||||
external_addresses,
|
||||
}
|
||||
OpaqueNetworkState { peer_id, external_addresses }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +274,8 @@ impl TryFrom<OpaqueNetworkState> for NetworkState {
|
||||
let bytes: Vec<u8> = Decode::decode(&mut &inner_vec[..]).map_err(|_| ())?;
|
||||
let peer_id = PeerId::from_bytes(&bytes).map_err(|_| ())?;
|
||||
|
||||
let external_addresses: Result<Vec<Multiaddr>, Self::Error> = state.external_addresses
|
||||
let external_addresses: Result<Vec<Multiaddr>, Self::Error> = state
|
||||
.external_addresses
|
||||
.iter()
|
||||
.map(|enc_multiaddr| -> Result<Multiaddr, Self::Error> {
|
||||
let inner_vec = &enc_multiaddr.0;
|
||||
@@ -305,10 +287,7 @@ impl TryFrom<OpaqueNetworkState> for NetworkState {
|
||||
.collect();
|
||||
let external_addresses = external_addresses?;
|
||||
|
||||
Ok(NetworkState {
|
||||
peer_id,
|
||||
external_addresses,
|
||||
})
|
||||
Ok(NetworkState { peer_id, external_addresses })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,15 +308,9 @@ impl AsyncApi {
|
||||
) -> (Api, Self) {
|
||||
let (http_api, http_worker) = http::http(shared_client);
|
||||
|
||||
let api = Api {
|
||||
network_provider,
|
||||
is_validator,
|
||||
http: http_api,
|
||||
};
|
||||
let api = Api { network_provider, is_validator, http: http_api };
|
||||
|
||||
let async_api = Self {
|
||||
http: Some(http_worker),
|
||||
};
|
||||
let async_api = Self { http: Some(http_worker) };
|
||||
|
||||
(api, async_api)
|
||||
}
|
||||
@@ -355,8 +328,11 @@ mod tests {
|
||||
use super::*;
|
||||
use sc_client_db::offchain::LocalStorage;
|
||||
use sc_network::{NetworkStateInfo, PeerId};
|
||||
use sp_core::offchain::{Externalities, DbExternalities};
|
||||
use std::{convert::{TryFrom, TryInto}, time::SystemTime};
|
||||
use sp_core::offchain::{DbExternalities, Externalities};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
struct TestNetwork();
|
||||
|
||||
@@ -385,11 +361,7 @@ mod tests {
|
||||
let mock = Arc::new(TestNetwork());
|
||||
let shared_client = SharedClient::new();
|
||||
|
||||
AsyncApi::new(
|
||||
mock,
|
||||
false,
|
||||
shared_client,
|
||||
)
|
||||
AsyncApi::new(mock, false, shared_client)
|
||||
}
|
||||
|
||||
fn offchain_db() -> Db<LocalStorage> {
|
||||
@@ -402,7 +374,12 @@ mod tests {
|
||||
|
||||
// Get timestamp from std.
|
||||
let now = SystemTime::now();
|
||||
let d: u64 = now.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis().try_into().unwrap();
|
||||
let d: u64 = now
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
// Get timestamp from offchain api.
|
||||
let timestamp = api.timestamp();
|
||||
|
||||
@@ -28,16 +28,22 @@
|
||||
//! actively calling any function.
|
||||
|
||||
use crate::api::timestamp;
|
||||
use bytes::buf::ext::{Reader, BufExt};
|
||||
use bytes::buf::ext::{BufExt, Reader};
|
||||
use fnv::FnvHashMap;
|
||||
use futures::{prelude::*, future, channel::mpsc};
|
||||
use log::error;
|
||||
use sp_core::offchain::{HttpRequestId, Timestamp, HttpRequestStatus, HttpError};
|
||||
use std::{convert::TryFrom, fmt, io::Read as _, pin::Pin, task::{Context, Poll}};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender, TracingUnboundedReceiver};
|
||||
use std::sync::Arc;
|
||||
use hyper::{Client as HyperClient, Body, client};
|
||||
use futures::{channel::mpsc, future, prelude::*};
|
||||
use hyper::{client, Body, Client as HyperClient};
|
||||
use hyper_rustls::HttpsConnector;
|
||||
use log::error;
|
||||
use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
fmt,
|
||||
io::Read as _,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
/// Wrapper struct used for keeping the hyper_rustls client running.
|
||||
#[derive(Clone)]
|
||||
@@ -63,12 +69,8 @@ pub fn http(shared_client: SharedClient) -> (HttpApi, HttpWorker) {
|
||||
requests: FnvHashMap::default(),
|
||||
};
|
||||
|
||||
let engine = HttpWorker {
|
||||
to_api,
|
||||
from_api,
|
||||
http_client: shared_client.0,
|
||||
requests: Vec::new(),
|
||||
};
|
||||
let engine =
|
||||
HttpWorker { to_api, from_api, http_client: shared_client.0, requests: Vec::new() };
|
||||
|
||||
(api, engine)
|
||||
}
|
||||
@@ -127,11 +129,7 @@ struct HttpApiRequestRp {
|
||||
|
||||
impl HttpApi {
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn request_start(
|
||||
&mut self,
|
||||
method: &str,
|
||||
uri: &str
|
||||
) -> Result<HttpRequestId, ()> {
|
||||
pub fn request_start(&mut self, method: &str, uri: &str) -> Result<HttpRequestId, ()> {
|
||||
// Start by building the prototype of the request.
|
||||
// We do this first so that we don't touch anything in `self` if building the prototype
|
||||
// fails.
|
||||
@@ -146,10 +144,11 @@ impl HttpApi {
|
||||
Some(new_id) => self.next_id.0 = new_id,
|
||||
None => {
|
||||
error!("Overflow in offchain worker HTTP request ID assignment");
|
||||
return Err(());
|
||||
}
|
||||
return Err(())
|
||||
},
|
||||
};
|
||||
self.requests.insert(new_id, HttpApiRequest::NotDispatched(request, body_sender));
|
||||
self.requests
|
||||
.insert(new_id, HttpApiRequest::NotDispatched(request, body_sender));
|
||||
|
||||
Ok(new_id)
|
||||
}
|
||||
@@ -159,11 +158,11 @@ impl HttpApi {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
name: &str,
|
||||
value: &str
|
||||
value: &str,
|
||||
) -> Result<(), ()> {
|
||||
let request = match self.requests.get_mut(&request_id) {
|
||||
Some(&mut HttpApiRequest::NotDispatched(ref mut rq, _)) => rq,
|
||||
_ => return Err(())
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
let name = hyper::header::HeaderName::try_from(name).map_err(drop)?;
|
||||
@@ -179,7 +178,7 @@ impl HttpApi {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
chunk: &[u8],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Result<(), HttpError> {
|
||||
// Extract the request from the list.
|
||||
// Don't forget to add it back if necessary when returning.
|
||||
@@ -193,76 +192,83 @@ impl HttpApi {
|
||||
let mut when_ready = future::maybe_done(future::poll_fn(|cx| sender.poll_ready(cx)));
|
||||
futures::executor::block_on(future::select(&mut when_ready, &mut deadline));
|
||||
match when_ready {
|
||||
future::MaybeDone::Done(Ok(())) => {}
|
||||
future::MaybeDone::Done(Ok(())) => {},
|
||||
future::MaybeDone::Done(Err(_)) => return Err(HttpError::IoError),
|
||||
future::MaybeDone::Future(_) |
|
||||
future::MaybeDone::Gone => {
|
||||
future::MaybeDone::Future(_) | future::MaybeDone::Gone => {
|
||||
debug_assert!(matches!(deadline, future::MaybeDone::Done(..)));
|
||||
return Err(HttpError::DeadlineReached)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
futures::executor::block_on(sender.send_data(hyper::body::Bytes::from(chunk.to_owned())))
|
||||
.map_err(|_| {
|
||||
error!("HTTP sender refused data despite being ready");
|
||||
HttpError::IoError
|
||||
})
|
||||
futures::executor::block_on(
|
||||
sender.send_data(hyper::body::Bytes::from(chunk.to_owned())),
|
||||
)
|
||||
.map_err(|_| {
|
||||
error!("HTTP sender refused data despite being ready");
|
||||
HttpError::IoError
|
||||
})
|
||||
};
|
||||
|
||||
loop {
|
||||
request = match request {
|
||||
HttpApiRequest::NotDispatched(request, sender) => {
|
||||
// If the request is not dispatched yet, dispatch it and loop again.
|
||||
let _ = self.to_worker.unbounded_send(ApiToWorker::Dispatch {
|
||||
id: request_id,
|
||||
request
|
||||
});
|
||||
let _ = self
|
||||
.to_worker
|
||||
.unbounded_send(ApiToWorker::Dispatch { id: request_id, request });
|
||||
HttpApiRequest::Dispatched(Some(sender))
|
||||
}
|
||||
},
|
||||
|
||||
HttpApiRequest::Dispatched(Some(mut sender)) =>
|
||||
if !chunk.is_empty() {
|
||||
match poll_sender(&mut sender) {
|
||||
Err(HttpError::IoError) => return Err(HttpError::IoError),
|
||||
other => {
|
||||
self.requests.insert(
|
||||
request_id,
|
||||
HttpApiRequest::Dispatched(Some(sender))
|
||||
);
|
||||
self.requests
|
||||
.insert(request_id, HttpApiRequest::Dispatched(Some(sender)));
|
||||
return other
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Writing an empty body is a hint that we should stop writing. Dropping
|
||||
// the sender.
|
||||
self.requests.insert(request_id, HttpApiRequest::Dispatched(None));
|
||||
return Ok(())
|
||||
}
|
||||
},
|
||||
|
||||
HttpApiRequest::Response(mut response @ HttpApiRequestRp { sending_body: Some(_), .. }) =>
|
||||
HttpApiRequest::Response(
|
||||
mut response @ HttpApiRequestRp { sending_body: Some(_), .. },
|
||||
) =>
|
||||
if !chunk.is_empty() {
|
||||
match poll_sender(response.sending_body.as_mut()
|
||||
.expect("Can only enter this match branch if Some; qed")) {
|
||||
match poll_sender(
|
||||
response
|
||||
.sending_body
|
||||
.as_mut()
|
||||
.expect("Can only enter this match branch if Some; qed"),
|
||||
) {
|
||||
Err(HttpError::IoError) => return Err(HttpError::IoError),
|
||||
other => {
|
||||
self.requests.insert(request_id, HttpApiRequest::Response(response));
|
||||
self.requests
|
||||
.insert(request_id, HttpApiRequest::Response(response));
|
||||
return other
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
} else {
|
||||
// Writing an empty body is a hint that we should stop writing. Dropping
|
||||
// the sender.
|
||||
self.requests.insert(request_id, HttpApiRequest::Response(HttpApiRequestRp {
|
||||
sending_body: None,
|
||||
..response
|
||||
}));
|
||||
self.requests.insert(
|
||||
request_id,
|
||||
HttpApiRequest::Response(HttpApiRequestRp {
|
||||
sending_body: None,
|
||||
..response
|
||||
}),
|
||||
);
|
||||
return Ok(())
|
||||
}
|
||||
},
|
||||
|
||||
HttpApiRequest::Fail(_) =>
|
||||
// If the request has already failed, return without putting back the request
|
||||
// in the list.
|
||||
// If the request has already failed, return without putting back the request
|
||||
// in the list.
|
||||
return Err(HttpError::IoError),
|
||||
|
||||
v @ HttpApiRequest::Dispatched(None) |
|
||||
@@ -270,7 +276,7 @@ impl HttpApi {
|
||||
// We have already finished sending this body.
|
||||
self.requests.insert(request_id, v);
|
||||
return Err(HttpError::Invalid)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,30 +285,27 @@ impl HttpApi {
|
||||
pub fn response_wait(
|
||||
&mut self,
|
||||
ids: &[HttpRequestId],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Vec<HttpRequestStatus> {
|
||||
// First of all, dispatch all the non-dispatched requests and drop all senders so that the
|
||||
// user can't write anymore data.
|
||||
for id in ids {
|
||||
match self.requests.get_mut(id) {
|
||||
Some(HttpApiRequest::NotDispatched(_, _)) => {}
|
||||
Some(HttpApiRequest::NotDispatched(_, _)) => {},
|
||||
Some(HttpApiRequest::Dispatched(sending_body)) |
|
||||
Some(HttpApiRequest::Response(HttpApiRequestRp { sending_body, .. })) => {
|
||||
let _ = sending_body.take();
|
||||
continue
|
||||
}
|
||||
_ => continue
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let (request, _sender) = match self.requests.remove(id) {
|
||||
Some(HttpApiRequest::NotDispatched(rq, s)) => (rq, s),
|
||||
_ => unreachable!("we checked for NotDispatched above; qed")
|
||||
_ => unreachable!("we checked for NotDispatched above; qed"),
|
||||
};
|
||||
|
||||
let _ = self.to_worker.unbounded_send(ApiToWorker::Dispatch {
|
||||
id: *id,
|
||||
request
|
||||
});
|
||||
let _ = self.to_worker.unbounded_send(ApiToWorker::Dispatch { id: *id, request });
|
||||
|
||||
// We also destroy the sender in order to forbid writing more data.
|
||||
self.requests.insert(*id, HttpApiRequest::Dispatched(None));
|
||||
@@ -319,25 +322,24 @@ impl HttpApi {
|
||||
for id in ids {
|
||||
output.push(match self.requests.get(id) {
|
||||
None => HttpRequestStatus::Invalid,
|
||||
Some(HttpApiRequest::NotDispatched(_, _)) =>
|
||||
unreachable!("we replaced all the NotDispatched with Dispatched earlier; qed"),
|
||||
Some(HttpApiRequest::NotDispatched(_, _)) => unreachable!(
|
||||
"we replaced all the NotDispatched with Dispatched earlier; qed"
|
||||
),
|
||||
Some(HttpApiRequest::Dispatched(_)) => {
|
||||
must_wait_more = true;
|
||||
HttpRequestStatus::DeadlineReached
|
||||
},
|
||||
Some(HttpApiRequest::Fail(_)) => HttpRequestStatus::IoError,
|
||||
Some(HttpApiRequest::Response(HttpApiRequestRp { status_code, .. })) =>
|
||||
HttpRequestStatus::Finished(status_code.as_u16()),
|
||||
Some(HttpApiRequest::Response(HttpApiRequestRp {
|
||||
status_code, ..
|
||||
})) => HttpRequestStatus::Finished(status_code.as_u16()),
|
||||
});
|
||||
}
|
||||
debug_assert_eq!(output.len(), ids.len());
|
||||
|
||||
// Are we ready to call `return`?
|
||||
let is_done = if let future::MaybeDone::Done(_) = deadline {
|
||||
true
|
||||
} else {
|
||||
!must_wait_more
|
||||
};
|
||||
let is_done =
|
||||
if let future::MaybeDone::Done(_) = deadline { true } else { !must_wait_more };
|
||||
|
||||
if is_done {
|
||||
// Requests in "fail" mode are purged before returning.
|
||||
@@ -369,47 +371,45 @@ impl HttpApi {
|
||||
Some(WorkerToApi::Response { id, status_code, headers, body }) =>
|
||||
match self.requests.remove(&id) {
|
||||
Some(HttpApiRequest::Dispatched(sending_body)) => {
|
||||
self.requests.insert(id, HttpApiRequest::Response(HttpApiRequestRp {
|
||||
sending_body,
|
||||
status_code,
|
||||
headers,
|
||||
body: body.fuse(),
|
||||
current_read_chunk: None,
|
||||
}));
|
||||
}
|
||||
None => {} // can happen if we detected an IO error when sending the body
|
||||
self.requests.insert(
|
||||
id,
|
||||
HttpApiRequest::Response(HttpApiRequestRp {
|
||||
sending_body,
|
||||
status_code,
|
||||
headers,
|
||||
body: body.fuse(),
|
||||
current_read_chunk: None,
|
||||
}),
|
||||
);
|
||||
},
|
||||
None => {}, // can happen if we detected an IO error when sending the body
|
||||
_ => error!("State mismatch between the API and worker"),
|
||||
}
|
||||
},
|
||||
|
||||
Some(WorkerToApi::Fail { id, error }) =>
|
||||
match self.requests.remove(&id) {
|
||||
Some(HttpApiRequest::Dispatched(_)) => {
|
||||
self.requests.insert(id, HttpApiRequest::Fail(error));
|
||||
}
|
||||
None => {} // can happen if we detected an IO error when sending the body
|
||||
_ => error!("State mismatch between the API and worker"),
|
||||
}
|
||||
Some(WorkerToApi::Fail { id, error }) => match self.requests.remove(&id) {
|
||||
Some(HttpApiRequest::Dispatched(_)) => {
|
||||
self.requests.insert(id, HttpApiRequest::Fail(error));
|
||||
},
|
||||
None => {}, // can happen if we detected an IO error when sending the body
|
||||
_ => error!("State mismatch between the API and worker"),
|
||||
},
|
||||
|
||||
None => {
|
||||
error!("Worker has crashed");
|
||||
return ids.iter().map(|_| HttpRequestStatus::IoError).collect()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn response_headers(
|
||||
&mut self,
|
||||
request_id: HttpRequestId
|
||||
) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
pub fn response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
// Do an implicit non-blocking wait on the request.
|
||||
let _ = self.response_wait(&[request_id], Some(timestamp::now()));
|
||||
|
||||
let headers = match self.requests.get(&request_id) {
|
||||
Some(HttpApiRequest::Response(HttpApiRequestRp { headers, .. })) => headers,
|
||||
_ => return Vec::new()
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
headers
|
||||
@@ -423,7 +423,7 @@ impl HttpApi {
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
deadline: Option<Timestamp>,
|
||||
) -> Result<usize, HttpError> {
|
||||
// Do an implicit wait on the request.
|
||||
let _ = self.response_wait(&[request_id], deadline);
|
||||
@@ -439,14 +439,13 @@ impl HttpApi {
|
||||
return Err(HttpError::DeadlineReached)
|
||||
},
|
||||
// The request has failed.
|
||||
Some(HttpApiRequest::Fail { .. }) =>
|
||||
return Err(HttpError::IoError),
|
||||
Some(HttpApiRequest::Fail { .. }) => return Err(HttpError::IoError),
|
||||
// Request hasn't been dispatched yet; reading the body is invalid.
|
||||
Some(rq @ HttpApiRequest::NotDispatched(_, _)) => {
|
||||
self.requests.insert(request_id, rq);
|
||||
return Err(HttpError::Invalid)
|
||||
}
|
||||
None => return Err(HttpError::Invalid)
|
||||
},
|
||||
None => return Err(HttpError::Invalid),
|
||||
};
|
||||
|
||||
// Convert the deadline into a `Future` that resolves when the deadline is reached.
|
||||
@@ -456,19 +455,22 @@ impl HttpApi {
|
||||
// First read from `current_read_chunk`.
|
||||
if let Some(mut current_read_chunk) = response.current_read_chunk.take() {
|
||||
match current_read_chunk.read(buffer) {
|
||||
Ok(0) => {}
|
||||
Ok(0) => {},
|
||||
Ok(n) => {
|
||||
self.requests.insert(request_id, HttpApiRequest::Response(HttpApiRequestRp {
|
||||
current_read_chunk: Some(current_read_chunk),
|
||||
.. response
|
||||
}));
|
||||
self.requests.insert(
|
||||
request_id,
|
||||
HttpApiRequest::Response(HttpApiRequestRp {
|
||||
current_read_chunk: Some(current_read_chunk),
|
||||
..response
|
||||
}),
|
||||
);
|
||||
return Ok(n)
|
||||
},
|
||||
Err(err) => {
|
||||
// This code should never be reached unless there's a logic error somewhere.
|
||||
error!("Failed to read from current read chunk: {:?}", err);
|
||||
return Err(HttpError::IoError)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +484,7 @@ impl HttpApi {
|
||||
match next_body {
|
||||
Some(Ok(chunk)) => response.current_read_chunk = Some(chunk.reader()),
|
||||
Some(Err(_)) => return Err(HttpError::IoError),
|
||||
None => return Ok(0), // eof
|
||||
None => return Ok(0), // eof
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,9 +498,7 @@ impl HttpApi {
|
||||
|
||||
impl fmt::Debug for HttpApi {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(self.requests.iter())
|
||||
.finish()
|
||||
f.debug_list().entries(self.requests.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,12 +507,13 @@ impl fmt::Debug for HttpApiRequest {
|
||||
match self {
|
||||
HttpApiRequest::NotDispatched(_, _) =>
|
||||
f.debug_tuple("HttpApiRequest::NotDispatched").finish(),
|
||||
HttpApiRequest::Dispatched(_) =>
|
||||
f.debug_tuple("HttpApiRequest::Dispatched").finish(),
|
||||
HttpApiRequest::Response(HttpApiRequestRp { status_code, headers, .. }) =>
|
||||
f.debug_tuple("HttpApiRequest::Response").field(status_code).field(headers).finish(),
|
||||
HttpApiRequest::Fail(err) =>
|
||||
f.debug_tuple("HttpApiRequest::Fail").field(err).finish(),
|
||||
HttpApiRequest::Dispatched(_) => f.debug_tuple("HttpApiRequest::Dispatched").finish(),
|
||||
HttpApiRequest::Response(HttpApiRequestRp { status_code, headers, .. }) => f
|
||||
.debug_tuple("HttpApiRequest::Response")
|
||||
.field(status_code)
|
||||
.field(headers)
|
||||
.finish(),
|
||||
HttpApiRequest::Fail(err) => f.debug_tuple("HttpApiRequest::Fail").field(err).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -525,7 +526,7 @@ enum ApiToWorker {
|
||||
id: HttpRequestId,
|
||||
/// Request to start executing.
|
||||
request: hyper::Request<hyper::Body>,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/// Message send from the API to the worker.
|
||||
@@ -605,8 +606,8 @@ impl Future for HttpWorker {
|
||||
Poll::Ready(Ok(response)) => response,
|
||||
Poll::Ready(Err(error)) => {
|
||||
let _ = me.to_api.unbounded_send(WorkerToApi::Fail { id, error });
|
||||
continue; // don't insert the request back
|
||||
}
|
||||
continue // don't insert the request back
|
||||
},
|
||||
};
|
||||
|
||||
// We received a response! Decompose it into its parts.
|
||||
@@ -622,20 +623,20 @@ impl Future for HttpWorker {
|
||||
});
|
||||
|
||||
me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx: body_tx }));
|
||||
cx.waker().wake_by_ref(); // reschedule in order to poll the new future
|
||||
cx.waker().wake_by_ref(); // reschedule in order to poll the new future
|
||||
continue
|
||||
}
|
||||
},
|
||||
|
||||
HttpWorkerRequest::ReadBody { mut body, mut tx } => {
|
||||
// Before reading from the HTTP response, check that `tx` is ready to accept
|
||||
// a new chunk.
|
||||
match tx.poll_ready(cx) {
|
||||
Poll::Ready(Ok(())) => {}
|
||||
Poll::Ready(Err(_)) => continue, // don't insert the request back
|
||||
Poll::Ready(Ok(())) => {},
|
||||
Poll::Ready(Err(_)) => continue, // don't insert the request back
|
||||
Poll::Pending => {
|
||||
me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx }));
|
||||
continue
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// `tx` is ready. Read a chunk from the socket and send it to the channel.
|
||||
@@ -643,31 +644,31 @@ impl Future for HttpWorker {
|
||||
Poll::Ready(Some(Ok(chunk))) => {
|
||||
let _ = tx.start_send(Ok(chunk));
|
||||
me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx }));
|
||||
cx.waker().wake_by_ref(); // reschedule in order to continue reading
|
||||
}
|
||||
cx.waker().wake_by_ref(); // reschedule in order to continue reading
|
||||
},
|
||||
Poll::Ready(Some(Err(err))) => {
|
||||
let _ = tx.start_send(Err(err));
|
||||
// don't insert the request back
|
||||
},
|
||||
Poll::Ready(None) => {} // EOF; don't insert the request back
|
||||
Poll::Ready(None) => {}, // EOF; don't insert the request back
|
||||
Poll::Pending => {
|
||||
me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx }));
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Check for messages coming from the [`HttpApi`].
|
||||
match Stream::poll_next(Pin::new(&mut me.from_api), cx) {
|
||||
Poll::Pending => {},
|
||||
Poll::Ready(None) => return Poll::Ready(()), // stops the worker
|
||||
Poll::Ready(None) => return Poll::Ready(()), // stops the worker
|
||||
Poll::Ready(Some(ApiToWorker::Dispatch { id, request })) => {
|
||||
let future = me.http_client.request(request);
|
||||
debug_assert!(me.requests.iter().all(|(i, _)| *i != id));
|
||||
me.requests.push((id, HttpWorkerRequest::Dispatched(future)));
|
||||
cx.waker().wake_by_ref(); // reschedule the task to poll the request
|
||||
}
|
||||
cx.waker().wake_by_ref(); // reschedule the task to poll the request
|
||||
},
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
@@ -676,9 +677,7 @@ impl Future for HttpWorker {
|
||||
|
||||
impl fmt::Debug for HttpWorker {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(self.requests.iter())
|
||||
.finish()
|
||||
f.debug_list().entries(self.requests.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,13 +694,13 @@ impl fmt::Debug for HttpWorkerRequest {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::convert::Infallible;
|
||||
use crate::api::timestamp;
|
||||
use super::{http, SharedClient};
|
||||
use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Duration};
|
||||
use crate::api::timestamp;
|
||||
use core::convert::Infallible;
|
||||
use futures::future;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use sp_core::offchain::{Duration, HttpError, HttpRequestId, HttpRequestStatus};
|
||||
|
||||
// Using lazy_static to avoid spawning lots of different SharedClients,
|
||||
// as spawning a SharedClient is CPU-intensive and opens lots of fds.
|
||||
lazy_static! {
|
||||
@@ -720,14 +719,17 @@ mod tests {
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let worker = rt.spawn(worker);
|
||||
let server = rt.spawn(async move {
|
||||
let server = hyper::Server::bind(&"127.0.0.1:0".parse().unwrap())
|
||||
.serve(hyper::service::make_service_fn(|_| { async move {
|
||||
Ok::<_, Infallible>(hyper::service::service_fn(move |_req| async move {
|
||||
Ok::<_, Infallible>(
|
||||
hyper::Response::new(hyper::Body::from("Hello World!"))
|
||||
)
|
||||
}))
|
||||
}}));
|
||||
let server = hyper::Server::bind(&"127.0.0.1:0".parse().unwrap()).serve(
|
||||
hyper::service::make_service_fn(|_| async move {
|
||||
Ok::<_, Infallible>(hyper::service::service_fn(
|
||||
move |_req| async move {
|
||||
Ok::<_, Infallible>(hyper::Response::new(hyper::Body::from(
|
||||
"Hello World!",
|
||||
)))
|
||||
},
|
||||
))
|
||||
}),
|
||||
);
|
||||
let _ = addr_tx.send(server.local_addr());
|
||||
server.await.map_err(drop)
|
||||
});
|
||||
@@ -750,7 +752,7 @@ mod tests {
|
||||
|
||||
match api.response_wait(&[id], Some(deadline))[0] {
|
||||
HttpRequestStatus::Finished(200) => {},
|
||||
v => panic!("Connecting to localhost failed: {:?}", v)
|
||||
v => panic!("Connecting to localhost failed: {:?}", v),
|
||||
}
|
||||
|
||||
let headers = api.response_headers(id);
|
||||
@@ -766,13 +768,13 @@ mod tests {
|
||||
let (mut api, addr) = build_api_server!();
|
||||
|
||||
match api.request_start("\0", &format!("http://{}", addr)) {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
match api.request_start("GET", "http://\0localhost") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -781,42 +783,42 @@ mod tests {
|
||||
let (mut api, addr) = build_api_server!();
|
||||
|
||||
match api.request_add_header(HttpRequestId(0xdead), "Foo", "bar") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("GET", &format!("http://{}", addr)).unwrap();
|
||||
match api.request_add_header(id, "\0", "bar") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
match api.request_add_header(id, "Foo", "\0") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.request_add_header(id, "Foo", "Bar").unwrap();
|
||||
api.request_write_body(id, &[1, 2, 3, 4], None).unwrap();
|
||||
match api.request_add_header(id, "Foo2", "Bar") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("GET", &format!("http://{}", addr)).unwrap();
|
||||
api.response_headers(id);
|
||||
match api.request_add_header(id, "Foo2", "Bar") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("GET", &format!("http://{}", addr)).unwrap();
|
||||
api.response_read_body(id, &mut [], None).unwrap();
|
||||
match api.request_add_header(id, "Foo2", "Bar") {
|
||||
Err(()) => {}
|
||||
Ok(_) => panic!()
|
||||
Err(()) => {},
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -825,13 +827,13 @@ mod tests {
|
||||
let (mut api, addr) = build_api_server!();
|
||||
|
||||
match api.request_write_body(HttpRequestId(0xdead), &[1, 2, 3], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
match api.request_write_body(HttpRequestId(0xdead), &[], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
@@ -839,8 +841,8 @@ mod tests {
|
||||
api.request_write_body(id, &[1, 2, 3, 4], None).unwrap();
|
||||
api.request_write_body(id, &[], None).unwrap();
|
||||
match api.request_write_body(id, &[], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
@@ -848,52 +850,52 @@ mod tests {
|
||||
api.request_write_body(id, &[1, 2, 3, 4], None).unwrap();
|
||||
api.request_write_body(id, &[], None).unwrap();
|
||||
match api.request_write_body(id, &[1, 2, 3, 4], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.request_write_body(id, &[1, 2, 3, 4], None).unwrap();
|
||||
api.response_wait(&[id], None);
|
||||
match api.request_write_body(id, &[], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.request_write_body(id, &[1, 2, 3, 4], None).unwrap();
|
||||
api.response_wait(&[id], None);
|
||||
match api.request_write_body(id, &[1, 2, 3, 4], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.response_headers(id);
|
||||
match api.request_write_body(id, &[1, 2, 3, 4], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("GET", &format!("http://{}", addr)).unwrap();
|
||||
api.response_headers(id);
|
||||
match api.request_write_body(id, &[], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.response_read_body(id, &mut [], None).unwrap();
|
||||
match api.request_write_body(id, &[1, 2, 3, 4], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let id = api.request_start("POST", &format!("http://{}", addr)).unwrap();
|
||||
api.response_read_body(id, &mut [], None).unwrap();
|
||||
match api.request_write_body(id, &[], None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -948,15 +950,15 @@ mod tests {
|
||||
let mut buf = [0; 512];
|
||||
|
||||
match api.response_read_body(HttpRequestId(0xdead), &mut buf, None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
let id = api.request_start("GET", &format!("http://{}", addr)).unwrap();
|
||||
while api.response_read_body(id, &mut buf, None).unwrap() != 0 {}
|
||||
match api.response_read_body(id, &mut buf, None) {
|
||||
Err(HttpError::Invalid) => {}
|
||||
_ => panic!()
|
||||
Err(HttpError::Invalid) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,16 +975,26 @@ mod tests {
|
||||
|
||||
for _ in 0..250 {
|
||||
match rand::random::<u8>() % 6 {
|
||||
0 => { let _ = api.request_add_header(id, "Foo", "Bar"); }
|
||||
1 => { let _ = api.request_write_body(id, &[1, 2, 3, 4], None); }
|
||||
2 => { let _ = api.request_write_body(id, &[], None); }
|
||||
3 => { let _ = api.response_wait(&[id], None); }
|
||||
4 => { let _ = api.response_headers(id); }
|
||||
0 => {
|
||||
let _ = api.request_add_header(id, "Foo", "Bar");
|
||||
},
|
||||
1 => {
|
||||
let _ = api.request_write_body(id, &[1, 2, 3, 4], None);
|
||||
},
|
||||
2 => {
|
||||
let _ = api.request_write_body(id, &[], None);
|
||||
},
|
||||
3 => {
|
||||
let _ = api.response_wait(&[id], None);
|
||||
},
|
||||
4 => {
|
||||
let _ = api.response_headers(id);
|
||||
},
|
||||
5 => {
|
||||
let mut buf = [0; 512];
|
||||
let _ = api.response_read_body(id, &mut buf, None);
|
||||
}
|
||||
6 ..= 255 => unreachable!()
|
||||
},
|
||||
6..=255 => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,12 @@
|
||||
|
||||
//! Contains the same API as the `http` module, except that everything returns an error.
|
||||
|
||||
use sp_core::offchain::{HttpRequestId, Timestamp, HttpRequestStatus, HttpError};
|
||||
use std::{future::Future, pin::Pin, task::Context, task::Poll};
|
||||
use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp};
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
/// Wrapper struct (wrapping nothing in case of http_dummy) used for keeping the hyper_rustls client running.
|
||||
#[derive(Clone)]
|
||||
@@ -46,24 +50,17 @@ pub struct HttpWorker;
|
||||
|
||||
impl HttpApi {
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn request_start(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: &str
|
||||
) -> Result<HttpRequestId, ()> {
|
||||
pub fn request_start(&mut self, _: &str, _: &str) -> Result<HttpRequestId, ()> {
|
||||
/// Because this always returns an error, none of the other methods should ever be called.
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn request_add_header(
|
||||
&mut self,
|
||||
_: HttpRequestId,
|
||||
_: &str,
|
||||
_: &str
|
||||
) -> Result<(), ()> {
|
||||
unreachable!("Creating a request always fails, thus this function will \
|
||||
never be called; qed")
|
||||
pub fn request_add_header(&mut self, _: HttpRequestId, _: &str, _: &str) -> Result<(), ()> {
|
||||
unreachable!(
|
||||
"Creating a request always fails, thus this function will \
|
||||
never be called; qed"
|
||||
)
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
@@ -71,33 +68,36 @@ impl HttpApi {
|
||||
&mut self,
|
||||
_: HttpRequestId,
|
||||
_: &[u8],
|
||||
_: Option<Timestamp>
|
||||
_: Option<Timestamp>,
|
||||
) -> Result<(), HttpError> {
|
||||
unreachable!("Creating a request always fails, thus this function will \
|
||||
never be called; qed")
|
||||
unreachable!(
|
||||
"Creating a request always fails, thus this function will \
|
||||
never be called; qed"
|
||||
)
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn response_wait(
|
||||
&mut self,
|
||||
requests: &[HttpRequestId],
|
||||
_: Option<Timestamp>
|
||||
_: Option<Timestamp>,
|
||||
) -> Vec<HttpRequestStatus> {
|
||||
if requests.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
unreachable!("Creating a request always fails, thus the list of requests should \
|
||||
always be empty; qed")
|
||||
unreachable!(
|
||||
"Creating a request always fails, thus the list of requests should \
|
||||
always be empty; qed"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
pub fn response_headers(
|
||||
&mut self,
|
||||
_: HttpRequestId
|
||||
) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
unreachable!("Creating a request always fails, thus this function will \
|
||||
never be called; qed")
|
||||
pub fn response_headers(&mut self, _: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
unreachable!(
|
||||
"Creating a request always fails, thus this function will \
|
||||
never be called; qed"
|
||||
)
|
||||
}
|
||||
|
||||
/// Mimics the corresponding method in the offchain API.
|
||||
@@ -105,10 +105,12 @@ impl HttpApi {
|
||||
&mut self,
|
||||
_: HttpRequestId,
|
||||
_: &mut [u8],
|
||||
_: Option<Timestamp>
|
||||
_: Option<Timestamp>,
|
||||
) -> Result<usize, HttpError> {
|
||||
unreachable!("Creating a request always fails, thus this function will \
|
||||
never be called; qed")
|
||||
unreachable!(
|
||||
"Creating a request always fails, thus this function will \
|
||||
never be called; qed"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
//! Helper methods dedicated to timestamps.
|
||||
|
||||
use sp_core::offchain::Timestamp;
|
||||
use std::convert::TryInto;
|
||||
use std::time::{SystemTime, Duration};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
/// Returns the current time as a `Timestamp`.
|
||||
pub fn now() -> Timestamp {
|
||||
@@ -34,9 +36,12 @@ pub fn now() -> Timestamp {
|
||||
Ok(d) => {
|
||||
let duration = d.as_millis();
|
||||
// Assuming overflow won't happen for a few hundred years.
|
||||
Timestamp::from_unix_millis(duration.try_into()
|
||||
.expect("epoch milliseconds won't overflow u64 for hundreds of years; qed"))
|
||||
}
|
||||
Timestamp::from_unix_millis(
|
||||
duration
|
||||
.try_into()
|
||||
.expect("epoch milliseconds won't overflow u64 for hundreds of years; qed"),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +65,6 @@ pub fn deadline_to_future(
|
||||
// Only apply delay if we need to wait a non-zero duration
|
||||
Some(duration) if duration <= Duration::from_secs(0) =>
|
||||
Either::Right(Either::Left(future::ready(()))),
|
||||
Some(duration) =>
|
||||
Either::Right(Either::Right(futures_timer::Delay::new(duration))),
|
||||
Some(duration) => Either::Right(Either::Right(futures_timer::Delay::new(duration))),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,20 +35,22 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{
|
||||
fmt, marker::PhantomData, sync::Arc,
|
||||
collections::HashSet,
|
||||
};
|
||||
use std::{collections::HashSet, fmt, marker::PhantomData, sync::Arc};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use threadpool::ThreadPool;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use futures::future::Future;
|
||||
use futures::{
|
||||
future::{ready, Future},
|
||||
prelude::*,
|
||||
};
|
||||
use log::{debug, warn};
|
||||
use parking_lot::Mutex;
|
||||
use sc_network::{ExHashT, NetworkService, NetworkStateInfo, PeerId};
|
||||
use sp_core::{offchain, ExecutionContext, traits::SpawnNamed};
|
||||
use sp_runtime::{generic::BlockId, traits::{self, Header}};
|
||||
use futures::{prelude::*, future::ready};
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_core::{offchain, traits::SpawnNamed, ExecutionContext};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{self, Header},
|
||||
};
|
||||
use threadpool::ThreadPool;
|
||||
|
||||
mod api;
|
||||
|
||||
@@ -94,25 +96,23 @@ impl<Client, Block: traits::Block> OffchainWorkers<Client, Block> {
|
||||
Self {
|
||||
client,
|
||||
_block: PhantomData,
|
||||
thread_pool: Mutex::new(ThreadPool::with_name("offchain-worker".into(), num_cpus::get())),
|
||||
thread_pool: Mutex::new(ThreadPool::with_name(
|
||||
"offchain-worker".into(),
|
||||
num_cpus::get(),
|
||||
)),
|
||||
shared_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Block: traits::Block> fmt::Debug for OffchainWorkers<
|
||||
Client,
|
||||
Block,
|
||||
> {
|
||||
impl<Client, Block: traits::Block> fmt::Debug for OffchainWorkers<Client, Block> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("OffchainWorkers").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Block> OffchainWorkers<
|
||||
Client,
|
||||
Block,
|
||||
> where
|
||||
impl<Client, Block> OffchainWorkers<Client, Block>
|
||||
where
|
||||
Block: traits::Block,
|
||||
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
@@ -127,28 +127,22 @@ impl<Client, Block> OffchainWorkers<
|
||||
) -> impl Future<Output = ()> {
|
||||
let runtime = self.client.runtime_api();
|
||||
let at = BlockId::hash(header.hash());
|
||||
let has_api_v1 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(
|
||||
&at, |v| v == 1
|
||||
);
|
||||
let has_api_v2 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(
|
||||
&at, |v| v == 2
|
||||
);
|
||||
let has_api_v1 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(&at, |v| v == 1);
|
||||
let has_api_v2 = runtime.has_api_with::<dyn OffchainWorkerApi<Block>, _>(&at, |v| v == 2);
|
||||
let version = match (has_api_v1, has_api_v2) {
|
||||
(_, Ok(true)) => 2,
|
||||
(Ok(true), _) => 1,
|
||||
err => {
|
||||
let help = "Consider turning off offchain workers if they are not part of your runtime.";
|
||||
let help =
|
||||
"Consider turning off offchain workers if they are not part of your runtime.";
|
||||
log::error!("Unsupported Offchain Worker API version: {:?}. {}.", err, help);
|
||||
0
|
||||
}
|
||||
},
|
||||
};
|
||||
debug!("Checking offchain workers at {:?}: version:{}", at, version);
|
||||
if version > 0 {
|
||||
let (api, runner) = api::AsyncApi::new(
|
||||
network_provider,
|
||||
is_validator,
|
||||
self.shared_client.clone(),
|
||||
);
|
||||
let (api, runner) =
|
||||
api::AsyncApi::new(network_provider, is_validator, self.shared_client.clone());
|
||||
debug!("Spawning offchain workers at {:?}", at);
|
||||
let header = header.clone();
|
||||
let client = self.client.clone();
|
||||
@@ -156,18 +150,19 @@ impl<Client, Block> OffchainWorkers<
|
||||
let runtime = client.runtime_api();
|
||||
let api = Box::new(api);
|
||||
debug!("Running offchain workers at {:?}", at);
|
||||
let context = ExecutionContext::OffchainCall(Some(
|
||||
(api, offchain::Capabilities::all())
|
||||
));
|
||||
let context =
|
||||
ExecutionContext::OffchainCall(Some((api, offchain::Capabilities::all())));
|
||||
let run = if version == 2 {
|
||||
runtime.offchain_worker_with_context(&at, context, &header)
|
||||
} else {
|
||||
#[allow(deprecated)]
|
||||
runtime.offchain_worker_before_version_2_with_context(
|
||||
&at, context, *header.number()
|
||||
&at,
|
||||
context,
|
||||
*header.number(),
|
||||
)
|
||||
};
|
||||
if let Err(e) = run {
|
||||
if let Err(e) = run {
|
||||
log::error!("Error running offchain workers at {:?}: {:?}", at, e);
|
||||
}
|
||||
});
|
||||
@@ -197,50 +192,51 @@ pub async fn notification_future<Client, Block, Spawner>(
|
||||
offchain: Arc<OffchainWorkers<Client, Block>>,
|
||||
spawner: Spawner,
|
||||
network_provider: Arc<dyn NetworkProvider + Send + Sync>,
|
||||
)
|
||||
where
|
||||
Block: traits::Block,
|
||||
Client: ProvideRuntimeApi<Block> + sc_client_api::BlockchainEvents<Block> + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
Spawner: SpawnNamed
|
||||
) where
|
||||
Block: traits::Block,
|
||||
Client:
|
||||
ProvideRuntimeApi<Block> + sc_client_api::BlockchainEvents<Block> + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
Spawner: SpawnNamed,
|
||||
{
|
||||
client.import_notification_stream().for_each(move |n| {
|
||||
if n.is_new_best {
|
||||
spawner.spawn(
|
||||
"offchain-on-block",
|
||||
offchain.on_block_imported(
|
||||
&n.header,
|
||||
network_provider.clone(),
|
||||
is_validator,
|
||||
).boxed(),
|
||||
);
|
||||
} else {
|
||||
log::debug!(
|
||||
target: "sc_offchain",
|
||||
"Skipping offchain workers for non-canon block: {:?}",
|
||||
n.header,
|
||||
)
|
||||
}
|
||||
client
|
||||
.import_notification_stream()
|
||||
.for_each(move |n| {
|
||||
if n.is_new_best {
|
||||
spawner.spawn(
|
||||
"offchain-on-block",
|
||||
offchain
|
||||
.on_block_imported(&n.header, network_provider.clone(), is_validator)
|
||||
.boxed(),
|
||||
);
|
||||
} else {
|
||||
log::debug!(
|
||||
target: "sc_offchain",
|
||||
"Skipping offchain workers for non-canon block: {:?}",
|
||||
n.header,
|
||||
)
|
||||
}
|
||||
|
||||
ready(())
|
||||
}).await;
|
||||
ready(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::Arc;
|
||||
use sc_network::{Multiaddr, PeerId};
|
||||
use substrate_test_runtime_client::{
|
||||
TestClient, runtime::Block, TestClientBuilderExt,
|
||||
DefaultTestClientBuilderExt, ClientBlockImportExt,
|
||||
};
|
||||
use sc_transaction_pool::{BasicPool, FullChainApi};
|
||||
use sc_transaction_pool_api::{TransactionPool, InPoolTransaction};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sc_client_api::Backend as _;
|
||||
use sc_block_builder::BlockBuilderProvider as _;
|
||||
use futures::executor::block_on;
|
||||
use sc_block_builder::BlockBuilderProvider as _;
|
||||
use sc_client_api::Backend as _;
|
||||
use sc_network::{Multiaddr, PeerId};
|
||||
use sc_transaction_pool::{BasicPool, FullChainApi};
|
||||
use sc_transaction_pool_api::{InPoolTransaction, TransactionPool};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::Block, ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient,
|
||||
TestClientBuilderExt,
|
||||
};
|
||||
|
||||
struct TestNetwork();
|
||||
|
||||
@@ -264,9 +260,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
struct TestPool(
|
||||
Arc<BasicPool<FullChainApi<TestClient, Block>, Block>>
|
||||
);
|
||||
struct TestPool(Arc<BasicPool<FullChainApi<TestClient, Block>, Block>>);
|
||||
|
||||
impl sc_transaction_pool_api::OffchainSubmitTransaction<Block> for TestPool {
|
||||
fn submit_at(
|
||||
@@ -299,9 +293,7 @@ mod tests {
|
||||
|
||||
// when
|
||||
let offchain = OffchainWorkers::new(client);
|
||||
futures::executor::block_on(
|
||||
offchain.on_block_imported(&header, network, false)
|
||||
);
|
||||
futures::executor::block_on(offchain.on_block_imported(&header, network, false));
|
||||
|
||||
// then
|
||||
assert_eq!(pool.0.status().ready, 1);
|
||||
@@ -314,22 +306,21 @@ mod tests {
|
||||
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let (client, backend) =
|
||||
substrate_test_runtime_client::TestClientBuilder::new()
|
||||
.enable_offchain_indexing_api()
|
||||
.build_with_backend();
|
||||
let (client, backend) = substrate_test_runtime_client::TestClientBuilder::new()
|
||||
.enable_offchain_indexing_api()
|
||||
.build_with_backend();
|
||||
let mut client = Arc::new(client);
|
||||
let offchain_db = backend.offchain_storage().unwrap();
|
||||
|
||||
let key = &b"hello"[..];
|
||||
let value = &b"world"[..];
|
||||
let mut block_builder = client.new_block(Default::default()).unwrap();
|
||||
block_builder.push(
|
||||
substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexSet(
|
||||
block_builder
|
||||
.push(substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexSet(
|
||||
key.to_vec(),
|
||||
value.to_vec(),
|
||||
),
|
||||
).unwrap();
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let block = block_builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
@@ -337,9 +328,11 @@ mod tests {
|
||||
assert_eq!(value, &offchain_db.get(sp_offchain::STORAGE_PREFIX, &key).unwrap());
|
||||
|
||||
let mut block_builder = client.new_block(Default::default()).unwrap();
|
||||
block_builder.push(
|
||||
substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexClear(key.to_vec()),
|
||||
).unwrap();
|
||||
block_builder
|
||||
.push(substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexClear(
|
||||
key.to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let block = block_builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user