Skip to content

Commit 55e5e1c

Browse files
authored
[factory] add daoRetrofitter interface (#4522)
1 parent 6ac9264 commit 55e5e1c

File tree

2 files changed

+83
-40
lines changed

2 files changed

+83
-40
lines changed

state/factory/daoretrofitter.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) 2024 IoTeX Foundation
2+
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
3+
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
4+
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
5+
6+
package factory
7+
8+
import (
9+
"context"
10+
11+
"github.com/pkg/errors"
12+
13+
"github.com/iotexproject/iotex-core/v2/db"
14+
"github.com/iotexproject/iotex-core/v2/pkg/util/byteutil"
15+
)
16+
17+
type daoRTF struct {
18+
dao db.KVStore
19+
}
20+
21+
func newDaoRetrofitter(dao db.KVStore) *daoRTF {
22+
return &daoRTF{
23+
dao: dao,
24+
}
25+
}
26+
27+
func (rtf *daoRTF) Start(ctx context.Context) error {
28+
return rtf.dao.Start(ctx)
29+
}
30+
31+
func (rtf *daoRTF) Stop(ctx context.Context) error {
32+
return rtf.dao.Stop(ctx)
33+
}
34+
35+
func (rtf *daoRTF) atHeight(uint64) db.KVStore {
36+
return rtf.dao
37+
}
38+
39+
func (rtf *daoRTF) getHeight() (uint64, error) {
40+
height, err := rtf.dao.Get(AccountKVNamespace, []byte(CurrentHeightKey))
41+
if err != nil {
42+
return 0, errors.Wrap(err, "failed to get factory's height from underlying DB")
43+
}
44+
return byteutil.BytesToUint64(height), nil
45+
}
46+
47+
func (rtf *daoRTF) putHeight(h uint64) error {
48+
return rtf.dao.Put(AccountKVNamespace, []byte(CurrentHeightKey), byteutil.Uint64ToBytes(h))
49+
}

state/factory/statedb.go

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2020 IoTeX Foundation
1+
// Copyright (c) 2024 IoTeX Foundation
22
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
33
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
44
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
@@ -27,25 +27,34 @@ import (
2727
"github.com/iotexproject/iotex-core/v2/blockchain/genesis"
2828
"github.com/iotexproject/iotex-core/v2/db"
2929
"github.com/iotexproject/iotex-core/v2/db/batch"
30+
"github.com/iotexproject/iotex-core/v2/pkg/lifecycle"
3031
"github.com/iotexproject/iotex-core/v2/pkg/log"
3132
"github.com/iotexproject/iotex-core/v2/pkg/prometheustimer"
32-
"github.com/iotexproject/iotex-core/v2/pkg/util/byteutil"
3333
"github.com/iotexproject/iotex-core/v2/state"
3434
)
3535

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+
)
4958

5059
// StateDBOption sets stateDB construction parameter
5160
type StateDBOption func(*stateDB, *Config) error
@@ -90,14 +99,14 @@ func NewStateDB(cfg Config, dao db.KVStore, opts ...StateDBOption) (Factory, err
9099
registry: protocol.NewRegistry(),
91100
protocolView: protocol.View{},
92101
workingsets: cache.NewThreadSafeLruCache(int(cfg.Chain.WorkingSetCacheSize)),
93-
dao: dao,
94102
}
95103
for _, opt := range opts {
96104
if err := opt(&sdb, &cfg); err != nil {
97105
log.S().Errorf("Failed to execute state factory creation option %p: %v", opt, err)
98106
return nil, err
99107
}
100108
}
109+
sdb.dao = newDaoRetrofitter(dao)
101110
timerFactory, err := prometheustimer.New(
102111
"iotex_statefactory_perf",
103112
"Performance of state factory module",
@@ -117,17 +126,17 @@ func (sdb *stateDB) Start(ctx context.Context) error {
117126
return err
118127
}
119128
// check factory height
120-
h, err := sdb.dao.Get(AccountKVNamespace, []byte(CurrentHeightKey))
129+
h, err := sdb.dao.getHeight()
121130
switch errors.Cause(err) {
122131
case nil:
123-
sdb.currentChainHeight = byteutil.BytesToUint64(h)
132+
sdb.currentChainHeight = h
124133
// start all protocols
125134
if sdb.protocolView, err = sdb.registry.StartAll(ctx, sdb); err != nil {
126135
return err
127136
}
128137
case db.ErrNotExist:
129138
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 {
131140
return errors.Wrap(err, "failed to init statedb's height")
132141
}
133142
// start all protocols
@@ -150,7 +159,6 @@ func (sdb *stateDB) Start(ctx context.Context) error {
150159
default:
151160
return err
152161
}
153-
154162
return nil
155163
}
156164

@@ -165,17 +173,13 @@ func (sdb *stateDB) Stop(ctx context.Context) error {
165173
func (sdb *stateDB) Height() (uint64, error) {
166174
sdb.mutex.RLock()
167175
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()
173177
}
174178

175179
func (sdb *stateDB) newWorkingSet(ctx context.Context, height uint64) (*workingSet, error) {
176180
g := genesis.MustExtractGenesisContext(ctx)
177181
flusher, err := db.NewKVStoreFlusher(
178-
sdb.dao,
182+
sdb.dao.atHeight(height),
179183
batch.NewCachedBatch(),
180184
sdb.flusherOptions(!g.IsEaster(height))...,
181185
)
@@ -332,7 +336,7 @@ func (sdb *stateDB) State(s interface{}, opts ...protocol.StateOption) (uint64,
332336
if cfg.Keys != nil {
333337
return 0, errors.Wrap(ErrNotSupported, "Read state with keys option has not been implemented yet")
334338
}
335-
return sdb.currentChainHeight, sdb.state(cfg.Namespace, cfg.Key, s)
339+
return sdb.currentChainHeight, sdb.state(sdb.currentChainHeight, cfg.Namespace, cfg.Key, s)
336340
}
337341

338342
// State returns a set of states in the state factory
@@ -346,7 +350,7 @@ func (sdb *stateDB) States(opts ...protocol.StateOption) (uint64, state.Iterator
346350
if cfg.Key != nil {
347351
return sdb.currentChainHeight, nil, errors.Wrap(ErrNotSupported, "Read states with key option has not been implemented yet")
348352
}
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)
350354
if err != nil {
351355
return 0, nil, err
352356
}
@@ -358,16 +362,6 @@ func (sdb *stateDB) States(opts ...protocol.StateOption) (uint64, state.Iterator
358362
return sdb.currentChainHeight, iter, nil
359363
}
360364

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-
371365
// ReadView reads the view
372366
func (sdb *stateDB) ReadView(name string) (interface{}, error) {
373367
return sdb.protocolView.Read(name)
@@ -397,8 +391,8 @@ func (sdb *stateDB) flusherOptions(preEaster bool) []db.KVStoreFlusherOption {
397391
)
398392
}
399393

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)
402396
if err != nil {
403397
if errors.Cause(err) == db.ErrNotExist {
404398
return errors.Wrapf(state.ErrStateNotExist, "state of %x doesn't exist", addr)

0 commit comments

Comments
 (0)