1use 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
33pub const STORAGE_PREFIX: &[u8] = b"storage";
35
36pub trait OffchainStorage: Clone + Send + Sync {
38 fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]);
40
41 fn remove(&mut self, prefix: &[u8], key: &[u8]);
43
44 fn get(&self, prefix: &[u8], key: &[u8]) -> Option<Vec<u8>>;
46
47 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#[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 = 1_isize,
71 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#[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#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByEnum)]
111#[repr(C)]
112pub enum HttpError {
113 DeadlineReached = 1_isize,
115 IoError = 2_isize,
117 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#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByCodec)]
142pub enum HttpRequestStatus {
143 DeadlineReached,
148 IoError,
154 Invalid,
156 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#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByCodec, TypeInfo)]
188#[cfg_attr(feature = "std", derive(Default))]
189pub struct OpaqueNetworkState {
190 pub peer_id: OpaquePeerId,
192 pub external_addresses: Vec<OpaqueMultiaddr>,
194}
195
196#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner, TypeInfo)]
198pub struct OpaqueMultiaddr(pub Vec<u8>);
199
200impl OpaqueMultiaddr {
201 pub fn new(vec: Vec<u8>) -> Self {
203 OpaqueMultiaddr(vec)
204 }
205}
206
207#[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#[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 pub const fn from_millis(millis: u64) -> Self {
224 Duration(millis)
225 }
226
227 pub fn millis(&self) -> u64 {
229 self.0
230 }
231}
232
233impl Timestamp {
234 pub fn from_unix_millis(millis: u64) -> Self {
236 Timestamp(millis)
237 }
238
239 pub fn add(&self, duration: Duration) -> Timestamp {
241 Timestamp(self.0.saturating_add(duration.0))
242 }
243
244 pub fn sub(&self, duration: Duration) -> Timestamp {
246 Timestamp(self.0.saturating_sub(duration.0))
247 }
248
249 pub fn diff(&self, other: &Self) -> Duration {
251 Duration(self.0.saturating_sub(other.0))
252 }
253
254 pub fn unix_millis(&self) -> u64 {
256 self.0
257 }
258}
259
260bitflags::bitflags! {
261 pub struct Capabilities: u32 {
263 const HTTP = 1 << 0;
265 const KEYSTORE = 1 << 2;
267 const RANDOMNESS = 1 << 3;
269 const NETWORK_STATE = 1 << 4;
271 const OFFCHAIN_DB_READ = 1 << 5;
273 const OFFCHAIN_DB_WRITE = 1 << 6;
275 const NODE_AUTHORIZATION = 1 << 7;
277 const TIME = 1 << 8;
279 }
280}
281
282pub trait Externalities: Send {
284 fn is_validator(&self) -> bool;
289
290 fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
292
293 fn timestamp(&mut self) -> Timestamp;
295
296 fn sleep_until(&mut self, deadline: Timestamp);
298
299 fn random_seed(&mut self) -> [u8; 32];
304
305 fn http_request_start(
314 &mut self,
315 method: &str,
316 uri: &str,
317 meta: &[u8],
318 ) -> Result<HttpRequestId, ()>;
319
320 fn http_request_add_header(
333 &mut self,
334 request_id: HttpRequestId,
335 name: &str,
336 value: &str,
337 ) -> Result<(), ()>;
338
339 fn http_request_write_body(
354 &mut self,
355 request_id: HttpRequestId,
356 chunk: &[u8],
357 deadline: Option<Timestamp>,
358 ) -> Result<(), HttpError>;
359
360 fn http_response_wait(
371 &mut self,
372 ids: &[HttpRequestId],
373 deadline: Option<Timestamp>,
374 ) -> Vec<HttpRequestStatus>;
375
376 fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)>;
386
387 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 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
499pub struct LimitedExternalities<T> {
501 capabilities: Capabilities,
502 externalities: T,
503}
504
505impl<T> LimitedExternalities<T> {
506 pub fn new(capabilities: Capabilities, externalities: T) -> Self {
508 Self { capabilities, externalities }
509 }
510
511 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 pub struct OffchainWorkerExt(Box<dyn Externalities>);
611}
612
613#[cfg(feature = "std")]
614impl OffchainWorkerExt {
615 pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
617 Self(Box::new(offchain))
618 }
619}
620
621pub trait DbExternalities: Send {
623 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]);
628
629 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]);
634
635 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 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 pub struct OffchainDbExt(Box<dyn DbExternalities>);
717}
718
719#[cfg(feature = "std")]
720impl OffchainDbExt {
721 pub fn new<O: DbExternalities + 'static>(offchain: O) -> Self {
723 Self(Box::new(offchain))
724 }
725}
726
727#[cfg(feature = "std")]
733pub trait TransactionPool {
734 fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()>;
738}
739
740#[cfg(feature = "std")]
741sp_externalities::decl_extension! {
742 pub struct TransactionPoolExt(Box<dyn TransactionPool + Send>);
744}
745
746#[cfg(feature = "std")]
747impl TransactionPoolExt {
748 pub fn new<O: TransactionPool + Send + 'static>(pool: O) -> Self {
750 Self(Box::new(pool))
751 }
752}
753
754#[derive(Debug, Clone, Hash, Eq, PartialEq)]
756pub enum OffchainOverlayedChange {
757 Remove,
759 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}