referrerpolicy=no-referrer-when-downgrade

sp_core/offchain/
mod.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Offchain workers types
19
20use crate::{OpaquePeerId, RuntimeDebug};
21use alloc::{boxed::Box, vec::Vec};
22use codec::{Decode, Encode};
23use scale_info::TypeInfo;
24
25pub use crate::crypto::KeyTypeId;
26
27#[cfg(feature = "std")]
28pub mod storage;
29#[cfg(feature = "std")]
30pub mod testing;
31
32/// Persistent storage prefix used by the Offchain Worker API when creating a DB key.
33pub const STORAGE_PREFIX: &[u8] = b"storage";
34
35/// Offchain DB persistent (non-fork-aware) storage.
36pub trait OffchainStorage: Clone + Send + Sync {
37	/// Persist a value in storage under given key and prefix.
38	fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]);
39
40	/// Clear a storage entry under given key and prefix.
41	fn remove(&mut self, prefix: &[u8], key: &[u8]);
42
43	/// Retrieve a value from storage under given key and prefix.
44	fn get(&self, prefix: &[u8], key: &[u8]) -> Option<Vec<u8>>;
45
46	/// Replace the value in storage if given old_value matches the current one.
47	///
48	/// Returns `true` if the value has been set and false otherwise.
49	fn compare_and_set(
50		&mut self,
51		prefix: &[u8],
52		key: &[u8],
53		old_value: Option<&[u8]>,
54		new_value: &[u8],
55	) -> bool;
56}
57
58/// A type of supported crypto.
59#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61#[repr(C)]
62pub enum StorageKind {
63	/// Persistent storage is non-revertible and not fork-aware. It means that any value
64	/// set by the offchain worker triggered at block `N(hash1)` is persisted even
65	/// if that block is reverted as non-canonical and is available for the worker
66	/// that is re-run at block `N(hash2)`.
67	/// This storage can be used by offchain workers to handle forks
68	/// and coordinate offchain workers running on different forks.
69	PERSISTENT = 0_isize,
70	/// Local storage is revertible and fork-aware. It means that any value
71	/// set by the offchain worker triggered at block `N(hash1)` is reverted
72	/// if that block is reverted as non-canonical and is NOT available for the worker
73	/// that is re-run at block `N(hash2)`.
74	LOCAL = 1_isize,
75}
76
77impl TryFrom<u32> for StorageKind {
78	type Error = ();
79
80	fn try_from(kind: u32) -> Result<Self, Self::Error> {
81		match kind {
82			e if e == u32::from(StorageKind::PERSISTENT as u8) => Ok(StorageKind::PERSISTENT),
83			e if e == u32::from(StorageKind::LOCAL as u8) => Ok(StorageKind::LOCAL),
84			_ => Err(()),
85		}
86	}
87}
88
89impl From<StorageKind> for u32 {
90	fn from(c: StorageKind) -> Self {
91		c as u32
92	}
93}
94
95/// Opaque type for offchain http requests.
96#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode)]
97#[cfg_attr(feature = "std", derive(Hash))]
98pub struct HttpRequestId(pub u16);
99
100impl From<u16> for HttpRequestId {
101	fn from(value: u16) -> Self {
102		Self(value)
103	}
104}
105
106impl From<HttpRequestId> for u16 {
107	fn from(c: HttpRequestId) -> Self {
108		c.0
109	}
110}
111
112impl From<HttpRequestId> for u32 {
113	fn from(c: HttpRequestId) -> Self {
114		c.0 as u32
115	}
116}
117
118/// An error enum returned by some http methods.
119#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)]
120#[repr(C)]
121pub enum HttpError {
122	/// The requested action couldn't been completed within a deadline.
123	#[codec(index = 1)]
124	DeadlineReached = 0_isize,
125	/// There was an IO Error while processing the request.
126	#[codec(index = 2)]
127	IoError = 1_isize,
128	/// The ID of the request is invalid in this context.
129	#[codec(index = 3)]
130	Invalid = 2_isize,
131}
132
133impl TryFrom<u32> for HttpError {
134	type Error = ();
135
136	fn try_from(error: u32) -> Result<Self, Self::Error> {
137		match error {
138			e if e == HttpError::DeadlineReached as u8 as u32 => Ok(HttpError::DeadlineReached),
139			e if e == HttpError::IoError as u8 as u32 => Ok(HttpError::IoError),
140			e if e == HttpError::Invalid as u8 as u32 => Ok(HttpError::Invalid),
141			_ => Err(()),
142		}
143	}
144}
145
146impl From<HttpError> for u32 {
147	fn from(c: HttpError) -> Self {
148		c as u8 as u32
149	}
150}
151
152/// Status of the HTTP request
153#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)]
154pub enum HttpRequestStatus {
155	/// Deadline was reached while we waited for this request to finish.
156	///
157	/// Note the deadline is controlled by the calling part, it not necessarily
158	/// means that the request has timed out.
159	DeadlineReached,
160	/// An error has occurred during the request, for example a timeout or the
161	/// remote has closed our socket.
162	///
163	/// The request is now considered destroyed. To retry the request you need
164	/// to construct it again.
165	IoError,
166	/// The passed ID is invalid in this context.
167	Invalid,
168	/// The request has finished with given status code.
169	Finished(u16),
170}
171
172impl From<HttpRequestStatus> for u32 {
173	fn from(status: HttpRequestStatus) -> Self {
174		match status {
175			HttpRequestStatus::Invalid => 0,
176			HttpRequestStatus::DeadlineReached => 10,
177			HttpRequestStatus::IoError => 20,
178			HttpRequestStatus::Finished(code) => u32::from(code),
179		}
180	}
181}
182
183impl TryFrom<u32> for HttpRequestStatus {
184	type Error = ();
185
186	fn try_from(status: u32) -> Result<Self, Self::Error> {
187		match status {
188			0 => Ok(HttpRequestStatus::Invalid),
189			10 => Ok(HttpRequestStatus::DeadlineReached),
190			20 => Ok(HttpRequestStatus::IoError),
191			100..=999 => u16::try_from(status).map(HttpRequestStatus::Finished).map_err(|_| ()),
192			_ => Err(()),
193		}
194	}
195}
196
197/// A blob to hold information about the local node's network state
198/// without committing to its format.
199#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
200#[cfg_attr(feature = "std", derive(Default))]
201pub struct OpaqueNetworkState {
202	/// PeerId of the local node in SCALE encoded.
203	pub peer_id: OpaquePeerId,
204	/// List of addresses the node knows it can be reached as.
205	pub external_addresses: Vec<OpaqueMultiaddr>,
206}
207
208/// Simple blob to hold a `Multiaddr` without committing to its format.
209#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
210pub struct OpaqueMultiaddr(pub Vec<u8>);
211
212impl OpaqueMultiaddr {
213	/// Create new `OpaqueMultiaddr`
214	pub fn new(vec: Vec<u8>) -> Self {
215		OpaqueMultiaddr(vec)
216	}
217}
218
219/// Opaque timestamp type
220#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, Encode, Decode)]
221#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
222pub struct Timestamp(u64);
223
224impl From<u64> for Timestamp {
225	fn from(value: u64) -> Self {
226		Self(value)
227	}
228}
229
230impl From<Timestamp> for u64 {
231	fn from(value: Timestamp) -> u64 {
232		value.0
233	}
234}
235
236/// Duration type
237#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, Encode, Decode)]
238#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239pub struct Duration(u64);
240
241impl Duration {
242	/// Create new duration representing given number of milliseconds.
243	pub const fn from_millis(millis: u64) -> Self {
244		Duration(millis)
245	}
246
247	/// Returns number of milliseconds this Duration represents.
248	pub fn millis(&self) -> u64 {
249		self.0
250	}
251}
252
253impl Timestamp {
254	/// Creates new `Timestamp` given unix timestamp in milliseconds.
255	pub fn from_unix_millis(millis: u64) -> Self {
256		Timestamp(millis)
257	}
258
259	/// Increase the timestamp by given `Duration`.
260	pub fn add(&self, duration: Duration) -> Timestamp {
261		Timestamp(self.0.saturating_add(duration.0))
262	}
263
264	/// Decrease the timestamp by given `Duration`
265	pub fn sub(&self, duration: Duration) -> Timestamp {
266		Timestamp(self.0.saturating_sub(duration.0))
267	}
268
269	/// Returns a saturated difference (Duration) between two Timestamps.
270	pub fn diff(&self, other: &Self) -> Duration {
271		Duration(self.0.saturating_sub(other.0))
272	}
273
274	/// Return number of milliseconds since UNIX epoch.
275	pub fn unix_millis(&self) -> u64 {
276		self.0
277	}
278}
279
280bitflags::bitflags! {
281	/// Execution context extra capabilities.
282	pub struct Capabilities: u32 {
283		/// External http calls.
284		const HTTP = 1 << 0;
285		/// Keystore access.
286		const KEYSTORE = 1 << 2;
287		/// Randomness source.
288		const RANDOMNESS = 1 << 3;
289		/// Access to opaque network state.
290		const NETWORK_STATE = 1 << 4;
291		/// Access to offchain worker DB (read only).
292		const OFFCHAIN_DB_READ = 1 << 5;
293		/// Access to offchain worker DB (writes).
294		const OFFCHAIN_DB_WRITE = 1 << 6;
295		/// Manage the authorized nodes
296		const NODE_AUTHORIZATION = 1 << 7;
297		/// Access time related functionality
298		const TIME = 1 << 8;
299	}
300}
301
302/// An extended externalities for offchain workers.
303pub trait Externalities: Send {
304	/// Returns if the local node is a potential validator.
305	///
306	/// Even if this function returns `true`, it does not mean that any keys are configured
307	/// and that the validator is registered in the chain.
308	fn is_validator(&self) -> bool;
309
310	/// Returns information about the local node's network state.
311	fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
312
313	/// Returns current UNIX timestamp (in millis)
314	fn timestamp(&mut self) -> Timestamp;
315
316	/// Pause the execution until `deadline` is reached.
317	fn sleep_until(&mut self, deadline: Timestamp);
318
319	/// Returns a random seed.
320	///
321	/// This is a truly random non deterministic seed generated by host environment.
322	/// Obviously fine in the off-chain worker context.
323	fn random_seed(&mut self) -> [u8; 32];
324
325	/// Initiates a http request given HTTP verb and the URL.
326	///
327	/// Meta is a future-reserved field containing additional, parity-scale-codec encoded
328	/// parameters. Returns the id of newly started request.
329	///
330	/// Returns an error if:
331	/// - No new request identifier could be allocated.
332	/// - The method or URI contain invalid characters.
333	fn http_request_start(
334		&mut self,
335		method: &str,
336		uri: &str,
337		meta: &[u8],
338	) -> Result<HttpRequestId, ()>;
339
340	/// Append header to the request.
341	///
342	/// Calling this function multiple times with the same header name continues appending new
343	/// headers. In other words, headers are never replaced.
344	///
345	/// Returns an error if:
346	/// - The request identifier is invalid.
347	/// - You have called `http_request_write_body` on that request.
348	/// - The name or value contain invalid characters.
349	///
350	/// An error doesn't poison the request, and you can continue as if the call had never been
351	/// made.
352	fn http_request_add_header(
353		&mut self,
354		request_id: HttpRequestId,
355		name: &str,
356		value: &str,
357	) -> Result<(), ()>;
358
359	/// Write a chunk of request body.
360	///
361	/// Calling this function with a non-empty slice may or may not start the
362	/// HTTP request. Calling this function with an empty chunks finalizes the
363	/// request and always starts it. It is no longer valid to write more data
364	/// afterwards.
365	/// Passing `None` as deadline blocks forever.
366	///
367	/// Returns an error if:
368	/// - The request identifier is invalid.
369	/// - `http_response_wait` has already been called on this request.
370	/// - The deadline is reached.
371	/// - An I/O error has happened, for example the remote has closed our request. The request is
372	///   then considered invalid.
373	fn http_request_write_body(
374		&mut self,
375		request_id: HttpRequestId,
376		chunk: &[u8],
377		deadline: Option<Timestamp>,
378	) -> Result<(), HttpError>;
379
380	/// Block and wait for the responses for given requests.
381	///
382	/// Returns a vector of request statuses (the len is the same as ids).
383	/// Note that if deadline is not provided the method will block indefinitely,
384	/// otherwise unready responses will produce `DeadlineReached` status.
385	///
386	/// If a response returns an `IoError`, it is then considered destroyed.
387	/// Its id is then invalid.
388	///
389	/// Passing `None` as deadline blocks forever.
390	fn http_response_wait(
391		&mut self,
392		ids: &[HttpRequestId],
393		deadline: Option<Timestamp>,
394	) -> Vec<HttpRequestStatus>;
395
396	/// Read all response headers.
397	///
398	/// Returns a vector of pairs `(HeaderKey, HeaderValue)`.
399	///
400	/// Dispatches the request if it hasn't been done yet. It is no longer
401	/// valid to modify the headers or write data to the request.
402	///
403	/// Returns an empty list if the identifier is unknown/invalid, hasn't
404	/// received a response, or has finished.
405	fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)>;
406
407	/// Read a chunk of body response to given buffer.
408	///
409	/// Dispatches the request if it hasn't been done yet. It is no longer
410	/// valid to modify the headers or write data to the request.
411	///
412	/// Returns the number of bytes written or an error in case a deadline
413	/// is reached or server closed the connection.
414	/// Passing `None` as a deadline blocks forever.
415	///
416	/// If `Ok(0)` or `Err(IoError)` is returned, the request is considered
417	/// destroyed. Doing another read or getting the response's headers, for
418	/// example, is then invalid.
419	///
420	/// Returns an error if:
421	/// - The request identifier is invalid.
422	/// - The deadline is reached.
423	/// - An I/O error has happened, for example the remote has closed our request. The request is
424	///   then considered invalid.
425	fn http_response_read_body(
426		&mut self,
427		request_id: HttpRequestId,
428		buffer: &mut [u8],
429		deadline: Option<Timestamp>,
430	) -> Result<usize, HttpError>;
431
432	/// Set the authorized nodes from runtime.
433	///
434	/// In a permissioned network, the connections between nodes need to reach a
435	/// consensus between participants.
436	///
437	/// - `nodes`: a set of nodes which are allowed to connect for the local node.
438	/// each one is identified with an `OpaquePeerId`, here it just use plain bytes
439	/// without any encoding. Invalid `OpaquePeerId`s are silently ignored.
440	/// - `authorized_only`: if true, only the authorized nodes are allowed to connect,
441	/// otherwise unauthorized nodes can also be connected through other mechanism.
442	fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool);
443}
444
445impl<T: Externalities + ?Sized> Externalities for Box<T> {
446	fn is_validator(&self) -> bool {
447		(&**self).is_validator()
448	}
449
450	fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
451		(&**self).network_state()
452	}
453
454	fn timestamp(&mut self) -> Timestamp {
455		(&mut **self).timestamp()
456	}
457
458	fn sleep_until(&mut self, deadline: Timestamp) {
459		(&mut **self).sleep_until(deadline)
460	}
461
462	fn random_seed(&mut self) -> [u8; 32] {
463		(&mut **self).random_seed()
464	}
465
466	fn http_request_start(
467		&mut self,
468		method: &str,
469		uri: &str,
470		meta: &[u8],
471	) -> Result<HttpRequestId, ()> {
472		(&mut **self).http_request_start(method, uri, meta)
473	}
474
475	fn http_request_add_header(
476		&mut self,
477		request_id: HttpRequestId,
478		name: &str,
479		value: &str,
480	) -> Result<(), ()> {
481		(&mut **self).http_request_add_header(request_id, name, value)
482	}
483
484	fn http_request_write_body(
485		&mut self,
486		request_id: HttpRequestId,
487		chunk: &[u8],
488		deadline: Option<Timestamp>,
489	) -> Result<(), HttpError> {
490		(&mut **self).http_request_write_body(request_id, chunk, deadline)
491	}
492
493	fn http_response_wait(
494		&mut self,
495		ids: &[HttpRequestId],
496		deadline: Option<Timestamp>,
497	) -> Vec<HttpRequestStatus> {
498		(&mut **self).http_response_wait(ids, deadline)
499	}
500
501	fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
502		(&mut **self).http_response_headers(request_id)
503	}
504
505	fn http_response_read_body(
506		&mut self,
507		request_id: HttpRequestId,
508		buffer: &mut [u8],
509		deadline: Option<Timestamp>,
510	) -> Result<usize, HttpError> {
511		(&mut **self).http_response_read_body(request_id, buffer, deadline)
512	}
513
514	fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool) {
515		(&mut **self).set_authorized_nodes(nodes, authorized_only)
516	}
517}
518
519/// An `*Externalities` implementation with limited capabilities.
520pub struct LimitedExternalities<T> {
521	capabilities: Capabilities,
522	externalities: T,
523}
524
525impl<T> LimitedExternalities<T> {
526	/// Create new externalities limited to given `capabilities`.
527	pub fn new(capabilities: Capabilities, externalities: T) -> Self {
528		Self { capabilities, externalities }
529	}
530
531	/// Check if given capability is allowed.
532	///
533	/// Panics in case it is not.
534	fn check(&self, capability: Capabilities, name: &'static str) {
535		if !self.capabilities.contains(capability) {
536			panic!("Accessing a forbidden API: {}. No: {:?} capability.", name, capability);
537		}
538	}
539}
540
541impl<T: Externalities> Externalities for LimitedExternalities<T> {
542	fn is_validator(&self) -> bool {
543		self.check(Capabilities::KEYSTORE, "is_validator");
544		self.externalities.is_validator()
545	}
546
547	fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
548		self.check(Capabilities::NETWORK_STATE, "network_state");
549		self.externalities.network_state()
550	}
551
552	fn timestamp(&mut self) -> Timestamp {
553		self.check(Capabilities::TIME, "timestamp");
554		self.externalities.timestamp()
555	}
556
557	fn sleep_until(&mut self, deadline: Timestamp) {
558		self.check(Capabilities::TIME, "sleep_until");
559		self.externalities.sleep_until(deadline)
560	}
561
562	fn random_seed(&mut self) -> [u8; 32] {
563		self.check(Capabilities::RANDOMNESS, "random_seed");
564		self.externalities.random_seed()
565	}
566
567	fn http_request_start(
568		&mut self,
569		method: &str,
570		uri: &str,
571		meta: &[u8],
572	) -> Result<HttpRequestId, ()> {
573		self.check(Capabilities::HTTP, "http_request_start");
574		self.externalities.http_request_start(method, uri, meta)
575	}
576
577	fn http_request_add_header(
578		&mut self,
579		request_id: HttpRequestId,
580		name: &str,
581		value: &str,
582	) -> Result<(), ()> {
583		self.check(Capabilities::HTTP, "http_request_add_header");
584		self.externalities.http_request_add_header(request_id, name, value)
585	}
586
587	fn http_request_write_body(
588		&mut self,
589		request_id: HttpRequestId,
590		chunk: &[u8],
591		deadline: Option<Timestamp>,
592	) -> Result<(), HttpError> {
593		self.check(Capabilities::HTTP, "http_request_write_body");
594		self.externalities.http_request_write_body(request_id, chunk, deadline)
595	}
596
597	fn http_response_wait(
598		&mut self,
599		ids: &[HttpRequestId],
600		deadline: Option<Timestamp>,
601	) -> Vec<HttpRequestStatus> {
602		self.check(Capabilities::HTTP, "http_response_wait");
603		self.externalities.http_response_wait(ids, deadline)
604	}
605
606	fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
607		self.check(Capabilities::HTTP, "http_response_headers");
608		self.externalities.http_response_headers(request_id)
609	}
610
611	fn http_response_read_body(
612		&mut self,
613		request_id: HttpRequestId,
614		buffer: &mut [u8],
615		deadline: Option<Timestamp>,
616	) -> Result<usize, HttpError> {
617		self.check(Capabilities::HTTP, "http_response_read_body");
618		self.externalities.http_response_read_body(request_id, buffer, deadline)
619	}
620
621	fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool) {
622		self.check(Capabilities::NODE_AUTHORIZATION, "set_authorized_nodes");
623		self.externalities.set_authorized_nodes(nodes, authorized_only)
624	}
625}
626
627#[cfg(not(substrate_runtime))]
628sp_externalities::decl_extension! {
629	/// The offchain worker extension that will be registered at the Substrate externalities.
630	pub struct OffchainWorkerExt(Box<dyn Externalities>);
631}
632
633#[cfg(not(substrate_runtime))]
634impl OffchainWorkerExt {
635	/// Create a new instance of `Self`.
636	pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
637		Self(Box::new(offchain))
638	}
639}
640
641/// A externalities extension for accessing the Offchain DB.
642pub trait DbExternalities: Send {
643	/// Sets a value in the local storage.
644	///
645	/// Note this storage is not part of the consensus, it's only accessible by
646	/// offchain worker tasks running on the same machine. It _is_ persisted between runs.
647	fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]);
648
649	/// Removes a value in the local storage.
650	///
651	/// Note this storage is not part of the consensus, it's only accessible by
652	/// offchain worker tasks running on the same machine. It _is_ persisted between runs.
653	fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]);
654
655	/// Sets a value in the local storage if it matches current value.
656	///
657	/// Since multiple offchain workers may be running concurrently, to prevent
658	/// data races use CAS to coordinate between them.
659	///
660	/// Returns `true` if the value has been set, `false` otherwise.
661	///
662	/// Note this storage is not part of the consensus, it's only accessible by
663	/// offchain worker tasks running on the same machine. It _is_ persisted between runs.
664	fn local_storage_compare_and_set(
665		&mut self,
666		kind: StorageKind,
667		key: &[u8],
668		old_value: Option<&[u8]>,
669		new_value: &[u8],
670	) -> bool;
671
672	/// Gets a value from the local storage.
673	///
674	/// If the value does not exist in the storage `None` will be returned.
675	/// Note this storage is not part of the consensus, it's only accessible by
676	/// offchain worker tasks running on the same machine. It _is_ persisted between runs.
677	fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>>;
678}
679
680impl<T: DbExternalities + ?Sized> DbExternalities for Box<T> {
681	fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
682		(&mut **self).local_storage_set(kind, key, value)
683	}
684
685	fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
686		(&mut **self).local_storage_clear(kind, key)
687	}
688
689	fn local_storage_compare_and_set(
690		&mut self,
691		kind: StorageKind,
692		key: &[u8],
693		old_value: Option<&[u8]>,
694		new_value: &[u8],
695	) -> bool {
696		(&mut **self).local_storage_compare_and_set(kind, key, old_value, new_value)
697	}
698
699	fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
700		(&mut **self).local_storage_get(kind, key)
701	}
702}
703
704impl<T: DbExternalities> DbExternalities for LimitedExternalities<T> {
705	fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
706		self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_set");
707		self.externalities.local_storage_set(kind, key, value)
708	}
709
710	fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
711		self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_clear");
712		self.externalities.local_storage_clear(kind, key)
713	}
714
715	fn local_storage_compare_and_set(
716		&mut self,
717		kind: StorageKind,
718		key: &[u8],
719		old_value: Option<&[u8]>,
720		new_value: &[u8],
721	) -> bool {
722		self.check(Capabilities::OFFCHAIN_DB_WRITE, "local_storage_compare_and_set");
723		self.externalities
724			.local_storage_compare_and_set(kind, key, old_value, new_value)
725	}
726
727	fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
728		self.check(Capabilities::OFFCHAIN_DB_READ, "local_storage_get");
729		self.externalities.local_storage_get(kind, key)
730	}
731}
732
733#[cfg(not(substrate_runtime))]
734sp_externalities::decl_extension! {
735	/// The offchain database extension that will be registered at the Substrate externalities.
736	pub struct OffchainDbExt(Box<dyn DbExternalities>);
737}
738
739#[cfg(not(substrate_runtime))]
740impl OffchainDbExt {
741	/// Create a new instance of `OffchainDbExt`.
742	pub fn new<O: DbExternalities + 'static>(offchain: O) -> Self {
743		Self(Box::new(offchain))
744	}
745}
746
747/// Abstraction over transaction pool.
748///
749/// This trait is currently used within the `ExternalitiesExtension`
750/// to provide offchain calls with access to the transaction pool without
751/// tight coupling with any pool implementation.
752#[cfg(not(substrate_runtime))]
753pub trait TransactionPool {
754	/// Submit transaction.
755	///
756	/// The transaction will end up in the pool and be propagated to others.
757	fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()>;
758}
759
760#[cfg(not(substrate_runtime))]
761sp_externalities::decl_extension! {
762	/// An externalities extension to submit transactions to the pool.
763	pub struct TransactionPoolExt(Box<dyn TransactionPool + Send>);
764}
765
766#[cfg(not(substrate_runtime))]
767impl TransactionPoolExt {
768	/// Create a new instance of `TransactionPoolExt`.
769	pub fn new<O: TransactionPool + Send + 'static>(pool: O) -> Self {
770		Self(Box::new(pool))
771	}
772}
773
774/// Change to be applied to the offchain worker db in regards to a key.
775#[derive(Debug, Clone, Hash, Eq, PartialEq)]
776pub enum OffchainOverlayedChange {
777	/// Remove the data associated with the key
778	Remove,
779	/// Overwrite the value of an associated key
780	SetValue(Vec<u8>),
781}
782
783#[cfg(test)]
784mod tests {
785	use super::*;
786
787	#[test]
788	fn timestamp_ops() {
789		let t = Timestamp(5);
790		assert_eq!(t.add(Duration::from_millis(10)), Timestamp(15));
791		assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0));
792		assert_eq!(t.diff(&Timestamp(3)), Duration(2));
793	}
794
795	#[test]
796	fn capabilities() {
797		let none = Capabilities::empty();
798		let all = Capabilities::all();
799		let some = Capabilities::KEYSTORE | Capabilities::RANDOMNESS;
800
801		assert!(!none.contains(Capabilities::KEYSTORE));
802		assert!(all.contains(Capabilities::KEYSTORE));
803		assert!(some.contains(Capabilities::KEYSTORE));
804		assert!(!none.contains(Capabilities::RANDOMNESS));
805		assert!(all.contains(Capabilities::RANDOMNESS));
806		assert!(!some.contains(Capabilities::TIME));
807	}
808}