@@ -96,12 +96,6 @@ struct PendingBlock {
96
96
is_best : bool ,
97
97
}
98
98
99
- /// Database transaction
100
- pub struct BlockImportOperation {
101
- pending_state : DbState ,
102
- pending_block : Option < PendingBlock > ,
103
- }
104
-
105
99
#[ derive( Clone ) ]
106
100
struct Meta {
107
101
best_hash : HeaderHash ,
@@ -261,11 +255,18 @@ impl client::blockchain::Backend for BlockchainDb {
261
255
}
262
256
}
263
257
258
+ /// Database transaction
259
+ pub struct BlockImportOperation {
260
+ old_state : DbState ,
261
+ updates : MemoryDB ,
262
+ pending_block : Option < PendingBlock > ,
263
+ }
264
+
264
265
impl client:: backend:: BlockImportOperation for BlockImportOperation {
265
266
type State = DbState ;
266
267
267
268
fn state ( & self ) -> Result < & Self :: State , client:: error:: Error > {
268
- Ok ( & self . pending_state )
269
+ Ok ( & self . old_state )
269
270
}
270
271
271
272
fn set_block_data ( & mut self , header : block:: Header , body : Option < block:: Body > , justification : Option < primitives:: bft:: Justification > , is_best : bool ) -> Result < ( ) , client:: error:: Error > {
@@ -280,14 +281,14 @@ impl client::backend::BlockImportOperation for BlockImportOperation {
280
281
}
281
282
282
283
fn update_storage ( & mut self , update : MemoryDB ) -> Result < ( ) , client:: error:: Error > {
283
- self . pending_state . commit ( update) ;
284
+ self . updates = update;
284
285
Ok ( ( ) )
285
286
}
286
287
287
288
fn reset_storage < I : Iterator < Item =( Vec < u8 > , Vec < u8 > ) > > ( & mut self , iter : I ) -> Result < ( ) , client:: error:: Error > {
288
289
// TODO: wipe out existing trie.
289
- let ( _, update) = self . pending_state . storage_root ( iter. into_iter ( ) . map ( |( k, v) | ( k, Some ( v) ) ) ) ;
290
- self . pending_state . commit ( update) ;
290
+ let ( _, update) = self . old_state . storage_root ( iter. into_iter ( ) . map ( |( k, v) | ( k, Some ( v) ) ) ) ;
291
+ self . updates = update;
291
292
Ok ( ( ) )
292
293
}
293
294
}
@@ -341,10 +342,10 @@ impl<'a> HashDB for Ephemeral<'a> {
341
342
}
342
343
343
344
/// DB-backed patricia trie state, transaction type is an overlay of changes to commit.
345
+ #[ derive( Clone ) ]
344
346
pub struct DbState {
345
347
db : Arc < KeyValueDB > ,
346
348
root : TrieH256 ,
347
- updates : MemoryDB ,
348
349
}
349
350
350
351
impl state_machine:: Backend for DbState {
@@ -364,10 +365,6 @@ impl state_machine::Backend for DbState {
364
365
. get ( key) . map ( |x| x. map ( |val| val. to_vec ( ) ) ) . map_err ( map_e)
365
366
}
366
367
367
- fn commit ( & mut self , transaction : MemoryDB ) {
368
- self . updates = transaction;
369
- }
370
-
371
368
fn pairs ( & self ) -> Vec < ( Vec < u8 > , Vec < u8 > ) > {
372
369
let mut read_overlay = MemoryDB :: default ( ) ;
373
370
let eph = Ephemeral {
@@ -423,10 +420,12 @@ impl state_machine::Backend for DbState {
423
420
}
424
421
}
425
422
426
- /// In-memory backend. Keeps all states and blocks in memory. Useful for testing.
423
+ /// Disk backend. Keeps data in a key-value store. In archive mode, trie nodes are kept from all blocks.
424
+ /// Otherwise, trie nodes are kept only from the most recent block.
427
425
pub struct Backend {
428
426
db : Arc < KeyValueDB > ,
429
427
blockchain : BlockchainDb ,
428
+ archive : bool ,
430
429
}
431
430
432
431
impl Backend {
@@ -438,22 +437,23 @@ impl Backend {
438
437
let path = config. path . to_str ( ) . ok_or_else ( || client:: error:: ErrorKind :: Backend ( "Invalid database path" . into ( ) ) ) ?;
439
438
let db = Arc :: new ( Database :: open ( & db_config, & path) . map_err ( db_err) ?) ;
440
439
441
- Backend :: from_kvdb ( db as Arc < _ > )
440
+ Backend :: from_kvdb ( db as Arc < _ > , true )
442
441
}
443
442
444
443
#[ cfg( test) ]
445
444
fn new_test ( ) -> Backend {
446
445
let db = Arc :: new ( :: kvdb_memorydb:: create ( columns:: NUM_COLUMNS ) ) ;
447
446
448
- Backend :: from_kvdb ( db as Arc < _ > ) . expect ( "failed to create test-db" )
447
+ Backend :: from_kvdb ( db as Arc < _ > , false ) . expect ( "failed to create test-db" )
449
448
}
450
449
451
- fn from_kvdb ( db : Arc < KeyValueDB > ) -> Result < Backend , client:: error:: Error > {
450
+ fn from_kvdb ( db : Arc < KeyValueDB > , archive : bool ) -> Result < Backend , client:: error:: Error > {
452
451
let blockchain = BlockchainDb :: new ( db. clone ( ) ) ?;
453
452
454
453
Ok ( Backend {
455
454
db,
456
455
blockchain,
456
+ archive
457
457
} )
458
458
}
459
459
}
@@ -467,7 +467,8 @@ impl client::backend::Backend for Backend {
467
467
let state = self . state_at ( block) ?;
468
468
Ok ( BlockImportOperation {
469
469
pending_block : None ,
470
- pending_state : state,
470
+ old_state : state,
471
+ updates : MemoryDB :: default ( ) ,
471
472
} )
472
473
}
473
474
@@ -488,10 +489,10 @@ impl client::backend::Backend for Backend {
488
489
if pending_block. is_best {
489
490
transaction. put ( columns:: META , meta:: BEST_BLOCK , & key) ;
490
491
}
491
- for ( key, ( val, rc) ) in operation. pending_state . updates . drain ( ) {
492
+ for ( key, ( val, rc) ) in operation. updates . drain ( ) {
492
493
if rc > 0 {
493
494
transaction. put ( columns:: STATE , & key. 0 [ ..] , & val) ;
494
- } else {
495
+ } else if rc < 0 && ! self . archive {
495
496
transaction. delete ( columns:: STATE , & key. 0 [ ..] ) ;
496
497
}
497
498
}
@@ -518,7 +519,6 @@ impl client::backend::Backend for Backend {
518
519
519
520
return Ok ( DbState {
520
521
db : self . db . clone ( ) ,
521
- updates : Default :: default ( ) ,
522
522
root,
523
523
} )
524
524
}
@@ -528,7 +528,6 @@ impl client::backend::Backend for Backend {
528
528
self . blockchain . header ( block) . and_then ( |maybe_hdr| maybe_hdr. map ( |hdr| {
529
529
DbState {
530
530
db : self . db . clone ( ) ,
531
- updates : Default :: default ( ) ,
532
531
root : hdr. state_root . 0 . into ( ) ,
533
532
}
534
533
} ) . ok_or_else ( || client:: error:: ErrorKind :: UnknownBlock ( block) . into ( ) ) )
@@ -595,7 +594,7 @@ mod tests {
595
594
( vec![ 1 , 2 , 3 ] , vec![ 9 , 9 , 9 ] ) ,
596
595
] ;
597
596
598
- header. state_root = op. pending_state . storage_root ( storage
597
+ header. state_root = op. old_state . storage_root ( storage
599
598
. iter ( )
600
599
. cloned ( )
601
600
. map ( |( x, y) | ( x, Some ( y) ) )
@@ -634,7 +633,7 @@ mod tests {
634
633
( vec![ 5 , 5 , 5 ] , Some ( vec![ 4 , 5 , 6 ] ) ) ,
635
634
] ;
636
635
637
- let ( root, overlay) = op. pending_state . storage_root ( storage. iter ( ) . cloned ( ) ) ;
636
+ let ( root, overlay) = op. old_state . storage_root ( storage. iter ( ) . cloned ( ) ) ;
638
637
op. update_storage ( overlay) . unwrap ( ) ;
639
638
header. state_root = root. into ( ) ;
640
639
@@ -654,4 +653,106 @@ mod tests {
654
653
assert_eq ! ( state. storage( & [ 5 , 5 , 5 ] ) . unwrap( ) , Some ( vec![ 4 , 5 , 6 ] ) ) ;
655
654
}
656
655
}
656
+
657
+ #[ test]
658
+ fn delete_only_when_negative_rc ( ) {
659
+ let key;
660
+ let db = Backend :: new_test ( ) ;
661
+
662
+ {
663
+ let mut op = db. begin_operation ( BlockId :: Hash ( Default :: default ( ) ) ) . unwrap ( ) ;
664
+ let mut header = block:: Header {
665
+ number : 0 ,
666
+ parent_hash : Default :: default ( ) ,
667
+ state_root : Default :: default ( ) ,
668
+ digest : Default :: default ( ) ,
669
+ extrinsics_root : Default :: default ( ) ,
670
+ } ;
671
+
672
+ let storage: Vec < ( _ , _ ) > = vec ! [ ] ;
673
+
674
+ header. state_root = op. old_state . storage_root ( storage
675
+ . iter ( )
676
+ . cloned ( )
677
+ . map ( |( x, y) | ( x, Some ( y) ) )
678
+ ) . 0 . into ( ) ;
679
+
680
+ op. reset_storage ( storage. iter ( ) . cloned ( ) ) . unwrap ( ) ;
681
+
682
+ key = op. updates . insert ( b"hello" ) ;
683
+ op. set_block_data (
684
+ header,
685
+ Some ( vec ! [ ] ) ,
686
+ None ,
687
+ true
688
+ ) . unwrap ( ) ;
689
+
690
+ db. commit_operation ( op) . unwrap ( ) ;
691
+
692
+ assert_eq ! ( db. db. get( :: columns:: STATE , & key. 0 [ ..] ) . unwrap( ) . unwrap( ) , & b"hello" [ ..] ) ;
693
+ }
694
+
695
+ {
696
+ let mut op = db. begin_operation ( BlockId :: Number ( 0 ) ) . unwrap ( ) ;
697
+ let mut header = block:: Header {
698
+ number : 1 ,
699
+ parent_hash : Default :: default ( ) ,
700
+ state_root : Default :: default ( ) ,
701
+ digest : Default :: default ( ) ,
702
+ extrinsics_root : Default :: default ( ) ,
703
+ } ;
704
+
705
+ let storage: Vec < ( _ , _ ) > = vec ! [ ] ;
706
+
707
+ header. state_root = op. old_state . storage_root ( storage
708
+ . iter ( )
709
+ . cloned ( )
710
+ . map ( |( x, y) | ( x, Some ( y) ) )
711
+ ) . 0 . into ( ) ;
712
+
713
+ op. updates . insert ( b"hello" ) ;
714
+ op. updates . remove ( & key) ;
715
+ op. set_block_data (
716
+ header,
717
+ Some ( vec ! [ ] ) ,
718
+ None ,
719
+ true
720
+ ) . unwrap ( ) ;
721
+
722
+ db. commit_operation ( op) . unwrap ( ) ;
723
+
724
+ assert_eq ! ( db. db. get( :: columns:: STATE , & key. 0 [ ..] ) . unwrap( ) . unwrap( ) , & b"hello" [ ..] ) ;
725
+ }
726
+
727
+ {
728
+ let mut op = db. begin_operation ( BlockId :: Number ( 1 ) ) . unwrap ( ) ;
729
+ let mut header = block:: Header {
730
+ number : 1 ,
731
+ parent_hash : Default :: default ( ) ,
732
+ state_root : Default :: default ( ) ,
733
+ digest : Default :: default ( ) ,
734
+ extrinsics_root : Default :: default ( ) ,
735
+ } ;
736
+
737
+ let storage: Vec < ( _ , _ ) > = vec ! [ ] ;
738
+
739
+ header. state_root = op. old_state . storage_root ( storage
740
+ . iter ( )
741
+ . cloned ( )
742
+ . map ( |( x, y) | ( x, Some ( y) ) )
743
+ ) . 0 . into ( ) ;
744
+
745
+ op. updates . remove ( & key) ;
746
+ op. set_block_data (
747
+ header,
748
+ Some ( vec ! [ ] ) ,
749
+ None ,
750
+ true
751
+ ) . unwrap ( ) ;
752
+
753
+ db. commit_operation ( op) . unwrap ( ) ;
754
+
755
+ assert ! ( db. db. get( :: columns:: STATE , & key. 0 [ ..] ) . unwrap( ) . is_none( ) ) ;
756
+ }
757
+ }
657
758
}
0 commit comments