1
- // Copyright (c) 2020 IoTeX Foundation
1
+ // Copyright (c) 2024 IoTeX Foundation
2
2
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
3
3
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
4
4
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
@@ -27,25 +27,34 @@ import (
27
27
"github.com/iotexproject/iotex-core/v2/blockchain/genesis"
28
28
"github.com/iotexproject/iotex-core/v2/db"
29
29
"github.com/iotexproject/iotex-core/v2/db/batch"
30
+ "github.com/iotexproject/iotex-core/v2/pkg/lifecycle"
30
31
"github.com/iotexproject/iotex-core/v2/pkg/log"
31
32
"github.com/iotexproject/iotex-core/v2/pkg/prometheustimer"
32
- "github.com/iotexproject/iotex-core/v2/pkg/util/byteutil"
33
33
"github.com/iotexproject/iotex-core/v2/state"
34
34
)
35
35
36
- // stateDB implements StateFactory interface, tracks changes to account/contract and batch-commits to DB
37
- type stateDB struct {
38
- mutex sync.RWMutex
39
- currentChainHeight uint64
40
- cfg Config
41
- registry * protocol.Registry
42
- dao db.KVStore // the underlying DB for account/contract storage
43
- timerFactory * prometheustimer.TimerFactory
44
- workingsets cache.LRUCache // lru cache for workingsets
45
- protocolView protocol.View
46
- skipBlockValidationOnPut bool
47
- ps * patchStore
48
- }
36
+ type (
37
+ // daoRetrofitter represents the DAO-related methods to accommodate archive-mode
38
+ daoRetrofitter interface {
39
+ lifecycle.StartStopper
40
+ atHeight (uint64 ) db.KVStore
41
+ getHeight () (uint64 , error )
42
+ putHeight (uint64 ) error
43
+ }
44
+ // stateDB implements StateFactory interface, tracks changes to account/contract and batch-commits to DB
45
+ stateDB struct {
46
+ mutex sync.RWMutex
47
+ currentChainHeight uint64
48
+ cfg Config
49
+ registry * protocol.Registry
50
+ dao daoRetrofitter
51
+ timerFactory * prometheustimer.TimerFactory
52
+ workingsets cache.LRUCache // lru cache for workingsets
53
+ protocolView protocol.View
54
+ skipBlockValidationOnPut bool
55
+ ps * patchStore
56
+ }
57
+ )
49
58
50
59
// StateDBOption sets stateDB construction parameter
51
60
type StateDBOption func (* stateDB , * Config ) error
@@ -90,14 +99,14 @@ func NewStateDB(cfg Config, dao db.KVStore, opts ...StateDBOption) (Factory, err
90
99
registry : protocol .NewRegistry (),
91
100
protocolView : protocol.View {},
92
101
workingsets : cache .NewThreadSafeLruCache (int (cfg .Chain .WorkingSetCacheSize )),
93
- dao : dao ,
94
102
}
95
103
for _ , opt := range opts {
96
104
if err := opt (& sdb , & cfg ); err != nil {
97
105
log .S ().Errorf ("Failed to execute state factory creation option %p: %v" , opt , err )
98
106
return nil , err
99
107
}
100
108
}
109
+ sdb .dao = newDaoRetrofitter (dao )
101
110
timerFactory , err := prometheustimer .New (
102
111
"iotex_statefactory_perf" ,
103
112
"Performance of state factory module" ,
@@ -117,17 +126,17 @@ func (sdb *stateDB) Start(ctx context.Context) error {
117
126
return err
118
127
}
119
128
// check factory height
120
- h , err := sdb .dao .Get ( AccountKVNamespace , [] byte ( CurrentHeightKey ) )
129
+ h , err := sdb .dao .getHeight ( )
121
130
switch errors .Cause (err ) {
122
131
case nil :
123
- sdb .currentChainHeight = byteutil . BytesToUint64 ( h )
132
+ sdb .currentChainHeight = h
124
133
// start all protocols
125
134
if sdb .protocolView , err = sdb .registry .StartAll (ctx , sdb ); err != nil {
126
135
return err
127
136
}
128
137
case db .ErrNotExist :
129
138
sdb .currentChainHeight = 0
130
- if err = sdb .dao .Put ( AccountKVNamespace , [] byte ( CurrentHeightKey ), byteutil . Uint64ToBytes ( 0 ) ); err != nil {
139
+ if err = sdb .dao .putHeight ( 0 ); err != nil {
131
140
return errors .Wrap (err , "failed to init statedb's height" )
132
141
}
133
142
// start all protocols
@@ -150,7 +159,6 @@ func (sdb *stateDB) Start(ctx context.Context) error {
150
159
default :
151
160
return err
152
161
}
153
-
154
162
return nil
155
163
}
156
164
@@ -165,17 +173,13 @@ func (sdb *stateDB) Stop(ctx context.Context) error {
165
173
func (sdb * stateDB ) Height () (uint64 , error ) {
166
174
sdb .mutex .RLock ()
167
175
defer sdb .mutex .RUnlock ()
168
- height , err := sdb .dao .Get (AccountKVNamespace , []byte (CurrentHeightKey ))
169
- if err != nil {
170
- return 0 , errors .Wrap (err , "failed to get factory's height from underlying DB" )
171
- }
172
- return byteutil .BytesToUint64 (height ), nil
176
+ return sdb .dao .getHeight ()
173
177
}
174
178
175
179
func (sdb * stateDB ) newWorkingSet (ctx context.Context , height uint64 ) (* workingSet , error ) {
176
180
g := genesis .MustExtractGenesisContext (ctx )
177
181
flusher , err := db .NewKVStoreFlusher (
178
- sdb .dao ,
182
+ sdb .dao . atHeight ( height ) ,
179
183
batch .NewCachedBatch (),
180
184
sdb .flusherOptions (! g .IsEaster (height ))... ,
181
185
)
@@ -332,7 +336,7 @@ func (sdb *stateDB) State(s interface{}, opts ...protocol.StateOption) (uint64,
332
336
if cfg .Keys != nil {
333
337
return 0 , errors .Wrap (ErrNotSupported , "Read state with keys option has not been implemented yet" )
334
338
}
335
- return sdb .currentChainHeight , sdb .state (cfg .Namespace , cfg .Key , s )
339
+ return sdb .currentChainHeight , sdb .state (sdb . currentChainHeight , cfg .Namespace , cfg .Key , s )
336
340
}
337
341
338
342
// State returns a set of states in the state factory
@@ -346,7 +350,7 @@ func (sdb *stateDB) States(opts ...protocol.StateOption) (uint64, state.Iterator
346
350
if cfg .Key != nil {
347
351
return sdb .currentChainHeight , nil , errors .Wrap (ErrNotSupported , "Read states with key option has not been implemented yet" )
348
352
}
349
- keys , values , err := readStates (sdb .dao , cfg .Namespace , cfg .Keys )
353
+ keys , values , err := readStates (sdb .dao . atHeight ( sdb . currentChainHeight ) , cfg .Namespace , cfg .Keys )
350
354
if err != nil {
351
355
return 0 , nil , err
352
356
}
@@ -358,16 +362,6 @@ func (sdb *stateDB) States(opts ...protocol.StateOption) (uint64, state.Iterator
358
362
return sdb .currentChainHeight , iter , nil
359
363
}
360
364
361
- // StateAtHeight returns a confirmed state at height -- archive mode
362
- func (sdb * stateDB ) StateAtHeight (height uint64 , s interface {}, opts ... protocol.StateOption ) error {
363
- return ErrNotSupported
364
- }
365
-
366
- // StatesAtHeight returns a set states in the state factory at height -- archive mode
367
- func (sdb * stateDB ) StatesAtHeight (height uint64 , opts ... protocol.StateOption ) (state.Iterator , error ) {
368
- return nil , errors .Wrap (ErrNotSupported , "state db does not support archive mode" )
369
- }
370
-
371
365
// ReadView reads the view
372
366
func (sdb * stateDB ) ReadView (name string ) (interface {}, error ) {
373
367
return sdb .protocolView .Read (name )
@@ -397,8 +391,8 @@ func (sdb *stateDB) flusherOptions(preEaster bool) []db.KVStoreFlusherOption {
397
391
)
398
392
}
399
393
400
- func (sdb * stateDB ) state (ns string , addr []byte , s interface {}) error {
401
- data , err := sdb .dao .Get (ns , addr )
394
+ func (sdb * stateDB ) state (h uint64 , ns string , addr []byte , s interface {}) error {
395
+ data , err := sdb .dao .atHeight ( h ). Get (ns , addr )
402
396
if err != nil {
403
397
if errors .Cause (err ) == db .ErrNotExist {
404
398
return errors .Wrapf (state .ErrStateNotExist , "state of %x doesn't exist" , addr )
0 commit comments