135 lines
3.3 KiB
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...)
|
|
}
|