@@ -3,21 +3,18 @@ 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:: {
7- state_manager:: StateManagerTrait , utils:: to_key_prefix_iter_upper_bound,
8- KeyValueDbIterableTrait ,
9- } ;
6+ use cfx_storage:: state_manager:: StateManagerTrait ;
107use cfx_types:: { Address , Space , H256 } ;
118use cfxcore:: NodeType ;
12- use fallible_iterator :: FallibleIterator ;
9+ use chrono :: Utc ;
1310use keccak_hash:: { keccak, KECCAK_EMPTY } ;
1411use parking_lot:: { Condvar , Mutex } ;
1512use primitives:: {
1613 Account , SkipInputCheck , StorageKey , StorageKeyWithSpace , StorageValue ,
1714} ;
1815use rlp:: Rlp ;
1916use std:: {
20- collections:: { BTreeMap , HashMap , HashSet } ,
17+ collections:: { BTreeMap , HashMap } ,
2118 ops:: Deref ,
2219 sync:: Arc ,
2320 thread,
@@ -32,6 +29,10 @@ pub struct StateDumpConfig {
3229 pub no_storage : bool ,
3330}
3431
32+ // This method will read all data (k, v) from the Conflux state tree (including
33+ // core space and espace accounts, code, storage, deposit, vote_list) into
34+ // memory at once, then parse and assemble them and assemble all account states
35+ // into a StateDump struct and return it
3536pub fn dump_whole_state (
3637 conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
3738 config : & StateDumpConfig ,
@@ -52,14 +53,19 @@ pub fn dump_whole_state(
5253 Ok ( state_dump)
5354}
5455
56+ // This method will iterate through the entire state tree, storing each found
57+ // account in a temporary map After iterating through all accounts, it will
58+ // retrieve the code and storage for each account, then call the callback method
59+ // Pass the AccountState as a parameter to the callback method, which will
60+ // handle the AccountState
5561pub fn iterate_dump_whole_state < F : Fn ( AccountState ) > (
5662 conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
5763 config : & StateDumpConfig , callback : F ,
5864) -> Result < H256 , String > {
5965 let ( mut state_db, state_root) =
6066 prepare_state_db ( conf, exit_cond_var, config) ?;
6167
62- export_space_accounts_with_iterator (
68+ export_space_accounts_with_callback (
6369 & mut state_db,
6470 Space :: Ethereum ,
6571 config,
@@ -74,7 +80,7 @@ fn prepare_state_db(
7480 conf : & mut Configuration , exit_cond_var : Arc < ( Mutex < bool > , Condvar ) > ,
7581 config : & StateDumpConfig ,
7682) -> Result < ( StateDbGeneric , H256 ) , String > {
77- println ! ( "Preparing state..." ) ;
83+ println ( "Preparing state..." ) ;
7884 let (
7985 data_man,
8086 _,
@@ -140,6 +146,7 @@ fn prepare_state_db(
140146fn export_space_accounts (
141147 state : & mut StateDbGeneric , space : Space , config : & StateDumpConfig ,
142148) -> Result < BTreeMap < Address , AccountState > , Box < dyn std:: error:: Error > > {
149+ println ( "Start to iterate state..." ) ;
143150 let empty_key = StorageKey :: EmptyKey . with_space ( space) ;
144151 let kv_pairs = state. read_all ( empty_key, None ) ?;
145152
@@ -156,7 +163,7 @@ fn export_space_accounts(
156163 match storage_key_with_space. key {
157164 StorageKey :: AccountKey ( address_bytes) => {
158165 let address = Address :: from_slice ( address_bytes) ;
159- println ! ( "Find account: {:?}" , address) ;
166+ println ( & format ! ( "Find account: {:?}" , address) ) ;
160167 let account =
161168 Account :: new_from_rlp ( address, & Rlp :: new ( & value) ) ?;
162169 accounts_map. insert ( address, account) ;
@@ -208,16 +215,16 @@ fn export_space_accounts(
208215 codes_map. get ( & address) . cloned ( )
209216 } else {
210217 if let Some ( code) = codes_map. get ( & address) {
211- println ! ( "no-contract account have code: {:?}" , code) ;
218+ println ( & format ! ( "no-contract account have code: {:?}" , code) ) ;
212219 }
213220 None
214221 } ;
215222
216223 let storage = if is_contract {
217224 storage_map. get ( & address) . cloned ( )
218225 } else {
219- if let Some ( storage ) = storage_map. get ( & address) {
220- println ! ( "no-contract account have storage: {:?}" , storage ) ;
226+ if let Some ( _storage ) = storage_map. get ( & address) {
227+ println ( & format ! ( "no-contract account have storage" ) ) ;
221228 }
222229 None
223230 } ;
@@ -243,86 +250,61 @@ fn export_space_accounts(
243250 Ok ( accounts)
244251}
245252
246- fn export_space_accounts_with_iterator < F : Fn ( AccountState ) > (
253+ pub fn export_space_accounts_with_callback < F : Fn ( AccountState ) > (
247254 state : & mut StateDbGeneric , space : Space , config : & StateDumpConfig ,
248255 callback : F ,
249256) -> 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 ( ) ;
257+ println ( "Start to iterate state..." ) ;
254258 let mut found_accounts = 0 ;
259+ let mut core_space_key_count: u64 = 0 ;
260+ let mut total_key_count: u64 = 0 ;
255261
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) ;
262+ for i in 0 ..=255 {
263+ let prefix = [ i] ;
264+ let start_key = StorageKey :: AddressPrefixKey ( & prefix) . with_space ( space) ;
289265
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- }
266+ let mut account_states = BTreeMap :: new ( ) ;
302267
268+ let mut inner_callback = |( key, value) : ( Vec < u8 > , Box < [ u8 ] > ) | {
269+ total_key_count += 1 ;
303270 let storage_key_with_space =
304271 StorageKeyWithSpace :: from_key_bytes :: < SkipInputCheck > ( & key) ;
305272 if storage_key_with_space. space != space {
306- continue ;
273+ core_space_key_count += 1 ;
274+ return ;
275+ }
276+
277+ if total_key_count % 10000 == 0 {
278+ println ( & format ! (
279+ "total_key_count: {}, core_space_key_count: {}" ,
280+ total_key_count, core_space_key_count
281+ ) ) ;
307282 }
308283
309284 if let StorageKey :: AccountKey ( address_bytes) =
310285 storage_key_with_space. key
311286 {
312287 let address = Address :: from_slice ( address_bytes) ;
313- println ! ( "Find account: {:?}" , address) ;
314- let account =
315- Account :: new_from_rlp ( address , & Rlp :: new ( & value ) ) ? ;
288+ println ( & format ! ( "Find account: {:?}" , address) ) ;
289+ let account = Account :: new_from_rlp ( address , & Rlp :: new ( & value ) )
290+ . expect ( "Failed to decode account" ) ;
316291
317- let account_state = get_account_state ( state , & account, config ) ? ;
318- callback ( account_state ) ;
319- found_accounts += 1 ;
292+ account_states . insert ( address , account) ;
293+ }
294+ } ;
320295
321- if config. limit > 0 && found_accounts >= config. limit as usize {
322- break ;
323- }
324- } else {
325- continue ;
296+ state. read_all_with_callback ( start_key, & mut inner_callback) ?;
297+
298+ if account_states. len ( ) > 0 {
299+ println ( "Start to read account code and storage data..." ) ;
300+ }
301+
302+ for ( _address, account) in account_states {
303+ let account_state = get_account_state ( state, & account, config) ?;
304+ callback ( account_state) ;
305+ found_accounts += 1 ;
306+ if config. limit > 0 && found_accounts >= config. limit as usize {
307+ break ;
326308 }
327309 }
328310 }
@@ -369,3 +351,7 @@ fn get_account_state(
369351 address_hash : Some ( address_hash) ,
370352 } )
371353}
354+
355+ fn println ( message : & str ) {
356+ println ! ( "[{}] {}" , Utc :: now( ) . format( "%Y-%m-%d %H:%M:%S" ) , message) ;
357+ }
0 commit comments