common_primitives/
offchain.rs1use crate::msa::MessageSourceId;
2use numtoa::NumToA;
3use parity_scale_codec::{Decode, Encode};
4#[cfg(feature = "std")]
5use sp_externalities::ExternalitiesExt;
6use sp_runtime::offchain::storage::{StorageRetrievalError, StorageValueRef};
7extern crate alloc;
8use alloc::vec::Vec;
9use core::fmt::Debug;
10use sp_runtime_interface::{
11 pass_by::{AllocateAndReturnByCodec, PassFatPointerAndReadWrite},
12 runtime_interface,
13};
14
15#[cfg(feature = "std")]
16sp_externalities::decl_extension! {
17 pub struct OcwCustomExt (
19 Vec<u8>
21 );
22}
23
24#[runtime_interface]
26pub trait Custom: ExternalitiesExt {
27 fn get_val(&mut self) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
29 self.extension::<OcwCustomExt>().map(|ext| ext.0.clone())
30 }
31
32 fn get_val_buffered(&mut self, output: PassFatPointerAndReadWrite<&mut [u8]>) -> u32 {
36 match self.extension::<OcwCustomExt>() {
37 Some(ext) => {
38 let encoded = ext.0.clone().encode();
39 let written = core::cmp::min(encoded.len(), output.len());
40 output[..written].copy_from_slice(&encoded[..written]);
41 written as u32
42 },
43 None => 0,
44 }
45 }
46}
47pub const MSA_ACCOUNT_LOCK_TIMEOUT_EXPIRATION_MS: u64 = 50;
49pub const MSA_ACCOUNT_LOCK_NAME_PREFIX: &[u8; 16] = b"Msa::ofw::lock::";
51pub const MSA_ACCOUNT_STORAGE_NAME_PREFIX: &[u8; 16] = b"Msa::ofw::keys::";
53pub fn get_msa_account_lock_name(msa_id: MessageSourceId) -> Vec<u8> {
55 let mut buff = [0u8; 30];
56 [MSA_ACCOUNT_LOCK_NAME_PREFIX, msa_id.numtoa(10, &mut buff)].concat()
57}
58pub fn get_msa_account_storage_key_name(msa_id: MessageSourceId) -> Vec<u8> {
60 let mut buff = [0u8; 30];
61 [MSA_ACCOUNT_STORAGE_NAME_PREFIX, msa_id.numtoa(10, &mut buff)].concat()
62}
63
64#[derive(Debug)]
66pub enum LockStatus {
67 Locked,
69 Released,
71}
72
73pub fn get_index_value<V: Decode + Debug>(key: &[u8]) -> Result<Option<V>, StorageRetrievalError> {
75 get_impl::<V>(key)
76}
77
78fn get_impl<V: Decode + Debug>(key: &[u8]) -> Result<Option<V>, StorageRetrievalError> {
80 let oci_mem = StorageValueRef::persistent(key);
81 match oci_mem.get::<V>() {
82 Ok(Some(data)) => Ok(Some(data)),
83 Ok(None) => Ok(None),
84 Err(_) => Err(StorageRetrievalError::Undecodable),
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use sp_core::offchain::{testing, OffchainDbExt, OffchainWorkerExt};
92 use sp_io::TestExternalities;
93
94 #[test]
95 fn get_msa_account_lock_name_should_return_expected_value() {
96 let msa_id: MessageSourceId = 2_000_000;
97 let result = get_msa_account_lock_name(msa_id);
98 assert_eq!(result, b"Msa::ofw::lock::2000000".to_vec());
99 }
100
101 #[test]
102 fn get_msa_account_storage_name_should_return_expected_value() {
103 let msa_id: MessageSourceId = 2_000_000;
104 let result = get_msa_account_storage_key_name(msa_id);
105 assert_eq!(result, b"Msa::ofw::keys::2000000".to_vec());
106 }
107
108 #[test]
109 fn get_index_for_not_set_should_return_none() {
110 let (offchain, _state) = testing::TestOffchainExt::new();
111 let mut t = TestExternalities::default();
112 t.register_extension(OffchainDbExt::new(offchain.clone()));
113 t.register_extension(OffchainWorkerExt::new(offchain));
114
115 t.execute_with(|| {
116 let key = b"my_key";
117 let result = get_index_value::<MessageSourceId>(key);
118 assert_eq!(result, Ok(None));
119 });
120 }
121
122 #[test]
123 fn get_index_for_set_should_return_expected() {
124 let (offchain, _state) = testing::TestOffchainExt::new();
126 let mut t = TestExternalities::default();
127 t.register_extension(OffchainDbExt::new(offchain.clone()));
128 t.register_extension(OffchainWorkerExt::new(offchain));
129
130 t.execute_with(|| {
131 let key = b"my_key1";
132 let msa_id: MessageSourceId = 1000000;
133 let oci_mem = StorageValueRef::persistent(key);
134 oci_mem.set(&msa_id);
135
136 let result = get_index_value::<MessageSourceId>(key);
138
139 assert_eq!(result, Ok(Some(msa_id)));
141 });
142 }
143
144 #[test]
145 fn get_index_for_not_decodable_should_return_error() {
146 let (offchain, _state) = testing::TestOffchainExt::new();
147 let mut t = TestExternalities::default();
148 t.register_extension(OffchainDbExt::new(offchain.clone()));
149 t.register_extension(OffchainWorkerExt::new(offchain));
150
151 #[derive(Debug, Decode, PartialEq)]
152 struct Testing {
153 pub a: u64,
154 pub b: u32,
155 pub c: u16,
156 }
157
158 t.execute_with(|| {
159 let key = b"my_key2";
161 let msa_id: MessageSourceId = 1000000;
162 let oci_mem = StorageValueRef::persistent(key);
163 oci_mem.set(&msa_id);
164
165 let result = get_index_value::<Testing>(key);
167
168 assert_eq!(result, Err(StorageRetrievalError::Undecodable));
170 });
171 }
172}