1use codec::{Encode, Decode};
21use tetcore_std::{prelude::{Vec, Box}, convert::TryFrom};
22use crate::{OpaquePeerId, RuntimeDebug};
23use tp_runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum};
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 : &'static [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, Encode, Decode, RuntimeDebug, PassByEnum)]
60#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
61#[repr(C)]
62pub enum StorageKind {
63 PERSISTENT = 1,
70 LOCAL = 2,
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 u8 as u32
92 }
93}
94
95#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, PassByInner)]
97#[cfg_attr(feature = "std", derive(Hash))]
98pub struct HttpRequestId(pub u16);
99
100impl From<HttpRequestId> for u32 {
101 fn from(c: HttpRequestId) -> Self {
102 c.0 as u32
103 }
104}
105
106#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByEnum)]
108#[repr(C)]
109pub enum HttpError {
110 DeadlineReached = 1,
112 IoError = 2,
114 Invalid = 3,
116}
117
118impl TryFrom<u32> for HttpError {
119 type Error = ();
120
121 fn try_from(error: u32) -> Result<Self, Self::Error> {
122 match error {
123 e if e == HttpError::DeadlineReached as u8 as u32 => Ok(HttpError::DeadlineReached),
124 e if e == HttpError::IoError as u8 as u32 => Ok(HttpError::IoError),
125 e if e == HttpError::Invalid as u8 as u32 => Ok(HttpError::Invalid),
126 _ => Err(())
127 }
128 }
129}
130
131impl From<HttpError> for u32 {
132 fn from(c: HttpError) -> Self {
133 c as u8 as u32
134 }
135}
136
137#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByCodec)]
139pub enum HttpRequestStatus {
140 DeadlineReached,
145 IoError,
151 Invalid,
153 Finished(u16),
155}
156
157impl From<HttpRequestStatus> for u32 {
158 fn from(status: HttpRequestStatus) -> Self {
159 match status {
160 HttpRequestStatus::Invalid => 0,
161 HttpRequestStatus::DeadlineReached => 10,
162 HttpRequestStatus::IoError => 20,
163 HttpRequestStatus::Finished(code) => u32::from(code),
164 }
165 }
166}
167
168impl TryFrom<u32> for HttpRequestStatus {
169 type Error = ();
170
171 fn try_from(status: u32) -> Result<Self, Self::Error> {
172 match status {
173 0 => Ok(HttpRequestStatus::Invalid),
174 10 => Ok(HttpRequestStatus::DeadlineReached),
175 20 => Ok(HttpRequestStatus::IoError),
176 100..=999 => u16::try_from(status).map(HttpRequestStatus::Finished).map_err(|_| ()),
177 _ => Err(()),
178 }
179 }
180}
181
182#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByCodec)]
185#[cfg_attr(feature = "std", derive(Default))]
186pub struct OpaqueNetworkState {
187 pub peer_id: OpaquePeerId,
189 pub external_addresses: Vec<OpaqueMultiaddr>,
191}
192
193#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)]
195pub struct OpaqueMultiaddr(pub Vec<u8>);
196
197impl OpaqueMultiaddr {
198 pub fn new(vec: Vec<u8>) -> Self {
200 OpaqueMultiaddr(vec)
201 }
202}
203
204#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
206pub struct Timestamp(u64);
207
208#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
210pub struct Duration(u64);
211
212impl Duration {
213 pub const fn from_millis(millis: u64) -> Self {
215 Duration(millis)
216 }
217
218 pub fn millis(&self) -> u64 {
220 self.0
221 }
222}
223
224impl Timestamp {
225 pub fn from_unix_millis(millis: u64) -> Self {
227 Timestamp(millis)
228 }
229
230 pub fn add(&self, duration: Duration) -> Timestamp {
232 Timestamp(self.0.saturating_add(duration.0))
233 }
234
235 pub fn sub(&self, duration: Duration) -> Timestamp {
237 Timestamp(self.0.saturating_sub(duration.0))
238 }
239
240 pub fn diff(&self, other: &Self) -> Duration {
242 Duration(self.0.saturating_sub(other.0))
243 }
244
245 pub fn unix_millis(&self) -> u64 {
247 self.0
248 }
249}
250
251#[derive(Debug, PartialEq, Eq, Clone, Copy)]
253#[repr(u8)]
254pub enum Capability {
255 TransactionPool = 1,
257 Http = 2,
259 Keystore = 4,
261 Randomness = 8,
263 NetworkState = 16,
265 OffchainWorkerDbRead = 32,
267 OffchainWorkerDbWrite = 64,
269 NodeAuthorization = 128,
271}
272
273#[derive(Debug, PartialEq, Eq, Clone, Copy)]
275pub struct Capabilities(u8);
276
277impl Capabilities {
278 pub fn none() -> Self {
280 Self(0)
281 }
282
283 pub fn all() -> Self {
285 Self(u8::max_value())
286 }
287
288 pub fn rich_offchain_call() -> Self {
293 [
294 Capability::TransactionPool,
295 Capability::Keystore,
296 Capability::OffchainWorkerDbRead,
297 ][..].into()
298 }
299
300 pub fn has(&self, capability: Capability) -> bool {
302 self.0 & capability as u8 != 0
303 }
304
305 pub fn has_all(&self) -> bool {
307 self == &Capabilities::all()
308 }
309}
310
311impl<'a> From<&'a [Capability]> for Capabilities {
312 fn from(list: &'a [Capability]) -> Self {
313 Capabilities(list.iter().fold(0_u8, |a, b| a | *b as u8))
314 }
315}
316
317pub trait Externalities: Send {
319 fn is_validator(&self) -> bool;
324
325 fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
327
328 fn timestamp(&mut self) -> Timestamp;
330
331 fn sleep_until(&mut self, deadline: Timestamp);
333
334 fn random_seed(&mut self) -> [u8; 32];
339
340 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]);
345
346 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]);
351
352 fn local_storage_compare_and_set(
362 &mut self,
363 kind: StorageKind,
364 key: &[u8],
365 old_value: Option<&[u8]>,
366 new_value: &[u8],
367 ) -> bool;
368
369 fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>>;
375
376 fn http_request_start(
386 &mut self,
387 method: &str,
388 uri: &str,
389 meta: &[u8]
390 ) -> Result<HttpRequestId, ()>;
391
392 fn http_request_add_header(
406 &mut self,
407 request_id: HttpRequestId,
408 name: &str,
409 value: &str
410 ) -> Result<(), ()>;
411
412 fn http_request_write_body(
428 &mut self,
429 request_id: HttpRequestId,
430 chunk: &[u8],
431 deadline: Option<Timestamp>
432 ) -> Result<(), HttpError>;
433
434 fn http_response_wait(
445 &mut self,
446 ids: &[HttpRequestId],
447 deadline: Option<Timestamp>
448 ) -> Vec<HttpRequestStatus>;
449
450 fn http_response_headers(
460 &mut self,
461 request_id: HttpRequestId
462 ) -> Vec<(Vec<u8>, Vec<u8>)>;
463
464 fn http_response_read_body(
484 &mut self,
485 request_id: HttpRequestId,
486 buffer: &mut [u8],
487 deadline: Option<Timestamp>
488 ) -> Result<usize, HttpError>;
489
490 fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool);
501}
502
503impl<T: Externalities + ?Sized> Externalities for Box<T> {
504 fn is_validator(&self) -> bool {
505 (& **self).is_validator()
506 }
507
508 fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
509 (& **self).network_state()
510 }
511
512 fn timestamp(&mut self) -> Timestamp {
513 (&mut **self).timestamp()
514 }
515
516 fn sleep_until(&mut self, deadline: Timestamp) {
517 (&mut **self).sleep_until(deadline)
518 }
519
520 fn random_seed(&mut self) -> [u8; 32] {
521 (&mut **self).random_seed()
522 }
523
524 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
525 (&mut **self).local_storage_set(kind, key, value)
526 }
527
528 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
529 (&mut **self).local_storage_clear(kind, key)
530 }
531
532 fn local_storage_compare_and_set(
533 &mut self,
534 kind: StorageKind,
535 key: &[u8],
536 old_value: Option<&[u8]>,
537 new_value: &[u8],
538 ) -> bool {
539 (&mut **self).local_storage_compare_and_set(kind, key, old_value, new_value)
540 }
541
542 fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
543 (&mut **self).local_storage_get(kind, key)
544 }
545
546 fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
547 (&mut **self).http_request_start(method, uri, meta)
548 }
549
550 fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
551 (&mut **self).http_request_add_header(request_id, name, value)
552 }
553
554 fn http_request_write_body(
555 &mut self,
556 request_id: HttpRequestId,
557 chunk: &[u8],
558 deadline: Option<Timestamp>
559 ) -> Result<(), HttpError> {
560 (&mut **self).http_request_write_body(request_id, chunk, deadline)
561 }
562
563 fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
564 (&mut **self).http_response_wait(ids, deadline)
565 }
566
567 fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
568 (&mut **self).http_response_headers(request_id)
569 }
570
571 fn http_response_read_body(
572 &mut self,
573 request_id: HttpRequestId,
574 buffer: &mut [u8],
575 deadline: Option<Timestamp>
576 ) -> Result<usize, HttpError> {
577 (&mut **self).http_response_read_body(request_id, buffer, deadline)
578 }
579
580 fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool) {
581 (&mut **self).set_authorized_nodes(nodes, authorized_only)
582 }
583}
584
585pub struct LimitedExternalities<T> {
587 capabilities: Capabilities,
588 externalities: T,
589}
590
591impl<T> LimitedExternalities<T> {
592 pub fn new(capabilities: Capabilities, externalities: T) -> Self {
594 Self {
595 capabilities,
596 externalities,
597 }
598 }
599
600 fn check(&self, capability: Capability, name: &'static str) {
604 if !self.capabilities.has(capability) {
605 panic!("Accessing a forbidden API: {}. No: {:?} capability.", name, capability);
606 }
607 }
608}
609
610impl<T: Externalities> Externalities for LimitedExternalities<T> {
611 fn is_validator(&self) -> bool {
612 self.check(Capability::Keystore, "is_validator");
613 self.externalities.is_validator()
614 }
615
616 fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
617 self.check(Capability::NetworkState, "network_state");
618 self.externalities.network_state()
619 }
620
621 fn timestamp(&mut self) -> Timestamp {
622 self.check(Capability::Http, "timestamp");
623 self.externalities.timestamp()
624 }
625
626 fn sleep_until(&mut self, deadline: Timestamp) {
627 self.check(Capability::Http, "sleep_until");
628 self.externalities.sleep_until(deadline)
629 }
630
631 fn random_seed(&mut self) -> [u8; 32] {
632 self.check(Capability::Randomness, "random_seed");
633 self.externalities.random_seed()
634 }
635
636 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
637 self.check(Capability::OffchainWorkerDbWrite, "local_storage_set");
638 self.externalities.local_storage_set(kind, key, value)
639 }
640
641 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
642 self.check(Capability::OffchainWorkerDbWrite, "local_storage_clear");
643 self.externalities.local_storage_clear(kind, key)
644 }
645
646 fn local_storage_compare_and_set(
647 &mut self,
648 kind: StorageKind,
649 key: &[u8],
650 old_value: Option<&[u8]>,
651 new_value: &[u8],
652 ) -> bool {
653 self.check(Capability::OffchainWorkerDbWrite, "local_storage_compare_and_set");
654 self.externalities.local_storage_compare_and_set(kind, key, old_value, new_value)
655 }
656
657 fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
658 self.check(Capability::OffchainWorkerDbRead, "local_storage_get");
659 self.externalities.local_storage_get(kind, key)
660 }
661
662 fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
663 self.check(Capability::Http, "http_request_start");
664 self.externalities.http_request_start(method, uri, meta)
665 }
666
667 fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
668 self.check(Capability::Http, "http_request_add_header");
669 self.externalities.http_request_add_header(request_id, name, value)
670 }
671
672 fn http_request_write_body(
673 &mut self,
674 request_id: HttpRequestId,
675 chunk: &[u8],
676 deadline: Option<Timestamp>
677 ) -> Result<(), HttpError> {
678 self.check(Capability::Http, "http_request_write_body");
679 self.externalities.http_request_write_body(request_id, chunk, deadline)
680 }
681
682 fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
683 self.check(Capability::Http, "http_response_wait");
684 self.externalities.http_response_wait(ids, deadline)
685 }
686
687 fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
688 self.check(Capability::Http, "http_response_headers");
689 self.externalities.http_response_headers(request_id)
690 }
691
692 fn http_response_read_body(
693 &mut self,
694 request_id: HttpRequestId,
695 buffer: &mut [u8],
696 deadline: Option<Timestamp>
697 ) -> Result<usize, HttpError> {
698 self.check(Capability::Http, "http_response_read_body");
699 self.externalities.http_response_read_body(request_id, buffer, deadline)
700 }
701
702 fn set_authorized_nodes(&mut self, nodes: Vec<OpaquePeerId>, authorized_only: bool) {
703 self.check(Capability::NodeAuthorization, "set_authorized_nodes");
704 self.externalities.set_authorized_nodes(nodes, authorized_only)
705 }
706}
707
708#[cfg(feature = "std")]
709externalities::decl_extension! {
710 pub struct OffchainExt(Box<dyn Externalities>);
712}
713
714#[cfg(feature = "std")]
715impl OffchainExt {
716 pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
718 Self(Box::new(offchain))
719 }
720}
721
722#[cfg(feature = "std")]
728pub trait TransactionPool {
729 fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()>;
733}
734
735#[cfg(feature = "std")]
736externalities::decl_extension! {
737 pub struct TransactionPoolExt(Box<dyn TransactionPool + Send>);
739}
740
741#[cfg(feature = "std")]
742impl TransactionPoolExt {
743 pub fn new<O: TransactionPool + Send + 'static>(pool: O) -> Self {
745 Self(Box::new(pool))
746 }
747}
748
749#[derive(Debug, Clone, Hash, Eq, PartialEq)]
751pub enum OffchainOverlayedChange {
752 Remove,
754 SetValue(Vec<u8>),
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761
762 #[test]
763 fn timestamp_ops() {
764 let t = Timestamp(5);
765 assert_eq!(t.add(Duration::from_millis(10)), Timestamp(15));
766 assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0));
767 assert_eq!(t.diff(&Timestamp(3)), Duration(2));
768 }
769
770 #[test]
771 fn capabilities() {
772 let none = Capabilities::none();
773 let all = Capabilities::all();
774 let some = Capabilities::from(&[Capability::Keystore, Capability::Randomness][..]);
775
776 assert!(!none.has(Capability::Keystore));
777 assert!(all.has(Capability::Keystore));
778 assert!(some.has(Capability::Keystore));
779 assert!(!none.has(Capability::TransactionPool));
780 assert!(all.has(Capability::TransactionPool));
781 assert!(!some.has(Capability::TransactionPool));
782 }
783}