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