1use 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
32pub const STORAGE_PREFIX: &[u8] = b"storage";
34
35pub trait OffchainStorage: Clone + Send + Sync {
37 fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]);
39
40 fn remove(&mut self, prefix: &[u8], key: &[u8]);
42
43 fn get(&self, prefix: &[u8], key: &[u8]) -> Option<Vec<u8>>;
45
46 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#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61#[repr(C)]
62pub enum StorageKind {
63 PERSISTENT = 0_isize,
70 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#[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#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)]
120#[repr(C)]
121pub enum HttpError {
122 #[codec(index = 1)]
124 DeadlineReached = 0_isize,
125 #[codec(index = 2)]
127 IoError = 1_isize,
128 #[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#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)]
154pub enum HttpRequestStatus {
155 DeadlineReached,
160 IoError,
166 Invalid,
168 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#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
200#[cfg_attr(feature = "std", derive(Default))]
201pub struct OpaqueNetworkState {
202 pub peer_id: OpaquePeerId,
204 pub external_addresses: Vec<OpaqueMultiaddr>,
206}
207
208#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
210pub struct OpaqueMultiaddr(pub Vec<u8>);
211
212impl OpaqueMultiaddr {
213 pub fn new(vec: Vec<u8>) -> Self {
215 OpaqueMultiaddr(vec)
216 }
217}
218
219#[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#[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 pub const fn from_millis(millis: u64) -> Self {
244 Duration(millis)
245 }
246
247 pub fn millis(&self) -> u64 {
249 self.0
250 }
251}
252
253impl Timestamp {
254 pub fn from_unix_millis(millis: u64) -> Self {
256 Timestamp(millis)
257 }
258
259 pub fn add(&self, duration: Duration) -> Timestamp {
261 Timestamp(self.0.saturating_add(duration.0))
262 }
263
264 pub fn sub(&self, duration: Duration) -> Timestamp {
266 Timestamp(self.0.saturating_sub(duration.0))
267 }
268
269 pub fn diff(&self, other: &Self) -> Duration {
271 Duration(self.0.saturating_sub(other.0))
272 }
273
274 pub fn unix_millis(&self) -> u64 {
276 self.0
277 }
278}
279
280bitflags::bitflags! {
281 pub struct Capabilities: u32 {
283 const HTTP = 1 << 0;
285 const KEYSTORE = 1 << 2;
287 const RANDOMNESS = 1 << 3;
289 const NETWORK_STATE = 1 << 4;
291 const OFFCHAIN_DB_READ = 1 << 5;
293 const OFFCHAIN_DB_WRITE = 1 << 6;
295 const NODE_AUTHORIZATION = 1 << 7;
297 const TIME = 1 << 8;
299 }
300}
301
302pub trait Externalities: Send {
304 fn is_validator(&self) -> bool;
309
310 fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
312
313 fn timestamp(&mut self) -> Timestamp;
315
316 fn sleep_until(&mut self, deadline: Timestamp);
318
319 fn random_seed(&mut self) -> [u8; 32];
324
325 fn http_request_start(
334 &mut self,
335 method: &str,
336 uri: &str,
337 meta: &[u8],
338 ) -> Result<HttpRequestId, ()>;
339
340 fn http_request_add_header(
353 &mut self,
354 request_id: HttpRequestId,
355 name: &str,
356 value: &str,
357 ) -> Result<(), ()>;
358
359 fn http_request_write_body(
374 &mut self,
375 request_id: HttpRequestId,
376 chunk: &[u8],
377 deadline: Option<Timestamp>,
378 ) -> Result<(), HttpError>;
379
380 fn http_response_wait(
391 &mut self,
392 ids: &[HttpRequestId],
393 deadline: Option<Timestamp>,
394 ) -> Vec<HttpRequestStatus>;
395
396 fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)>;
406
407 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 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
519pub struct LimitedExternalities<T> {
521 capabilities: Capabilities,
522 externalities: T,
523}
524
525impl<T> LimitedExternalities<T> {
526 pub fn new(capabilities: Capabilities, externalities: T) -> Self {
528 Self { capabilities, externalities }
529 }
530
531 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 pub struct OffchainWorkerExt(Box<dyn Externalities>);
631}
632
633#[cfg(not(substrate_runtime))]
634impl OffchainWorkerExt {
635 pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
637 Self(Box::new(offchain))
638 }
639}
640
641pub trait DbExternalities: Send {
643 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]);
648
649 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]);
654
655 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 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 pub struct OffchainDbExt(Box<dyn DbExternalities>);
737}
738
739#[cfg(not(substrate_runtime))]
740impl OffchainDbExt {
741 pub fn new<O: DbExternalities + 'static>(offchain: O) -> Self {
743 Self(Box::new(offchain))
744 }
745}
746
747#[cfg(not(substrate_runtime))]
753pub trait TransactionPool {
754 fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()>;
758}
759
760#[cfg(not(substrate_runtime))]
761sp_externalities::decl_extension! {
762 pub struct TransactionPoolExt(Box<dyn TransactionPool + Send>);
764}
765
766#[cfg(not(substrate_runtime))]
767impl TransactionPoolExt {
768 pub fn new<O: TransactionPool + Send + 'static>(pool: O) -> Self {
770 Self(Box::new(pool))
771 }
772}
773
774#[derive(Debug, Clone, Hash, Eq, PartialEq)]
776pub enum OffchainOverlayedChange {
777 Remove,
779 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}