162 lines
4.2 KiB
Go
162 lines
4.2 KiB
Go
|
package root
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"io"
|
||
|
|
||
|
dbm "github.com/cosmos/cosmos-sdk/db"
|
||
|
prefixdb "github.com/cosmos/cosmos-sdk/db/prefix"
|
||
|
util "github.com/cosmos/cosmos-sdk/internal"
|
||
|
dbutil "github.com/cosmos/cosmos-sdk/internal/db"
|
||
|
"github.com/cosmos/cosmos-sdk/store/cachekv"
|
||
|
"github.com/cosmos/cosmos-sdk/store/listenkv"
|
||
|
"github.com/cosmos/cosmos-sdk/store/tracekv"
|
||
|
types "github.com/cosmos/cosmos-sdk/store/v2"
|
||
|
"github.com/cosmos/cosmos-sdk/store/v2/smt"
|
||
|
)
|
||
|
|
||
|
var ErrReadOnly = errors.New("cannot modify read-only store")
|
||
|
|
||
|
func (s *viewSubstore) GetStateCommitmentStore() *smt.Store {
|
||
|
return s.stateCommitmentStore
|
||
|
}
|
||
|
|
||
|
// Get implements KVStore.
|
||
|
func (s *viewSubstore) Get(key []byte) []byte {
|
||
|
val, err := s.dataBucket.Get(key)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
// Has implements KVStore.
|
||
|
func (s *viewSubstore) Has(key []byte) bool {
|
||
|
has, err := s.dataBucket.Has(key)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return has
|
||
|
}
|
||
|
|
||
|
// Set implements KVStore.
|
||
|
func (s *viewSubstore) Set(key []byte, value []byte) {
|
||
|
panic(ErrReadOnly)
|
||
|
}
|
||
|
|
||
|
// Delete implements KVStore.
|
||
|
func (s *viewSubstore) Delete(key []byte) {
|
||
|
panic(ErrReadOnly)
|
||
|
}
|
||
|
|
||
|
// Iterator implements KVStore.
|
||
|
func (s *viewSubstore) Iterator(start, end []byte) types.Iterator {
|
||
|
iter, err := s.dataBucket.Iterator(start, end)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return dbutil.DBToStoreIterator(iter)
|
||
|
}
|
||
|
|
||
|
// ReverseIterator implements KVStore.
|
||
|
func (s *viewSubstore) ReverseIterator(start, end []byte) types.Iterator {
|
||
|
iter, err := s.dataBucket.ReverseIterator(start, end)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return dbutil.DBToStoreIterator(iter)
|
||
|
}
|
||
|
|
||
|
// GetStoreType implements Store.
|
||
|
func (s *viewSubstore) GetStoreType() types.StoreType {
|
||
|
return types.StoreTypePersistent
|
||
|
}
|
||
|
|
||
|
func (st *viewSubstore) CacheWrap() types.CacheWrap {
|
||
|
return cachekv.NewStore(st)
|
||
|
}
|
||
|
|
||
|
func (st *viewSubstore) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||
|
return cachekv.NewStore(tracekv.NewStore(st, w, tc))
|
||
|
}
|
||
|
|
||
|
func (st *viewSubstore) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap {
|
||
|
return cachekv.NewStore(listenkv.NewStore(st, storeKey, listeners))
|
||
|
}
|
||
|
|
||
|
func (store *Store) getView(version int64) (ret *viewStore, err error) {
|
||
|
stateView, err := store.stateDB.ReaderAt(uint64(version))
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
defer func() {
|
||
|
if err != nil {
|
||
|
err = util.CombineErrors(err, stateView.Discard(), "stateView.Discard also failed")
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
stateCommitmentView := stateView
|
||
|
if store.StateCommitmentDB != nil {
|
||
|
stateCommitmentView, err = store.StateCommitmentDB.ReaderAt(uint64(version))
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
defer func() {
|
||
|
if err != nil {
|
||
|
err = util.CombineErrors(err, stateCommitmentView.Discard(), "stateCommitmentView.Discard also failed")
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
// Now read this version's schema
|
||
|
schemaView := prefixdb.NewPrefixReader(stateView, schemaPrefix)
|
||
|
defer func() {
|
||
|
if err != nil {
|
||
|
err = util.CombineErrors(err, schemaView.Discard(), "schemaView.Discard also failed")
|
||
|
}
|
||
|
}()
|
||
|
pr, err := readSavedSchema(schemaView)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
// The migrated contents and schema are not committed until the next store.Commit
|
||
|
ret = &viewStore{
|
||
|
stateView: stateView,
|
||
|
stateCommitmentView: stateCommitmentView,
|
||
|
substoreCache: map[string]*viewSubstore{},
|
||
|
schema: pr.StoreSchema,
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (vs *viewStore) GetKVStore(skey types.StoreKey) types.KVStore {
|
||
|
key := skey.Name()
|
||
|
if _, has := vs.schema[key]; !has {
|
||
|
panic(ErrStoreNotFound(key))
|
||
|
}
|
||
|
ret, err := vs.getSubstore(key)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
vs.substoreCache[key] = ret
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// Reads but does not update substore cache
|
||
|
func (vs *viewStore) getSubstore(key string) (*viewSubstore, error) {
|
||
|
if cached, has := vs.substoreCache[key]; has {
|
||
|
return cached, nil
|
||
|
}
|
||
|
pfx := substorePrefix(key)
|
||
|
stateR := prefixdb.NewPrefixReader(vs.stateView, pfx)
|
||
|
stateCommitmentR := prefixdb.NewPrefixReader(vs.stateCommitmentView, pfx)
|
||
|
rootHash, err := stateR.Get(merkleRootKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &viewSubstore{
|
||
|
dataBucket: prefixdb.NewPrefixReader(stateR, dataPrefix),
|
||
|
indexBucket: prefixdb.NewPrefixReader(stateR, indexPrefix),
|
||
|
stateCommitmentStore: loadSMT(dbm.ReaderAsReadWriter(stateCommitmentR), rootHash),
|
||
|
}, nil
|
||
|
}
|