@@ -2,7 +2,7 @@ use cosmwasm_std::{
2
2
entry_point, BankMsg , DepsMut , Env , MessageInfo , Order , Response , StdError , StdResult ,
3
3
} ;
4
4
5
- use crate :: msg:: { InstantiateMsg , MigrateMsg } ;
5
+ use crate :: msg:: { ExecuteMsg , InstantiateMsg , MigrateMsg } ;
6
6
7
7
#[ entry_point]
8
8
pub fn instantiate (
@@ -18,31 +18,58 @@ pub fn instantiate(
18
18
19
19
#[ entry_point]
20
20
pub fn migrate ( deps : DepsMut , env : Env , msg : MigrateMsg ) -> StdResult < Response > {
21
- // delete all state
22
- let keys: Vec < _ > = deps
23
- . storage
24
- . range ( None , None , Order :: Ascending )
25
- . map ( |( k, _) | k)
26
- . collect ( ) ;
27
- let count = keys. len ( ) ;
28
- for k in keys {
29
- deps. storage . remove ( & k) ;
30
- }
31
-
32
21
// get balance and send all to recipient
33
22
let balance = deps. querier . query_all_balances ( env. contract . address ) ?;
34
23
let send = BankMsg :: Send {
35
24
to_address : msg. payout . clone ( ) ,
36
25
amount : balance,
37
26
} ;
27
+ Ok ( Response :: new ( )
28
+ . add_message ( send)
29
+ . add_attribute ( "action" , "burn" )
30
+ . add_attribute ( "payout" , msg. payout ) )
31
+ }
32
+
33
+ #[ entry_point]
34
+ pub fn execute ( deps : DepsMut , env : Env , info : MessageInfo , msg : ExecuteMsg ) -> StdResult < Response > {
35
+ match msg {
36
+ ExecuteMsg :: Cleanup { limit } => execute_cleanup ( deps, env, info, limit) ,
37
+ }
38
+ }
39
+
40
+ pub fn execute_cleanup (
41
+ deps : DepsMut ,
42
+ _env : Env ,
43
+ _info : MessageInfo ,
44
+ limit : Option < u32 > ,
45
+ ) -> StdResult < Response > {
46
+ // the number of elements we can still take (decreasing over time)
47
+ let mut limit = limit. unwrap_or ( u32:: MAX ) as usize ;
38
48
39
- let data_msg = format ! ( "burnt {} keys" , count) . into_bytes ( ) ;
49
+ let mut deleted = 0 ;
50
+ const PER_SCAN : usize = 20 ;
51
+ loop {
52
+ let take_this_scan = std:: cmp:: min ( PER_SCAN , limit) ;
53
+ let keys: Vec < _ > = deps
54
+ . storage
55
+ . range ( None , None , Order :: Ascending )
56
+ . take ( take_this_scan)
57
+ . map ( |( k, _) | k)
58
+ . collect ( ) ;
59
+ let deleted_this_scan = keys. len ( ) ;
60
+ for k in keys {
61
+ deps. storage . remove ( & k) ;
62
+ }
63
+ deleted += deleted_this_scan;
64
+ limit -= deleted_this_scan;
65
+ if limit == 0 || deleted_this_scan < take_this_scan {
66
+ break ;
67
+ }
68
+ }
40
69
41
70
Ok ( Response :: new ( )
42
- . add_message ( send)
43
71
. add_attribute ( "action" , "burn" )
44
- . add_attribute ( "payout" , msg. payout )
45
- . set_data ( data_msg) )
72
+ . add_attribute ( "deleted_entries" , deleted. to_string ( ) ) )
46
73
}
47
74
48
75
#[ cfg( test) ]
@@ -51,7 +78,18 @@ mod tests {
51
78
use cosmwasm_std:: testing:: {
52
79
mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info,
53
80
} ;
54
- use cosmwasm_std:: { coins, StdError , Storage , SubMsg } ;
81
+ use cosmwasm_std:: { coins, Attribute , StdError , Storage , SubMsg } ;
82
+
83
+ /// Gets the value of the first attribute with the given key
84
+ fn first_attr ( data : impl AsRef < [ Attribute ] > , search_key : & str ) -> Option < String > {
85
+ data. as_ref ( ) . iter ( ) . find_map ( |a| {
86
+ if a. key == search_key {
87
+ Some ( a. value . clone ( ) )
88
+ } else {
89
+ None
90
+ }
91
+ } )
92
+ }
55
93
56
94
#[ test]
57
95
fn instantiate_fails ( ) {
@@ -70,16 +108,9 @@ mod tests {
70
108
}
71
109
72
110
#[ test]
73
- fn migrate_cleans_up_data ( ) {
111
+ fn migrate_sends_funds ( ) {
74
112
let mut deps = mock_dependencies_with_balance ( & coins ( 123456 , "gold" ) ) ;
75
113
76
- // store some sample data
77
- deps. storage . set ( b"foo" , b"bar" ) ;
78
- deps. storage . set ( b"key2" , b"data2" ) ;
79
- deps. storage . set ( b"key3" , b"cool stuff" ) ;
80
- let cnt = deps. storage . range ( None , None , Order :: Ascending ) . count ( ) ;
81
- assert_eq ! ( 3 , cnt) ;
82
-
83
114
// change the verifier via migrate
84
115
let payout = String :: from ( "someone else" ) ;
85
116
let msg = MigrateMsg {
@@ -96,9 +127,48 @@ mod tests {
96
127
amount: coins( 123456 , "gold" ) ,
97
128
} )
98
129
) ;
130
+ }
131
+
132
+ #[ test]
133
+ fn execute_cleans_up_data ( ) {
134
+ let mut deps = mock_dependencies_with_balance ( & coins ( 123456 , "gold" ) ) ;
135
+
136
+ // store some sample data
137
+ deps. storage . set ( b"foo" , b"bar" ) ;
138
+ deps. storage . set ( b"key2" , b"data2" ) ;
139
+ deps. storage . set ( b"key3" , b"cool stuff" ) ;
140
+ let cnt = deps. storage . range ( None , None , Order :: Ascending ) . count ( ) ;
141
+ assert_eq ! ( cnt, 3 ) ;
142
+
143
+ // change the verifier via migrate
144
+ let payout = String :: from ( "someone else" ) ;
145
+ let msg = MigrateMsg { payout } ;
146
+ let _res = migrate ( deps. as_mut ( ) , mock_env ( ) , msg) . unwrap ( ) ;
147
+
148
+ let res = execute (
149
+ deps. as_mut ( ) ,
150
+ mock_env ( ) ,
151
+ mock_info ( "anon" , & [ ] ) ,
152
+ ExecuteMsg :: Cleanup { limit : Some ( 2 ) } ,
153
+ )
154
+ . unwrap ( ) ;
155
+ assert_eq ! ( first_attr( res. attributes, "deleted_entries" ) . unwrap( ) , "2" ) ;
156
+
157
+ // One item should be left
158
+ let cnt = deps. storage . range ( None , None , Order :: Ascending ) . count ( ) ;
159
+ assert_eq ! ( cnt, 1 ) ;
160
+
161
+ let res = execute (
162
+ deps. as_mut ( ) ,
163
+ mock_env ( ) ,
164
+ mock_info ( "anon" , & [ ] ) ,
165
+ ExecuteMsg :: Cleanup { limit : Some ( 2 ) } ,
166
+ )
167
+ . unwrap ( ) ;
168
+ assert_eq ! ( first_attr( res. attributes, "deleted_entries" ) . unwrap( ) , "1" ) ;
99
169
100
- // check there is no data in storage
170
+ // Now all are gone
101
171
let cnt = deps. storage . range ( None , None , Order :: Ascending ) . count ( ) ;
102
- assert_eq ! ( 0 , cnt ) ;
172
+ assert_eq ! ( cnt , 0 ) ;
103
173
}
104
174
}
0 commit comments