@@ -36,11 +36,12 @@ use primitives::storage::well_known_keys;
3636use codec:: { Encode , Decode } ;
3737use state_machine:: {
3838 Backend as StateBackend , CodeExecutor ,
39- ExecutionStrategy , ExecutionManager , ChangesTrieAnchorBlockId ,
40- prove_read, key_changes, key_changes_proof, OverlayedChanges
39+ ExecutionStrategy , ExecutionManager , prove_read,
40+ key_changes, key_changes_proof,
41+ ChangesTrieAnchorBlockId , OverlayedChanges
4142} ;
4243
43- use backend:: { self , BlockImportOperation } ;
44+ use backend:: { self , BlockImportOperation , PrunableStateChangesTrieStorage } ;
4445use blockchain:: { self , Info as ChainInfo , Backend as ChainBackend , HeaderBackend as ChainHeaderBackend } ;
4546use call_executor:: { CallExecutor , LocalCallExecutor } ;
4647use executor:: { RuntimeVersion , RuntimeInfo } ;
@@ -336,33 +337,56 @@ impl<B, E, Block> Client<B, E, Block> where
336337 Ok ( ( header, proof) )
337338 }
338339
340+ /// Get longest range within [first; last] that is possible to use in `key_changes`
341+ /// and `key_changes_proof` calls.
342+ /// Range could be shortened from the beginning if some changes tries have been pruned.
343+ /// Returns None if changes trues are not supported.
344+ pub fn max_key_changes_range (
345+ & self ,
346+ first : NumberFor < Block > ,
347+ last : BlockId < Block > ,
348+ ) -> error:: Result < Option < ( NumberFor < Block > , BlockId < Block > ) > > {
349+ let ( config, storage) = match self . require_changes_trie ( ) . ok ( ) {
350+ Some ( ( config, storage) ) => ( config, storage) ,
351+ None => return Ok ( None ) ,
352+ } ;
353+
354+ let first = first. as_ ( ) ;
355+ let last_num = self . require_block_number_from_id ( & last) ?. as_ ( ) ;
356+ if first > last_num {
357+ return Err ( error:: ErrorKind :: ChangesTrieAccessFailed ( "Invalid changes trie range" . into ( ) ) . into ( ) ) ;
358+ }
359+
360+ let finalized_number = self . backend . blockchain ( ) . info ( ) ?. finalized_number ;
361+ let oldest = storage. oldest_changes_trie_block ( config, finalized_number. as_ ( ) ) ;
362+ let first = As :: sa ( :: std:: cmp:: max ( first, oldest) ) ;
363+ Ok ( Some ( ( first, last) ) )
364+ }
365+
339366 /// Get pairs of (block, extrinsic) where key has been changed at given blocks range.
340367 /// Works only for runtimes that are supporting changes tries.
368+ /// Changes are returned in descending order.
341369 pub fn key_changes (
342370 & self ,
343- first : Block :: Hash ,
344- last : Block :: Hash ,
345- key : & [ u8 ]
371+ first : NumberFor < Block > ,
372+ last : BlockId < Block > ,
373+ key : & StorageKey ,
346374 ) -> error:: Result < Vec < ( NumberFor < Block > , u32 ) > > {
347- let config = self . changes_trie_config . as_ref ( ) ;
348- let storage = self . backend . changes_trie_storage ( ) ;
349- let ( config, storage) = match ( config, storage) {
350- ( Some ( config) , Some ( storage) ) => ( config, storage) ,
351- _ => return Err ( error:: ErrorKind :: ChangesTriesNotSupported . into ( ) ) ,
352- } ;
353-
354- key_changes :: < _ , Blake2Hasher > (
375+ let ( config, storage) = self . require_changes_trie ( ) ?;
376+ let last_number = self . require_block_number_from_id ( & last) ?. as_ ( ) ;
377+ let last_hash = self . require_block_hash_from_id ( & last) ?;
378+ key_changes (
355379 config,
356- storage,
357- self . require_block_number_from_id ( & BlockId :: Hash ( first) ) ? . as_ ( ) ,
380+ & * storage,
381+ first. as_ ( ) ,
358382 & ChangesTrieAnchorBlockId {
359- hash : convert_hash ( & last ) ,
360- number : self . require_block_number_from_id ( & BlockId :: Hash ( last ) ) ? . as_ ( ) ,
383+ hash : convert_hash ( & last_hash ) ,
384+ number : last_number ,
361385 } ,
362386 self . backend . blockchain ( ) . info ( ) ?. best_number . as_ ( ) ,
363- key)
387+ & key. 0 )
388+ . and_then ( |r| r. map ( |r| r. map ( |( block, tx) | ( As :: sa ( block) , tx) ) ) . collect :: < Result < _ , _ > > ( ) )
364389 . map_err ( |err| error:: ErrorKind :: ChangesTrieAccessFailed ( err) . into ( ) )
365- . map ( |r| r. into_iter ( ) . map ( |( b, e) | ( As :: sa ( b) , e) ) . collect ( ) )
366390 }
367391
368392 /// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
@@ -374,33 +398,37 @@ impl<B, E, Block> Client<B, E, Block> where
374398 first : Block :: Hash ,
375399 last : Block :: Hash ,
376400 max : Block :: Hash ,
377- key : & [ u8 ]
401+ key : & StorageKey ,
378402 ) -> error:: Result < ( NumberFor < Block > , Vec < Vec < u8 > > ) > {
379- let config = self . changes_trie_config . as_ref ( ) ;
380- let storage = self . backend . changes_trie_storage ( ) ;
381- let ( config, storage) = match ( config, storage) {
382- ( Some ( config) , Some ( storage) ) => ( config, storage) ,
383- _ => return Err ( error:: ErrorKind :: ChangesTriesNotSupported . into ( ) ) ,
384- } ;
385-
403+ let ( config, storage) = self . require_changes_trie ( ) ?;
386404 let max_number = :: std:: cmp:: min (
387405 self . backend . blockchain ( ) . info ( ) ?. best_number ,
388406 self . require_block_number_from_id ( & BlockId :: Hash ( max) ) ?,
389407 ) ;
390- key_changes_proof :: < _ , Blake2Hasher > (
408+ key_changes_proof (
391409 config,
392- storage,
410+ & * storage,
393411 self . require_block_number_from_id ( & BlockId :: Hash ( first) ) ?. as_ ( ) ,
394412 & ChangesTrieAnchorBlockId {
395413 hash : convert_hash ( & last) ,
396414 number : self . require_block_number_from_id ( & BlockId :: Hash ( last) ) ?. as_ ( ) ,
397415 } ,
398416 max_number. as_ ( ) ,
399- key)
417+ & key. 0 )
400418 . map_err ( |err| error:: ErrorKind :: ChangesTrieAccessFailed ( err) . into ( ) )
401419 . map ( |proof| ( max_number, proof) )
402420 }
403421
422+ /// Returns changes trie configuration and storage or an error if it is not supported.
423+ fn require_changes_trie ( & self ) -> error:: Result < ( & ChangesTrieConfiguration , & B :: ChangesTrieStorage ) > {
424+ let config = self . changes_trie_config . as_ref ( ) ;
425+ let storage = self . backend . changes_trie_storage ( ) ;
426+ match ( config, storage) {
427+ ( Some ( config) , Some ( storage) ) => Ok ( ( config, storage) ) ,
428+ _ => Err ( error:: ErrorKind :: ChangesTriesNotSupported . into ( ) ) ,
429+ }
430+ }
431+
404432 /// Create a new block, built on the head of the chain.
405433 pub fn new_block ( & self ) -> error:: Result < block_builder:: BlockBuilder < B , E , Block , Blake2Hasher > >
406434 where E : Clone
@@ -750,7 +778,13 @@ impl<B, E, Block> Client<B, E, Block> where
750778 }
751779 }
752780
753- /// Convert an arbitrary block ID into a block hash.
781+ /// Convert an arbitrary block ID into a block number, returning error if the block is unknown.
782+ fn require_block_hash_from_id ( & self , id : & BlockId < Block > ) -> error:: Result < Block :: Hash > {
783+ self . block_hash_from_id ( id)
784+ . and_then ( |n| n. ok_or_else ( || error:: ErrorKind :: UnknownBlock ( format ! ( "{}" , id) ) . into ( ) ) )
785+ }
786+
787+ /// Convert an arbitrary block ID into a block number.
754788 pub fn block_number_from_id ( & self , id : & BlockId < Block > ) -> error:: Result < Option < NumberFor < Block > > > {
755789 match * id {
756790 BlockId :: Hash ( _) => Ok ( self . header ( id) ?. map ( |h| h. number ( ) . clone ( ) ) ) ,
@@ -1586,9 +1620,7 @@ pub(crate) mod tests {
15861620 let ( client, _, test_cases) = prepare_client_with_key_changes ( ) ;
15871621
15881622 for ( index, ( begin, end, key, expected_result) ) in test_cases. into_iter ( ) . enumerate ( ) {
1589- let begin = client. block_hash ( begin) . unwrap ( ) . unwrap ( ) ;
1590- let end = client. block_hash ( end) . unwrap ( ) . unwrap ( ) ;
1591- let actual_result = client. key_changes ( begin, end, & key) . unwrap ( ) ;
1623+ let actual_result = client. key_changes ( begin, BlockId :: Number ( end) , & StorageKey ( key) ) . unwrap ( ) ;
15921624 match actual_result == expected_result {
15931625 true => ( ) ,
15941626 false => panic ! ( format!( "Failed test {}: actual = {:?}, expected = {:?}" ,
0 commit comments