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>>> {
30 None
31 }
32
33 fn get_val_buffered(&mut self, output: PassFatPointerAndReadWrite<&mut [u8]>) -> u32 {
37 match self.extension::<OcwCustomExt>() {
38 Some(ext) => {
39 let encoded = ext.0.clone().encode();
40 let written = core::cmp::min(encoded.len(), output.len());
41 output[..written].copy_from_slice(&encoded[..written]);
42 written as u32
43 },
44 None => 0,
45 }
46 }
47}
48pub const MSA_ACCOUNT_LOCK_TIMEOUT_EXPIRATION_MS: u64 = 50;
50pub const MSA_ACCOUNT_LOCK_NAME_PREFIX: &[u8; 16] = b"Msa::ofw::lock::";
52pub const MSA_ACCOUNT_STORAGE_NAME_PREFIX: &[u8; 16] = b"Msa::ofw::keys::";
54pub fn get_msa_account_lock_name(msa_id: MessageSourceId) -> Vec<u8> {
56 let mut buff = [0u8; 30];
57 [MSA_ACCOUNT_LOCK_NAME_PREFIX, msa_id.numtoa(10, &mut buff)].concat()
58}
59pub fn get_msa_account_storage_key_name(msa_id: MessageSourceId) -> Vec<u8> {
61 let mut buff = [0u8; 30];
62 [MSA_ACCOUNT_STORAGE_NAME_PREFIX, msa_id.numtoa(10, &mut buff)].concat()
63}
64
65#[derive(Debug)]
67pub enum LockStatus {
68 Locked,
70 Released,
72}
73
74pub fn get_index_value<V: Decode + Debug>(key: &[u8]) -> Result<Option<V>, StorageRetrievalError> {
76 get_impl::<V>(key)
77}
78
79fn get_impl<V: Decode + Debug>(key: &[u8]) -> Result<Option<V>, StorageRetrievalError> {
81 let oci_mem = StorageValueRef::persistent(key);
82 match oci_mem.get::<V>() {
83 Ok(Some(data)) => Ok(Some(data)),
84 Ok(None) => Ok(None),
85 Err(_) => Err(StorageRetrievalError::Undecodable),
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use sp_core::offchain::{testing, OffchainDbExt, OffchainWorkerExt};
93 use sp_io::TestExternalities;
94
95 #[test]
96 fn get_msa_account_lock_name_should_return_expected_value() {
97 let msa_id: MessageSourceId = 2_000_000;
98 let result = get_msa_account_lock_name(msa_id);
99 assert_eq!(result, b"Msa::ofw::lock::2000000".to_vec());
100 }
101
102 #[test]
103 fn get_msa_account_storage_name_should_return_expected_value() {
104 let msa_id: MessageSourceId = 2_000_000;
105 let result = get_msa_account_storage_key_name(msa_id);
106 assert_eq!(result, b"Msa::ofw::keys::2000000".to_vec());
107 }
108
109 #[test]
110 fn get_index_for_not_set_should_return_none() {
111 let (offchain, _state) = testing::TestOffchainExt::new();
112 let mut t = TestExternalities::default();
113 t.register_extension(OffchainDbExt::new(offchain.clone()));
114 t.register_extension(OffchainWorkerExt::new(offchain));
115
116 t.execute_with(|| {
117 let key = b"my_key";
118 let result = get_index_value::<MessageSourceId>(key);
119 assert_eq!(result, Ok(None));
120 });
121 }
122
123 #[test]
124 fn get_index_for_set_should_return_expected() {
125 let (offchain, _state) = testing::TestOffchainExt::new();
127 let mut t = TestExternalities::default();
128 t.register_extension(OffchainDbExt::new(offchain.clone()));
129 t.register_extension(OffchainWorkerExt::new(offchain));
130
131 t.execute_with(|| {
132 let key = b"my_key1";
133 let msa_id: MessageSourceId = 1000000;
134 let oci_mem = StorageValueRef::persistent(key);
135 oci_mem.set(&msa_id);
136
137 let result = get_index_value::<MessageSourceId>(key);
139
140 assert_eq!(result, Ok(Some(msa_id)));
142 });
143 }
144
145 #[test]
146 fn get_index_for_not_decodable_should_return_error() {
147 let (offchain, _state) = testing::TestOffchainExt::new();
148 let mut t = TestExternalities::default();
149 t.register_extension(OffchainDbExt::new(offchain.clone()));
150 t.register_extension(OffchainWorkerExt::new(offchain));
151
152 #[derive(Debug, Decode, PartialEq)]
153 struct Testing {
154 pub a: u64,
155 pub b: u32,
156 pub c: u16,
157 }
158
159 t.execute_with(|| {
160 let key = b"my_key2";
162 let msa_id: MessageSourceId = 1000000;
163 let oci_mem = StorageValueRef::persistent(key);
164 oci_mem.set(&msa_id);
165
166 let result = get_index_value::<Testing>(key);
168
169 assert_eq!(result, Err(StorageRetrievalError::Undecodable));
171 });
172 }
173}