@@ -28,6 +28,25 @@ pub struct StorageValueRef<'a> {
2828 kind : StorageKind ,
2929}
3030
31+ /// Reason for not being able to provide the stored value
32+ #[ derive( Debug , PartialEq , Eq ) ]
33+ pub enum StorageRetrievalError {
34+ /// Value found but undecodable
35+ Undecodable ,
36+ }
37+
38+ /// Possible errors when mutating a storage value.
39+ #[ derive( Debug , PartialEq , Eq ) ]
40+ pub enum MutateStorageError < T , E > {
41+ /// The underlying db failed to update due to a concurrent modification.
42+ /// Contains the new value that was not stored.
43+ ConcurrentModification ( T ) ,
44+ /// The function given to us to create the value to be stored failed.
45+ /// May be used to signal that having looked at the existing value,
46+ /// they don't want to mutate it.
47+ ValueFunctionFailed ( E )
48+ }
49+
3150impl < ' a > StorageValueRef < ' a > {
3251 /// Create a new reference to a value in the persistent local storage.
3352 pub fn persistent ( key : & ' a [ u8 ] ) -> Self {
@@ -58,30 +77,40 @@ impl<'a> StorageValueRef<'a> {
5877 /// Retrieve & decode the value from storage.
5978 ///
6079 /// Note that if you want to do some checks based on the value
61- /// and write changes after that you should rather be using `mutate`.
80+ /// and write changes after that, you should rather be using `mutate`.
6281 ///
63- /// The function returns `None` if the value was not found in storage,
64- /// otherwise a decoding of the value to requested type .
65- pub fn get < T : codec:: Decode > ( & self ) -> Option < Option < T > > {
82+ /// Returns the value if stored.
83+ /// Returns an error if the value could not be decoded .
84+ pub fn get < T : codec:: Decode > ( & self ) -> Result < Option < T > , StorageRetrievalError > {
6685 sp_io:: offchain:: local_storage_get ( self . kind , self . key )
67- . map ( |val| T :: decode ( & mut & * val) . ok ( ) )
86+ . map ( |val| T :: decode ( & mut & * val)
87+ . map_err ( |_| StorageRetrievalError :: Undecodable ) )
88+ . transpose ( )
6889 }
6990
70- /// Retrieve & decode the value and set it to a new one atomically.
91+ /// Retrieve & decode the current value and set it to a new value atomically.
92+ ///
93+ /// Function `mutate_val` takes as input the current value and should
94+ /// return a new value that is attempted to be written to storage.
7195 ///
72- /// Function `f` should return a new value that we should attempt to write to storage.
7396 /// This function returns:
74- /// 1. `Ok(Ok(T) )` in case the value has been successfully set.
75- /// 2. `Ok( Err(T))` in case the value was calculated by the passed closure `f`,
76- /// but it could not be stored.
77- /// 3. `Err(_) ` in case `f ` returns an error.
78- pub fn mutate < T , E , F > ( & self , f : F ) -> Result < Result < T , T > , E > where
97+ /// 1. `Ok(T )` in case the value has been successfully set.
98+ /// 2. `Err(MutateStorageError::ConcurrentModification( T))` in case the value was calculated
99+ /// by the passed closure `mutate_val`, but it could not be stored.
100+ /// 3. `Err(MutateStorageError::ValueFunctionFailed(_)) ` in case `mutate_val ` returns an error.
101+ pub fn mutate < T , E , F > ( & self , mutate_val : F ) -> Result < T , MutateStorageError < T , E > > where
79102 T : codec:: Codec ,
80- F : FnOnce ( Option < Option < T > > ) -> Result < T , E >
103+ F : FnOnce ( Result < Option < T > , StorageRetrievalError > ) -> Result < T , E >
81104 {
82105 let value = sp_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) ?;
106+ let decoded = value. as_deref ( )
107+ . map ( |mut bytes| {
108+ T :: decode ( & mut bytes)
109+ . map_err ( |_| StorageRetrievalError :: Undecodable )
110+ } ) . transpose ( ) ;
111+
112+ let val = mutate_val ( decoded) . map_err ( |err| MutateStorageError :: ValueFunctionFailed ( err) ) ?;
113+
85114 let set = val. using_encoded ( |new_val| {
86115 sp_io:: offchain:: local_storage_compare_and_set (
87116 self . kind ,
@@ -90,11 +119,10 @@ impl<'a> StorageValueRef<'a> {
90119 new_val,
91120 )
92121 } ) ;
93-
94122 if set {
95- Ok ( Ok ( val) )
123+ Ok ( val)
96124 } else {
97- Ok ( Err ( val) )
125+ Err ( MutateStorageError :: ConcurrentModification ( val) )
98126 }
99127 }
100128}
@@ -117,12 +145,12 @@ mod tests {
117145 t. execute_with ( || {
118146 let val = StorageValue :: persistent ( b"testval" ) ;
119147
120- assert_eq ! ( val. get:: <u32 >( ) , None ) ;
148+ assert_eq ! ( val. get:: <u32 >( ) , Ok ( None ) ) ;
121149
122150 val. set ( & 15_u32 ) ;
123151
124- assert_eq ! ( val. get:: <u32 >( ) , Some ( Some ( 15_u32 ) ) ) ;
125- assert_eq ! ( val. get:: <Vec <u8 >>( ) , Some ( None ) ) ;
152+ assert_eq ! ( val. get:: <u32 >( ) , Ok ( Some ( 15_u32 ) ) ) ;
153+ assert_eq ! ( val. get:: <Vec <u8 >>( ) , Err ( StorageRetrievalError :: Undecodable ) ) ;
126154 assert_eq ! (
127155 state. read( ) . persistent_storage. get( b"testval" ) ,
128156 Some ( vec![ 15_u8 , 0 , 0 , 0 ] )
@@ -140,23 +168,23 @@ mod tests {
140168 let val = StorageValue :: persistent ( b"testval" ) ;
141169
142170 let result = val. mutate :: < u32 , ( ) , _ > ( |val| {
143- assert_eq ! ( val, None ) ;
171+ assert_eq ! ( val, Ok ( None ) ) ;
144172
145173 Ok ( 16_u32 )
146174 } ) ;
147- assert_eq ! ( result, Ok ( Ok ( 16_u32 ) ) ) ;
148- assert_eq ! ( val. get:: <u32 >( ) , Some ( Some ( 16_u32 ) ) ) ;
175+ assert_eq ! ( result, Ok ( 16_u32 ) ) ;
176+ assert_eq ! ( val. get:: <u32 >( ) , Ok ( Some ( 16_u32 ) ) ) ;
149177 assert_eq ! (
150178 state. read( ) . persistent_storage. get( b"testval" ) ,
151179 Some ( vec![ 16_u8 , 0 , 0 , 0 ] )
152180 ) ;
153181
154182 // mutate again, but this time early-exit.
155183 let res = val. mutate :: < u32 , ( ) , _ > ( |val| {
156- assert_eq ! ( val, Some ( Some ( 16_u32 ) ) ) ;
184+ assert_eq ! ( val, Ok ( Some ( 16_u32 ) ) ) ;
157185 Err ( ( ) )
158186 } ) ;
159- assert_eq ! ( res, Err ( ( ) ) ) ;
187+ assert_eq ! ( res, Err ( MutateStorageError :: ValueFunctionFailed ( ( ) ) ) ) ;
160188 } )
161189 }
162190}
0 commit comments