17
17
18
18
//! Stuff to do with the runtime's storage.
19
19
20
- pub use self :: types:: StorageEntryMetadataBuilder ;
21
20
use crate :: {
22
21
hash:: { ReversibleStorageHasher , StorageHasher } ,
23
22
storage:: types:: {
@@ -27,12 +26,14 @@ use crate::{
27
26
} ;
28
27
use codec:: { Decode , Encode , EncodeLike , FullCodec , FullEncode } ;
29
28
use sp_core:: storage:: ChildInfo ;
30
- pub use sp_runtime:: TransactionOutcome ;
31
- use sp_runtime:: {
32
- generic:: { Digest , DigestItem } ,
33
- DispatchError , TransactionalError ,
34
- } ;
29
+ use sp_runtime:: generic:: { Digest , DigestItem } ;
35
30
use sp_std:: prelude:: * ;
31
+
32
+ pub use self :: {
33
+ transactional:: { with_transaction, with_transaction_unchecked} ,
34
+ types:: StorageEntryMetadataBuilder ,
35
+ } ;
36
+ pub use sp_runtime:: TransactionOutcome ;
36
37
pub use types:: Key ;
37
38
38
39
pub mod bounded_btree_map;
@@ -43,140 +44,11 @@ pub mod child;
43
44
pub mod generator;
44
45
pub mod hashed;
45
46
pub mod migration;
47
+ pub mod transactional;
46
48
pub mod types;
47
49
pub mod unhashed;
48
50
pub mod weak_bounded_vec;
49
51
50
- mod transaction_level_tracker {
51
- type Layer = u32 ;
52
- const TRANSACTION_LEVEL_KEY : & ' static [ u8 ] = b":transaction_level:" ;
53
- const TRANSACTIONAL_LIMIT : Layer = 255 ;
54
-
55
- pub fn get_transaction_level ( ) -> Layer {
56
- crate :: storage:: unhashed:: get_or_default :: < Layer > ( TRANSACTION_LEVEL_KEY )
57
- }
58
-
59
- fn set_transaction_level ( level : & Layer ) {
60
- crate :: storage:: unhashed:: put :: < Layer > ( TRANSACTION_LEVEL_KEY , level) ;
61
- }
62
-
63
- fn kill_transaction_level ( ) {
64
- crate :: storage:: unhashed:: kill ( TRANSACTION_LEVEL_KEY ) ;
65
- }
66
-
67
- /// Increments the transaction level. Returns an error if levels go past the limit.
68
- ///
69
- /// Returns a guard that when dropped decrements the transaction level automatically.
70
- pub fn inc_transaction_level ( ) -> Result < StorageLayerGuard , ( ) > {
71
- let existing_levels = get_transaction_level ( ) ;
72
- if existing_levels >= TRANSACTIONAL_LIMIT {
73
- return Err ( ( ) )
74
- }
75
- // Cannot overflow because of check above.
76
- set_transaction_level ( & ( existing_levels + 1 ) ) ;
77
- Ok ( StorageLayerGuard )
78
- }
79
-
80
- fn dec_transaction_level ( ) {
81
- let existing_levels = get_transaction_level ( ) ;
82
- if existing_levels == 0 {
83
- log:: warn!(
84
- "We are underflowing with calculating transactional levels. Not great, but let's not panic..." ,
85
- ) ;
86
- } else if existing_levels == 1 {
87
- // Don't leave any trace of this storage item.
88
- kill_transaction_level ( ) ;
89
- } else {
90
- // Cannot underflow because of checks above.
91
- set_transaction_level ( & ( existing_levels - 1 ) ) ;
92
- }
93
- }
94
-
95
- pub fn is_transactional ( ) -> bool {
96
- get_transaction_level ( ) > 0
97
- }
98
-
99
- pub struct StorageLayerGuard ;
100
-
101
- impl Drop for StorageLayerGuard {
102
- fn drop ( & mut self ) {
103
- dec_transaction_level ( )
104
- }
105
- }
106
- }
107
-
108
- /// Check if the current call is within a transactional layer.
109
- pub fn is_transactional ( ) -> bool {
110
- transaction_level_tracker:: is_transactional ( )
111
- }
112
-
113
- /// Execute the supplied function in a new storage transaction.
114
- ///
115
- /// All changes to storage performed by the supplied function are discarded if the returned
116
- /// outcome is `TransactionOutcome::Rollback`.
117
- ///
118
- /// Transactions can be nested up to `TRANSACTIONAL_LIMIT` times; more than that will result in an
119
- /// error.
120
- ///
121
- /// Commits happen to the parent transaction.
122
- pub fn with_transaction < T , E > ( f : impl FnOnce ( ) -> TransactionOutcome < Result < T , E > > ) -> Result < T , E >
123
- where
124
- E : From < DispatchError > ,
125
- {
126
- use sp_io:: storage:: { commit_transaction, rollback_transaction, start_transaction} ;
127
- use TransactionOutcome :: * ;
128
-
129
- let _guard = transaction_level_tracker:: inc_transaction_level ( )
130
- . map_err ( |( ) | TransactionalError :: LimitReached . into ( ) ) ?;
131
-
132
- start_transaction ( ) ;
133
-
134
- match f ( ) {
135
- Commit ( res) => {
136
- commit_transaction ( ) ;
137
- res
138
- } ,
139
- Rollback ( res) => {
140
- rollback_transaction ( ) ;
141
- res
142
- } ,
143
- }
144
- }
145
-
146
- /// Same as [`with_transaction`] but without a limit check on nested transactional layers.
147
- ///
148
- /// This is mostly for backwards compatibility before there was a transactional layer limit.
149
- /// It is recommended to only use [`with_transaction`] to avoid users from generating too many
150
- /// transactional layers.
151
- pub fn with_transaction_unchecked < R > ( f : impl FnOnce ( ) -> TransactionOutcome < R > ) -> R {
152
- use sp_io:: storage:: { commit_transaction, rollback_transaction, start_transaction} ;
153
- use TransactionOutcome :: * ;
154
-
155
- let maybe_guard = transaction_level_tracker:: inc_transaction_level ( ) ;
156
-
157
- if maybe_guard. is_err ( ) {
158
- log:: warn!(
159
- "The transactional layer limit has been reached, and new transactional layers are being
160
- spawned with `with_transaction_unchecked`. This could be caused by someone trying to
161
- attack your chain, and you should investigate usage of `with_transaction_unchecked` and
162
- potentially migrate to `with_transaction`, which enforces a transactional limit." ,
163
- ) ;
164
- }
165
-
166
- start_transaction ( ) ;
167
-
168
- match f ( ) {
169
- Commit ( res) => {
170
- commit_transaction ( ) ;
171
- res
172
- } ,
173
- Rollback ( res) => {
174
- rollback_transaction ( ) ;
175
- res
176
- } ,
177
- }
178
- }
179
-
180
52
/// A trait for working with macro-generated storage values under the substrate storage API.
181
53
///
182
54
/// Details on implementation can be found at [`generator::StorageValue`].
@@ -1473,13 +1345,12 @@ pub fn storage_prefix(pallet_name: &[u8], storage_name: &[u8]) -> [u8; 32] {
1473
1345
#[ cfg( test) ]
1474
1346
mod test {
1475
1347
use super :: * ;
1476
- use crate :: { assert_noop , assert_ok, hash:: Identity , Twox128 } ;
1348
+ use crate :: { assert_ok, hash:: Identity , Twox128 } ;
1477
1349
use bounded_vec:: BoundedVec ;
1478
1350
use frame_support:: traits:: ConstU32 ;
1479
1351
use generator:: StorageValue as _;
1480
1352
use sp_core:: hashing:: twox_128;
1481
1353
use sp_io:: TestExternalities ;
1482
- use sp_runtime:: DispatchResult ;
1483
1354
use weak_bounded_vec:: WeakBoundedVec ;
1484
1355
1485
1356
#[ test]
@@ -1590,71 +1461,6 @@ mod test {
1590
1461
} ) ;
1591
1462
}
1592
1463
1593
- #[ test]
1594
- fn is_transactional_should_return_false ( ) {
1595
- TestExternalities :: default ( ) . execute_with ( || {
1596
- assert ! ( !is_transactional( ) ) ;
1597
- } ) ;
1598
- }
1599
-
1600
- #[ test]
1601
- fn is_transactional_should_not_error_in_with_transaction ( ) {
1602
- TestExternalities :: default ( ) . execute_with ( || {
1603
- assert_ok ! ( with_transaction( || -> TransactionOutcome <DispatchResult > {
1604
- assert!( is_transactional( ) ) ;
1605
- TransactionOutcome :: Commit ( Ok ( ( ) ) )
1606
- } ) ) ;
1607
-
1608
- assert_noop ! (
1609
- with_transaction( || -> TransactionOutcome <DispatchResult > {
1610
- assert!( is_transactional( ) ) ;
1611
- TransactionOutcome :: Rollback ( Err ( "revert" . into( ) ) )
1612
- } ) ,
1613
- "revert"
1614
- ) ;
1615
- } ) ;
1616
- }
1617
-
1618
- fn recursive_transactional ( num : u32 ) -> DispatchResult {
1619
- if num == 0 {
1620
- return Ok ( ( ) )
1621
- }
1622
-
1623
- with_transaction ( || -> TransactionOutcome < DispatchResult > {
1624
- let res = recursive_transactional ( num - 1 ) ;
1625
- TransactionOutcome :: Commit ( res)
1626
- } )
1627
- }
1628
-
1629
- #[ test]
1630
- fn transaction_limit_should_work ( ) {
1631
- TestExternalities :: default ( ) . execute_with ( || {
1632
- assert_eq ! ( transaction_level_tracker:: get_transaction_level( ) , 0 ) ;
1633
-
1634
- assert_ok ! ( with_transaction( || -> TransactionOutcome <DispatchResult > {
1635
- assert_eq!( transaction_level_tracker:: get_transaction_level( ) , 1 ) ;
1636
- TransactionOutcome :: Commit ( Ok ( ( ) ) )
1637
- } ) ) ;
1638
-
1639
- assert_ok ! ( with_transaction( || -> TransactionOutcome <DispatchResult > {
1640
- assert_eq!( transaction_level_tracker:: get_transaction_level( ) , 1 ) ;
1641
- let res = with_transaction( || -> TransactionOutcome <DispatchResult > {
1642
- assert_eq!( transaction_level_tracker:: get_transaction_level( ) , 2 ) ;
1643
- TransactionOutcome :: Commit ( Ok ( ( ) ) )
1644
- } ) ;
1645
- TransactionOutcome :: Commit ( res)
1646
- } ) ) ;
1647
-
1648
- assert_ok ! ( recursive_transactional( 255 ) ) ;
1649
- assert_noop ! (
1650
- recursive_transactional( 256 ) ,
1651
- sp_runtime:: TransactionalError :: LimitReached
1652
- ) ;
1653
-
1654
- assert_eq ! ( transaction_level_tracker:: get_transaction_level( ) , 0 ) ;
1655
- } ) ;
1656
- }
1657
-
1658
1464
#[ test]
1659
1465
fn key_prefix_iterator_works ( ) {
1660
1466
TestExternalities :: default ( ) . execute_with ( || {
0 commit comments