@@ -3,17 +3,21 @@ use cfx_config::Configuration;
33use cfx_rpc_eth_types:: { AccountState , StateDump , EOA_STORAGE_ROOT_H256 } ;
44use cfx_rpc_primitives:: Bytes ;
55use cfx_statedb:: { StateDbExt , StateDbGeneric } ;
6- use cfx_storage:: state_manager:: StateManagerTrait ;
6+ use cfx_storage:: {
7+ state_manager:: StateManagerTrait , utils:: to_key_prefix_iter_upper_bound,
8+ KeyValueDbIterableTrait ,
9+ } ;
710use cfx_types:: { Address , Space , H256 } ;
811use cfxcore:: NodeType ;
12+ use fallible_iterator:: FallibleIterator ;
913use keccak_hash:: { keccak, KECCAK_EMPTY } ;
1014use parking_lot:: { Condvar , Mutex } ;
1115use primitives:: {
1216 Account , SkipInputCheck , StorageKey , StorageKeyWithSpace , StorageValue ,
1317} ;
1418use rlp:: Rlp ;
1519use std:: {
16- collections:: { BTreeMap , HashMap } ,
20+ collections:: { BTreeMap , HashMap , HashSet } ,
1721 ops:: Deref ,
1822 sync:: Arc ,
1923 thread,
@@ -32,6 +36,44 @@ pub fn dump_whole_state(
3236 conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
3337 config : & StateDumpConfig ,
3438) -> Result < StateDump , String > {
39+ let ( mut state_db, state_root) =
40+ prepare_state_db ( conf, exit_cond_var, config) ?;
41+
42+ let accounts =
43+ export_space_accounts ( & mut state_db, Space :: Ethereum , config)
44+ . map_err ( |e| e. to_string ( ) ) ?;
45+
46+ let state_dump = StateDump {
47+ root : state_root,
48+ accounts,
49+ next : None ,
50+ } ;
51+
52+ Ok ( state_dump)
53+ }
54+
55+ pub fn iterate_dump_whole_state < F : Fn ( AccountState ) > (
56+ conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
57+ config : & StateDumpConfig , callback : F ,
58+ ) -> Result < H256 , String > {
59+ let ( mut state_db, state_root) =
60+ prepare_state_db ( conf, exit_cond_var, config) ?;
61+
62+ export_space_accounts_with_iterator (
63+ & mut state_db,
64+ Space :: Ethereum ,
65+ config,
66+ callback,
67+ )
68+ . map_err ( |e| e. to_string ( ) ) ?;
69+
70+ Ok ( state_root)
71+ }
72+
73+ fn prepare_state_db (
74+ conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
75+ config : & StateDumpConfig ,
76+ ) -> Result < ( StateDbGeneric , H256 ) , String > {
3577 println ! ( "Preparing state..." ) ;
3678 let (
3779 data_man,
@@ -71,8 +113,6 @@ pub fn dump_whole_state(
71113 None => consensus. latest_confirmed_epoch_number ( ) ,
72114 } ;
73115
74- println ! ( "Start to dump state at epoch: {:?}" , target_height) ;
75-
76116 let epoch_hash = consensus
77117 . get_hash_from_epoch_number ( target_height. into ( ) )
78118 . map_err ( |e| e. to_string ( ) ) ?;
@@ -92,19 +132,9 @@ pub fn dump_whole_state(
92132 . map_err ( |e| e. to_string ( ) ) ?
93133 . ok_or ( "Failed to get state" ) ?;
94134
95- let mut state_db = StateDbGeneric :: new ( state) ;
96-
97- let accounts =
98- export_space_accounts ( & mut state_db, Space :: Ethereum , config)
99- . map_err ( |e| e. to_string ( ) ) ?;
100-
101- let state_dump = StateDump {
102- root : state_root. clone ( ) ,
103- accounts,
104- next : None ,
105- } ;
135+ let state_db = StateDbGeneric :: new ( state) ;
106136
107- Ok ( state_dump )
137+ Ok ( ( state_db , state_root . clone ( ) ) )
108138}
109139
110140fn export_space_accounts (
@@ -177,12 +207,18 @@ fn export_space_accounts(
177207 let code = if is_contract {
178208 codes_map. get ( & address) . cloned ( )
179209 } else {
210+ if let Some ( code) = codes_map. get ( & address) {
211+ println ! ( "no-contract account have code: {:?}" , code) ;
212+ }
180213 None
181214 } ;
182215
183216 let storage = if is_contract {
184217 storage_map. get ( & address) . cloned ( )
185218 } else {
219+ if let Some ( storage) = storage_map. get ( & address) {
220+ println ! ( "no-contract account have storage: {:?}" , storage) ;
221+ }
186222 None
187223 } ;
188224
@@ -207,6 +243,93 @@ fn export_space_accounts(
207243 Ok ( accounts)
208244}
209245
246+ fn export_space_accounts_with_iterator < F : Fn ( AccountState ) > (
247+ state : & mut StateDbGeneric , space : Space , config : & StateDumpConfig ,
248+ callback : F ,
249+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
250+ let empty_key = StorageKey :: EmptyKey . with_space ( space) ;
251+ let ( kvs, maybe_kv_iterator) = state. read_all_iterator ( empty_key) ?;
252+
253+ let mut deleted_keys = HashSet :: new ( ) ;
254+ let mut found_accounts = 0 ;
255+
256+ // Iterate key value pairs from delta trie and intermediate trie
257+ for ( k, v) in kvs {
258+ let storage_key = StorageKeyWithSpace :: from_delta_mpt_key ( & k) ;
259+ let key = storage_key. to_key_bytes ( ) ;
260+ deleted_keys. insert ( key. clone ( ) ) ;
261+
262+ let storage_key_with_space =
263+ StorageKeyWithSpace :: from_key_bytes :: < SkipInputCheck > ( & key) ;
264+ if storage_key_with_space. space != space {
265+ continue ;
266+ }
267+
268+ if let StorageKey :: AccountKey ( address_bytes) =
269+ storage_key_with_space. key
270+ {
271+ let address = Address :: from_slice ( address_bytes) ;
272+ println ! ( "Find account: {:?}" , address) ;
273+ let account = Account :: new_from_rlp ( address, & Rlp :: new ( & v) ) ?;
274+
275+ let account_state = get_account_state ( state, & account, config) ?;
276+ callback ( account_state) ;
277+ found_accounts += 1 ;
278+
279+ if config. limit > 0 && found_accounts >= config. limit as usize {
280+ break ;
281+ }
282+ } else {
283+ continue ;
284+ }
285+ }
286+
287+ let lower_bound_incl = empty_key. to_key_bytes ( ) ;
288+ let upper_bound_excl = to_key_prefix_iter_upper_bound ( & lower_bound_incl) ;
289+
290+ if let Some ( mut kv_iterator) = maybe_kv_iterator {
291+ let mut kvs = kv_iterator
292+ . iter_range (
293+ lower_bound_incl. as_slice ( ) ,
294+ upper_bound_excl. as_ref ( ) . map ( |v| & * * v) ,
295+ ) ?
296+ . take ( ) ;
297+
298+ while let Some ( ( key, value) ) = kvs. next ( ) ? {
299+ if deleted_keys. contains ( & key) {
300+ continue ;
301+ }
302+
303+ let storage_key_with_space =
304+ StorageKeyWithSpace :: from_key_bytes :: < SkipInputCheck > ( & key) ;
305+ if storage_key_with_space. space != space {
306+ continue ;
307+ }
308+
309+ if let StorageKey :: AccountKey ( address_bytes) =
310+ storage_key_with_space. key
311+ {
312+ let address = Address :: from_slice ( address_bytes) ;
313+ println ! ( "Find account: {:?}" , address) ;
314+ let account =
315+ Account :: new_from_rlp ( address, & Rlp :: new ( & value) ) ?;
316+
317+ let account_state = get_account_state ( state, & account, config) ?;
318+ callback ( account_state) ;
319+ found_accounts += 1 ;
320+
321+ if config. limit > 0 && found_accounts >= config. limit as usize {
322+ break ;
323+ }
324+ } else {
325+ continue ;
326+ }
327+ }
328+ }
329+
330+ Ok ( ( ) )
331+ }
332+
210333#[ allow( unused) ]
211334fn get_account_state (
212335 state : & mut StateDbGeneric , account : & Account , config : & StateDumpConfig ,
0 commit comments