cosmos-sdk/stack/prefixstore.go

135 lines
3.3 KiB
Go

package stack
import (
"bytes"
"errors"
"github.com/tendermint/basecoin/state"
)
type prefixStore struct {
prefix []byte
store state.SimpleDB
}
var _ state.SimpleDB = prefixStore{}
func (p prefixStore) Set(key, value []byte) {
key = append(p.prefix, key...)
p.store.Set(key, value)
}
func (p prefixStore) Get(key []byte) (value []byte) {
key = append(p.prefix, key...)
return p.store.Get(key)
}
func (p prefixStore) Has(key []byte) bool {
key = append(p.prefix, key...)
return p.store.Has(key)
}
func (p prefixStore) Remove(key []byte) (value []byte) {
key = append(p.prefix, key...)
return p.store.Remove(key)
}
func (p prefixStore) List(start, end []byte, limit int) []state.Model {
start = append(p.prefix, start...)
end = append(p.prefix, end...)
res := p.store.List(start, end, limit)
trim := len(p.prefix)
for i := range res {
res[i].Key = res[i].Key[trim:]
}
return res
}
func (p prefixStore) First(start, end []byte) state.Model {
start = append(p.prefix, start...)
end = append(p.prefix, end...)
res := p.store.First(start, end)
if len(res.Key) > 0 {
res.Key = res.Key[len(p.prefix):]
}
return res
}
func (p prefixStore) Last(start, end []byte) state.Model {
start = append(p.prefix, start...)
end = append(p.prefix, end...)
res := p.store.Last(start, end)
if len(res.Key) > 0 {
res.Key = res.Key[len(p.prefix):]
}
return res
}
func (p prefixStore) Checkpoint() state.SimpleDB {
return prefixStore{
prefix: p.prefix,
store: p.store.Checkpoint(),
}
}
func (p prefixStore) Commit(sub state.SimpleDB) error {
ps, ok := sub.(prefixStore)
if !ok {
return errors.New("Must commit prefixStore")
}
if !bytes.Equal(ps.prefix, p.prefix) {
return errors.New("Cannot commit sub-tx with different prefix")
}
// commit the wrapped data, don't worry about the prefix here
p.store.Commit(ps.store)
return nil
}
func (p prefixStore) Discard() {
p.store.Discard()
}
// stateSpace will unwrap any prefixStore and then add the prefix
//
// this can be used by the middleware and dispatcher to isolate one space,
// then unwrap and isolate another space
func stateSpace(store state.SimpleDB, app string) state.SimpleDB {
// unwrap one-level if wrapped
if pstore, ok := store.(prefixStore); ok {
store = pstore.store
}
return PrefixedStore(app, store)
}
func unwrap(store state.SimpleDB) state.SimpleDB {
// unwrap one-level if wrapped
if pstore, ok := store.(prefixStore); ok {
store = pstore.store
}
return store
}
// PrefixedStore allows one to create an isolated state-space for a given
// app prefix, but it cannot easily be unwrapped
//
// This is useful for tests or utilities that have access to the global
// state to check individual app spaces. Individual apps should not be able
// to use this to read each other's space
func PrefixedStore(app string, store state.SimpleDB) state.SimpleDB {
prefix := append([]byte(app), byte(0))
return prefixStore{prefix, store}
}
// PrefixedKey returns the absolute path to a given key in a particular
// app's state-space
//
// This is useful for tests or utilities that have access to the global
// state to check individual app spaces. Individual apps should not be able
// to use this to read each other's space
func PrefixedKey(app string, key []byte) []byte {
prefix := append([]byte(app), byte(0))
return append(prefix, key...)
}