2
2
//! Keeps per-block state for rollbacks or per-epoch state for historical lookups
3
3
//! Use imbl collections in the state to avoid memory explosion!
4
4
5
- use crate :: params:: SECURITY_PARAMETER_K ;
6
5
use std:: collections:: VecDeque ;
7
-
8
6
use tracing:: info;
9
7
10
- pub enum HistoryKind {
11
- BlockState , // Used for rollbacks, bounded at k
12
- EpochState , // Used for historical lookups, unbounded
8
+ use crate :: params:: SECURITY_PARAMETER_K ;
9
+
10
+ pub enum StateHistoryStore {
11
+ Bounded ( u64 ) , // Used for rollbacks, bounded at k
12
+ Unbounded , // Used for historical lookups, unbounded
13
+ }
14
+
15
+ impl StateHistoryStore {
16
+ pub fn default_block_store ( ) -> Self {
17
+ Self :: Bounded ( SECURITY_PARAMETER_K )
18
+ }
13
19
}
14
20
15
21
struct HistoryEntry < S > {
@@ -25,17 +31,16 @@ pub struct StateHistory<S> {
25
31
/// Module name
26
32
module : String ,
27
33
28
- // Block or Epoch based history
29
- kind : HistoryKind ,
34
+ store : StateHistoryStore ,
30
35
}
31
36
32
37
impl < S : Clone + Default > StateHistory < S > {
33
38
/// Construct
34
- pub fn new ( module : & str , kind : HistoryKind ) -> Self {
39
+ pub fn new ( module : & str , store : StateHistoryStore ) -> Self {
35
40
Self {
36
41
history : VecDeque :: new ( ) ,
37
42
module : module. to_string ( ) ,
38
- kind : kind ,
43
+ store ,
39
44
}
40
45
}
41
46
@@ -50,38 +55,25 @@ impl<S: Clone + Default> StateHistory<S> {
50
55
self . history . back ( ) . map ( |entry| entry. state . clone ( ) ) . unwrap_or_default ( )
51
56
}
52
57
58
+ /// Get all the states references in the history
59
+ pub fn values ( & self ) -> Vec < & S > {
60
+ self . history . iter ( ) . map ( |entry| & entry. state ) . collect ( )
61
+ }
62
+
53
63
/// Get the previous state for the given block, handling rollbacks if required
54
64
/// State returned is cloned ready for modification - call commit() when done
55
65
pub fn get_rolled_back_state ( & mut self , index : u64 ) -> S {
56
- match self . kind {
57
- HistoryKind :: BlockState => {
58
- while let Some ( entry) = self . history . back ( ) {
59
- if entry. index >= index {
60
- info ! (
61
- "{} rolling back state to {} removing block {}" ,
62
- self . module, index, entry. index
63
- ) ;
64
- self . history . pop_back ( ) ;
65
- } else {
66
- break ;
67
- }
68
- }
69
- }
70
- HistoryKind :: EpochState => {
71
- while let Some ( entry) = self . history . back ( ) {
72
- if entry. index >= index {
73
- info ! (
74
- "{} rolling back epoch state to {} removing epoch {}" ,
75
- self . module, index, entry. index
76
- ) ;
77
- self . history . pop_back ( ) ;
78
- } else {
79
- break ;
80
- }
81
- }
66
+ while let Some ( entry) = self . history . back ( ) {
67
+ if entry. index >= index {
68
+ info ! (
69
+ "{} rolling back state to {} removing block {}" ,
70
+ self . module, index, entry. index
71
+ ) ;
72
+ self . history . pop_back ( ) ;
73
+ } else {
74
+ break ;
82
75
}
83
76
}
84
-
85
77
self . get_current_state ( )
86
78
}
87
79
@@ -90,20 +82,36 @@ impl<S: Clone + Default> StateHistory<S> {
90
82
self . history . iter ( ) . find ( |entry| entry. index == index) . map ( |entry| & entry. state )
91
83
}
92
84
85
+ /// Return a reference to the state at the given block number, if it exists
86
+ pub fn get_by_index_reverse ( & self , index : u64 ) -> Option < & S > {
87
+ self . history . iter ( ) . rev ( ) . find ( |entry| entry. index == index) . map ( |entry| & entry. state )
88
+ }
89
+
90
+ /// Get state history's size
93
91
pub fn len ( & self ) -> usize {
94
92
self . history . len ( )
95
93
}
96
94
95
+ /// Commit new state without checking the block number
96
+ /// TODO: enhance block number logic to commit state without check (for bootstrapping)
97
+ pub fn commit_forced ( & mut self , state : S ) {
98
+ self . history . push_back ( HistoryEntry { index : 0 , state } ) ;
99
+ }
100
+
97
101
/// Commit the new state
98
102
pub fn commit ( & mut self , index : u64 , state : S ) {
99
- match self . kind {
100
- HistoryKind :: BlockState => {
101
- while self . history . len ( ) >= SECURITY_PARAMETER_K as usize {
102
- self . history . pop_front ( ) ;
103
+ match self . store {
104
+ StateHistoryStore :: Bounded ( k) => {
105
+ while let Some ( entry) = self . history . front ( ) {
106
+ if ( index - entry. index ) > k {
107
+ self . history . pop_front ( ) ;
108
+ } else {
109
+ break ;
110
+ }
103
111
}
104
112
self . history . push_back ( HistoryEntry { index, state } ) ;
105
113
}
106
- HistoryKind :: EpochState => {
114
+ StateHistoryStore :: Unbounded => {
107
115
self . history . push_back ( HistoryEntry { index, state } ) ;
108
116
}
109
117
}
@@ -122,4 +130,9 @@ impl<S: Clone> StateHistory<S> {
122
130
init ( )
123
131
}
124
132
}
133
+
134
+ /// Clear the history
135
+ pub fn clear ( & mut self ) {
136
+ self . history . clear ( ) ;
137
+ }
125
138
}
0 commit comments