tp_runtime/offchain/
storage.rs1use tet_core::offchain::StorageKind;
21
22pub type StorageValue = StorageValueRef<'static>;
24
25pub struct StorageValueRef<'a> {
27 key: &'a [u8],
28 kind: StorageKind,
29}
30
31impl<'a> StorageValueRef<'a> {
32 pub fn persistent(key: &'a [u8]) -> Self {
34 Self { key, kind: StorageKind::PERSISTENT }
35 }
36
37 pub fn local(key: &'a [u8]) -> Self {
39 Self { key, kind: StorageKind::LOCAL }
40 }
41
42 pub fn set(&self, value: &impl codec::Encode) {
48 value.using_encoded(|val| {
49 tet_io::offchain::local_storage_set(self.kind, self.key, val)
50 })
51 }
52
53 pub fn clear(&mut self) {
55 tet_io::offchain::local_storage_clear(self.kind, self.key)
56 }
57
58 pub fn get<T: codec::Decode>(&self) -> Option<Option<T>> {
66 tet_io::offchain::local_storage_get(self.kind, self.key)
67 .map(|val| T::decode(&mut &*val).ok())
68 }
69
70 pub fn mutate<T, E, F>(&self, f: F) -> Result<Result<T, T>, E> where
79 T: codec::Codec,
80 F: FnOnce(Option<Option<T>>) -> Result<T, E>
81 {
82 let value = tet_io::offchain::local_storage_get(self.kind, self.key);
83 let decoded = value.as_deref().map(|mut v| T::decode(&mut v).ok());
84 let val = f(decoded)?;
85 let set = val.using_encoded(|new_val| {
86 tet_io::offchain::local_storage_compare_and_set(
87 self.kind,
88 self.key,
89 value,
90 new_val,
91 )
92 });
93
94 if set {
95 Ok(Ok(val))
96 } else {
97 Ok(Err(val))
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use tet_io::TestExternalities;
106 use tet_core::offchain::{
107 OffchainExt,
108 testing,
109 };
110
111 #[test]
112 fn should_set_and_get() {
113 let (offchain, state) = testing::TestOffchainExt::new();
114 let mut t = TestExternalities::default();
115 t.register_extension(OffchainExt::new(offchain));
116
117 t.execute_with(|| {
118 let val = StorageValue::persistent(b"testval");
119
120 assert_eq!(val.get::<u32>(), None);
121
122 val.set(&15_u32);
123
124 assert_eq!(val.get::<u32>(), Some(Some(15_u32)));
125 assert_eq!(val.get::<Vec<u8>>(), Some(None));
126 assert_eq!(
127 state.read().persistent_storage.get(b"testval"),
128 Some(vec![15_u8, 0, 0, 0])
129 );
130 })
131 }
132
133 #[test]
134 fn should_mutate() {
135 let (offchain, state) = testing::TestOffchainExt::new();
136 let mut t = TestExternalities::default();
137 t.register_extension(OffchainExt::new(offchain));
138
139 t.execute_with(|| {
140 let val = StorageValue::persistent(b"testval");
141
142 let result = val.mutate::<u32, (), _>(|val| {
143 assert_eq!(val, None);
144
145 Ok(16_u32)
146 });
147 assert_eq!(result, Ok(Ok(16_u32)));
148 assert_eq!(val.get::<u32>(), Some(Some(16_u32)));
149 assert_eq!(
150 state.read().persistent_storage.get(b"testval"),
151 Some(vec![16_u8, 0, 0, 0])
152 );
153
154 let res = val.mutate::<u32, (), _>(|val| {
156 assert_eq!(val, Some(Some(16_u32)));
157 Err(())
158 });
159 assert_eq!(res, Err(()));
160 })
161 }
162}