Merge PR #1481: Transient Stores

This commit is contained in:
Joon 2018-07-26 18:24:18 -07:00 committed by Christopher Goes
parent 74e06d8b96
commit d46140a392
27 changed files with 361 additions and 140 deletions

View File

@ -35,6 +35,7 @@ FEATURES
* [cosmos-sdk-cli] Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd * [cosmos-sdk-cli] Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd
* This allows SDK users to initialize a new project repository. * This allows SDK users to initialize a new project repository.
* [tests] Remotenet commands for AWS (awsnet) * [tests] Remotenet commands for AWS (awsnet)
* [store] Add transient store
IMPROVEMENTS IMPROVEMENTS
* [baseapp] Allow any alphanumeric character in route * [baseapp] Allow any alphanumeric character in route

View File

@ -47,6 +47,7 @@ type GaiaApp struct {
keyGov *sdk.KVStoreKey keyGov *sdk.KVStoreKey
keyFeeCollection *sdk.KVStoreKey keyFeeCollection *sdk.KVStoreKey
keyParams *sdk.KVStoreKey keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// Manage getting and setting accounts // Manage getting and setting accounts
accountMapper auth.AccountMapper accountMapper auth.AccountMapper
@ -77,6 +78,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
keyGov: sdk.NewKVStoreKey("gov"), keyGov: sdk.NewKVStoreKey("gov"),
keyFeeCollection: sdk.NewKVStoreKey("fee"), keyFeeCollection: sdk.NewKVStoreKey("fee"),
keyParams: sdk.NewKVStoreKey("params"), keyParams: sdk.NewKVStoreKey("params"),
tkeyParams: sdk.NewTransientStoreKey("params"),
} }
// define the accountMapper // define the accountMapper
@ -109,6 +111,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
app.SetEndBlocker(app.EndBlocker) app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
app.MountStore(app.tkeyParams, sdk.StoreTypeTransient)
err := app.LoadLatestVersion(app.keyMain) err := app.LoadLatestVersion(app.keyMain)
if err != nil { if err != nil {
cmn.Exit(err.Error()) cmn.Exit(err.Error())

BIN
cmd/gaia/cmd/gaiadebug/gaiadebug Executable file

Binary file not shown.

View File

@ -11,7 +11,7 @@ import (
type ValidatorSet struct { type ValidatorSet struct {
sdk.ValidatorSet sdk.ValidatorSet
key sdk.KVStoreGetter store sdk.KVStore
cdc *wire.Codec cdc *wire.Codec
maxAssoc int maxAssoc int
@ -21,14 +21,14 @@ type ValidatorSet struct {
var _ sdk.ValidatorSet = ValidatorSet{} var _ sdk.ValidatorSet = ValidatorSet{}
// NewValidatorSet returns new ValidatorSet with underlying ValidatorSet // NewValidatorSet returns new ValidatorSet with underlying ValidatorSet
func NewValidatorSet(cdc *wire.Codec, key sdk.KVStoreGetter, valset sdk.ValidatorSet, maxAssoc int, addrLen int) ValidatorSet { func NewValidatorSet(cdc *wire.Codec, store sdk.KVStore, valset sdk.ValidatorSet, maxAssoc int, addrLen int) ValidatorSet {
if maxAssoc < 0 || addrLen < 0 { if maxAssoc < 0 || addrLen < 0 {
panic("Cannot use negative integer for NewValidatorSet") panic("Cannot use negative integer for NewValidatorSet")
} }
return ValidatorSet{ return ValidatorSet{
ValidatorSet: valset, ValidatorSet: valset,
key: key, store: store,
cdc: cdc, cdc: cdc,
maxAssoc: maxAssoc, maxAssoc: maxAssoc,
@ -38,8 +38,7 @@ func NewValidatorSet(cdc *wire.Codec, key sdk.KVStoreGetter, valset sdk.Validato
// Implements sdk.ValidatorSet // Implements sdk.ValidatorSet
func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res sdk.Validator) { func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res sdk.Validator) {
store := valset.key.KVStore(ctx) base := valset.store.Get(GetBaseKey(addr))
base := store.Get(GetBaseKey(addr))
res = valset.ValidatorSet.Validator(ctx, base) res = valset.ValidatorSet.Validator(ctx, base)
if res == nil { if res == nil {
res = valset.ValidatorSet.Validator(ctx, addr) res = valset.ValidatorSet.Validator(ctx, addr)
@ -67,13 +66,12 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.AccAddress, assoc
if len(base) != valset.addrLen || len(assoc) != valset.addrLen { if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false return false
} }
store := valset.key.KVStore(ctx)
// If someone already owns the associated address // If someone already owns the associated address
if store.Get(GetBaseKey(assoc)) != nil { if valset.store.Get(GetBaseKey(assoc)) != nil {
return false return false
} }
store.Set(GetBaseKey(assoc), base) valset.store.Set(GetBaseKey(assoc), base)
store.Set(GetAssocKey(base, assoc), []byte{0x00}) valset.store.Set(GetAssocKey(base, assoc), []byte{0x00})
return true return true
} }
@ -82,21 +80,19 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, asso
if len(base) != valset.addrLen || len(assoc) != valset.addrLen { if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false return false
} }
store := valset.key.KVStore(ctx)
// No associated address found for given validator // No associated address found for given validator
if !bytes.Equal(store.Get(GetBaseKey(assoc)), base) { if !bytes.Equal(valset.store.Get(GetBaseKey(assoc)), base) {
return false return false
} }
store.Delete(GetBaseKey(assoc)) valset.store.Delete(GetBaseKey(assoc))
store.Delete(GetAssocKey(base, assoc)) valset.store.Delete(GetAssocKey(base, assoc))
return true return true
} }
// Associations returns all associated addresses with a validator // Associations returns all associated addresses with a validator
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.AccAddress) (res []sdk.AccAddress) { func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.AccAddress) (res []sdk.AccAddress) {
store := valset.key.KVStore(ctx)
res = make([]sdk.AccAddress, valset.maxAssoc) res = make([]sdk.AccAddress, valset.maxAssoc)
iter := sdk.KVStorePrefixIterator(store, GetAssocPrefix(base)) iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
i := 0 i := 0
for ; iter.Valid(); iter.Next() { for ; iter.Valid(); iter.Next() {
key := iter.Key() key := iter.Key()

View File

@ -36,7 +36,7 @@ func TestValidatorSet(t *testing.T) {
{addr2, sdk.NewRat(2)}, {addr2, sdk.NewRat(2)},
}} }}
valset := NewValidatorSet(wire.NewCodec(), sdk.NewPrefixStoreGetter(key, []byte("assoc")), base, 1, 5) valset := NewValidatorSet(wire.NewCodec(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5)
require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1))
require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2))

View File

@ -26,7 +26,7 @@ func (keeper Keeper) update(ctx sdk.Context, val sdk.Validator, valset sdk.Valid
info.Power = sdk.ZeroRat() info.Power = sdk.ZeroRat()
info.Hash = hash info.Hash = hash
prefix := GetSignPrefix(p, keeper.cdc) prefix := GetSignPrefix(p, keeper.cdc)
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
iter := sdk.KVStorePrefixIterator(store, prefix) iter := sdk.KVStorePrefixIterator(store, prefix)
for ; iter.Valid(); iter.Next() { for ; iter.Valid(); iter.Next() {
if valset.Validator(ctx, iter.Value()) != nil { if valset.Validator(ctx, iter.Value()) != nil {

View File

@ -8,7 +8,7 @@ import (
// Keeper of the oracle store // Keeper of the oracle store
type Keeper struct { type Keeper struct {
key sdk.KVStoreGetter key sdk.StoreKey
cdc *wire.Codec cdc *wire.Codec
valset sdk.ValidatorSet valset sdk.ValidatorSet
@ -18,7 +18,7 @@ type Keeper struct {
} }
// NewKeeper constructs a new keeper // NewKeeper constructs a new keeper
func NewKeeper(key sdk.KVStoreGetter, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper { func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper {
if timeout < 0 { if timeout < 0 {
panic("Timeout should not be negative") panic("Timeout should not be negative")
} }
@ -64,7 +64,7 @@ func EmptyInfo(ctx sdk.Context) Info {
// Info returns the information about a payload // Info returns the information about a payload
func (keeper Keeper) Info(ctx sdk.Context, p Payload) (res Info) { func (keeper Keeper) Info(ctx sdk.Context, p Payload) (res Info) {
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
key := GetInfoKey(p, keeper.cdc) key := GetInfoKey(p, keeper.cdc)
bz := store.Get(key) bz := store.Get(key)
@ -77,7 +77,7 @@ func (keeper Keeper) Info(ctx sdk.Context, p Payload) (res Info) {
} }
func (keeper Keeper) setInfo(ctx sdk.Context, p Payload, info Info) { func (keeper Keeper) setInfo(ctx sdk.Context, p Payload, info Info) {
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
key := GetInfoKey(p, keeper.cdc) key := GetInfoKey(p, keeper.cdc)
bz := keeper.cdc.MustMarshalBinary(info) bz := keeper.cdc.MustMarshalBinary(info)
@ -85,21 +85,21 @@ func (keeper Keeper) setInfo(ctx sdk.Context, p Payload, info Info) {
} }
func (keeper Keeper) sign(ctx sdk.Context, p Payload, signer sdk.AccAddress) { func (keeper Keeper) sign(ctx sdk.Context, p Payload, signer sdk.AccAddress) {
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
key := GetSignKey(p, signer, keeper.cdc) key := GetSignKey(p, signer, keeper.cdc)
store.Set(key, signer) store.Set(key, signer)
} }
func (keeper Keeper) signed(ctx sdk.Context, p Payload, signer sdk.AccAddress) bool { func (keeper Keeper) signed(ctx sdk.Context, p Payload, signer sdk.AccAddress) bool {
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
key := GetSignKey(p, signer, keeper.cdc) key := GetSignKey(p, signer, keeper.cdc)
return store.Has(key) return store.Has(key)
} }
func (keeper Keeper) clearSigns(ctx sdk.Context, p Payload) { func (keeper Keeper) clearSigns(ctx sdk.Context, p Payload) {
store := keeper.key.KVStore(ctx) store := ctx.KVStore(keeper.key)
prefix := GetSignPrefix(p, keeper.cdc) prefix := GetSignPrefix(p, keeper.cdc)

View File

@ -119,7 +119,7 @@ func TestOracle(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz})
ork := NewKeeper(sdk.NewPrefixStoreGetter(key, []byte("oracle")), cdc, valset, sdk.NewRat(2, 3), 100) ork := NewKeeper(key, cdc, valset, sdk.NewRat(2, 3), 100)
h := seqHandler(ork, key, sdk.CodespaceRoot) h := seqHandler(ork, key, sdk.CodespaceRoot)
// Nonmock.Validator signed, transaction failed // Nonmock.Validator signed, transaction failed

View File

@ -8,6 +8,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
var _ sdk.MultiStore = multiStore{}
type multiStore struct { type multiStore struct {
kv map[sdk.StoreKey]kvStore kv map[sdk.StoreKey]kvStore
} }
@ -76,10 +78,6 @@ func (ms multiStore) GetKVStore(key sdk.StoreKey) sdk.KVStore {
return ms.kv[key] return ms.kv[key]
} }
func (ms multiStore) GetKVStoreWithGas(meter sdk.GasMeter, key sdk.StoreKey) sdk.KVStore {
panic("not implemented")
}
func (ms multiStore) GetStore(key sdk.StoreKey) sdk.Store { func (ms multiStore) GetStore(key sdk.StoreKey) sdk.Store {
panic("not implemented") panic("not implemented")
} }
@ -88,6 +86,8 @@ func (ms multiStore) GetStoreType() sdk.StoreType {
panic("not implemented") panic("not implemented")
} }
var _ sdk.KVStore = kvStore{}
type kvStore struct { type kvStore struct {
store map[string][]byte store map[string][]byte
} }
@ -129,6 +129,10 @@ func (kv kvStore) Prefix(prefix []byte) sdk.KVStore {
panic("not implemented") panic("not implemented")
} }
func (kv kvStore) Gas(meter sdk.GasMeter, config sdk.GasConfig) sdk.KVStore {
panic("not implmeneted")
}
func (kv kvStore) Iterator(start, end []byte) sdk.Iterator { func (kv kvStore) Iterator(start, end []byte) sdk.Iterator {
panic("not implemented") panic("not implemented")
} }

View File

@ -85,6 +85,11 @@ func (ci *cacheKVStore) Prefix(prefix []byte) KVStore {
return prefixStore{ci, prefix} return prefixStore{ci, prefix}
} }
// Implements KVStore
func (ci *cacheKVStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, ci)
}
// Implements CacheKVStore. // Implements CacheKVStore.
func (ci *cacheKVStore) Write() { func (ci *cacheKVStore) Write() {
ci.mtx.Lock() ci.mtx.Lock()

View File

@ -134,6 +134,6 @@ func (cms cacheMultiStore) GetKVStore(key StoreKey) KVStore {
} }
// Implements MultiStore. // Implements MultiStore.
func (cms cacheMultiStore) GetKVStoreWithGas(meter sdk.GasMeter, key StoreKey) KVStore { func (cms cacheMultiStore) GetKVStoreWithGas(meter sdk.GasMeter, config sdk.GasConfig, key StoreKey) KVStore {
return NewGasKVStore(meter, cms.GetKVStore(key)) return NewGasKVStore(meter, config, cms.GetKVStore(key))
} }

View File

@ -7,6 +7,7 @@ import (
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"
) )
// Wrapper type for dbm.Db with implementation of KVStore
type dbStoreAdapter struct { type dbStoreAdapter struct {
dbm.DB dbm.DB
} }
@ -31,5 +32,10 @@ func (dsa dbStoreAdapter) Prefix(prefix []byte) KVStore {
return prefixStore{dsa, prefix} return prefixStore{dsa, prefix}
} }
// Implements KVStore
func (dsa dbStoreAdapter) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, dsa)
}
// dbm.DB implements KVStore so we can CacheKVStore it. // dbm.DB implements KVStore so we can CacheKVStore it.
var _ KVStore = dbStoreAdapter{dbm.DB(nil)} var _ KVStore = dbStoreAdapter{}

View File

@ -6,28 +6,20 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
// nolint var _ KVStore = &gasKVStore{}
const (
HasCost = 10
ReadCostFlat = 10
ReadCostPerByte = 1
WriteCostFlat = 10
WriteCostPerByte = 10
KeyCostFlat = 5
ValueCostFlat = 10
ValueCostPerByte = 1
)
// gasKVStore applies gas tracking to an underlying kvstore // gasKVStore applies gas tracking to an underlying kvstore
type gasKVStore struct { type gasKVStore struct {
gasMeter sdk.GasMeter gasMeter sdk.GasMeter
gasConfig sdk.GasConfig
parent sdk.KVStore parent sdk.KVStore
} }
// nolint // nolint
func NewGasKVStore(gasMeter sdk.GasMeter, parent sdk.KVStore) *gasKVStore { func NewGasKVStore(gasMeter sdk.GasMeter, gasConfig sdk.GasConfig, parent sdk.KVStore) *gasKVStore {
kvs := &gasKVStore{ kvs := &gasKVStore{
gasMeter: gasMeter, gasMeter: gasMeter,
gasConfig: gasConfig,
parent: parent, parent: parent,
} }
return kvs return kvs
@ -40,24 +32,25 @@ func (gi *gasKVStore) GetStoreType() sdk.StoreType {
// Implements KVStore. // Implements KVStore.
func (gi *gasKVStore) Get(key []byte) (value []byte) { func (gi *gasKVStore) Get(key []byte) (value []byte) {
gi.gasMeter.ConsumeGas(ReadCostFlat, "GetFlat") gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostFlat, "ReadFlat")
value = gi.parent.Get(key) value = gi.parent.Get(key)
// TODO overflow-safe math? // TODO overflow-safe math?
gi.gasMeter.ConsumeGas(ReadCostPerByte*sdk.Gas(len(value)), "ReadPerByte") gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*sdk.Gas(len(value)), "ReadPerByte")
return value return value
} }
// Implements KVStore. // Implements KVStore.
func (gi *gasKVStore) Set(key []byte, value []byte) { func (gi *gasKVStore) Set(key []byte, value []byte) {
gi.gasMeter.ConsumeGas(WriteCostFlat, "SetFlat") gi.gasMeter.ConsumeGas(gi.gasConfig.WriteCostFlat, "WriteFlat")
// TODO overflow-safe math? // TODO overflow-safe math?
gi.gasMeter.ConsumeGas(WriteCostPerByte*sdk.Gas(len(value)), "SetPerByte") gi.gasMeter.ConsumeGas(gi.gasConfig.WriteCostPerByte*sdk.Gas(len(value)), "WritePerByte")
gi.parent.Set(key, value) gi.parent.Set(key, value)
} }
// Implements KVStore. // Implements KVStore.
func (gi *gasKVStore) Has(key []byte) bool { func (gi *gasKVStore) Has(key []byte) bool {
gi.gasMeter.ConsumeGas(HasCost, "Has") gi.gasMeter.ConsumeGas(gi.gasConfig.HasCost, "Has")
return gi.parent.Has(key) return gi.parent.Has(key)
} }
@ -69,7 +62,17 @@ func (gi *gasKVStore) Delete(key []byte) {
// Implements KVStore // Implements KVStore
func (gi *gasKVStore) Prefix(prefix []byte) KVStore { func (gi *gasKVStore) Prefix(prefix []byte) KVStore {
return prefixStore{gi, prefix} // Keep gasstore layer at the top
return &gasKVStore{
gasMeter: gi.gasMeter,
gasConfig: gi.gasConfig,
parent: prefixStore{gi.parent, prefix},
}
}
// Implements KVStore
func (gi *gasKVStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, gi)
} }
// Implements KVStore. // Implements KVStore.
@ -99,17 +102,19 @@ func (gi *gasKVStore) iterator(start, end []byte, ascending bool) sdk.Iterator {
} else { } else {
parent = gi.parent.ReverseIterator(start, end) parent = gi.parent.ReverseIterator(start, end)
} }
return newGasIterator(gi.gasMeter, parent) return newGasIterator(gi.gasMeter, gi.gasConfig, parent)
} }
type gasIterator struct { type gasIterator struct {
gasMeter sdk.GasMeter gasMeter sdk.GasMeter
gasConfig sdk.GasConfig
parent sdk.Iterator parent sdk.Iterator
} }
func newGasIterator(gasMeter sdk.GasMeter, parent sdk.Iterator) sdk.Iterator { func newGasIterator(gasMeter sdk.GasMeter, gasConfig sdk.GasConfig, parent sdk.Iterator) sdk.Iterator {
return &gasIterator{ return &gasIterator{
gasMeter: gasMeter, gasMeter: gasMeter,
gasConfig: gasConfig,
parent: parent, parent: parent,
} }
} }
@ -131,7 +136,7 @@ func (g *gasIterator) Next() {
// Implements Iterator. // Implements Iterator.
func (g *gasIterator) Key() (key []byte) { func (g *gasIterator) Key() (key []byte) {
g.gasMeter.ConsumeGas(KeyCostFlat, "KeyFlat") g.gasMeter.ConsumeGas(g.gasConfig.KeyCostFlat, "KeyFlat")
key = g.parent.Key() key = g.parent.Key()
return key return key
} }
@ -139,8 +144,8 @@ func (g *gasIterator) Key() (key []byte) {
// Implements Iterator. // Implements Iterator.
func (g *gasIterator) Value() (value []byte) { func (g *gasIterator) Value() (value []byte) {
value = g.parent.Value() value = g.parent.Value()
g.gasMeter.ConsumeGas(ValueCostFlat, "ValueFlat") g.gasMeter.ConsumeGas(g.gasConfig.ValueCostFlat, "ValueFlat")
g.gasMeter.ConsumeGas(ValueCostPerByte*sdk.Gas(len(value)), "ValuePerByte") g.gasMeter.ConsumeGas(g.gasConfig.ValueCostPerByte*sdk.Gas(len(value)), "ValuePerByte")
return value return value
} }

View File

@ -3,21 +3,23 @@ package store
import ( import (
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
) )
func newGasKVStore() KVStore { func newGasKVStore() KVStore {
meter := sdk.NewGasMeter(1000) meter := sdk.NewGasMeter(1000)
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
return NewGasKVStore(meter, mem) return NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
} }
func TestGasKVStoreBasic(t *testing.T) { func TestGasKVStoreBasic(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(1000) meter := sdk.NewGasMeter(1000)
st := NewGasKVStore(meter, mem) st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
st.Set(keyFmt(1), valFmt(1)) st.Set(keyFmt(1), valFmt(1))
require.Equal(t, valFmt(1), st.Get(keyFmt(1))) require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
@ -29,7 +31,7 @@ func TestGasKVStoreBasic(t *testing.T) {
func TestGasKVStoreIterator(t *testing.T) { func TestGasKVStoreIterator(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(1000) meter := sdk.NewGasMeter(1000)
st := NewGasKVStore(meter, mem) st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty") require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty")
st.Set(keyFmt(1), valFmt(1)) st.Set(keyFmt(1), valFmt(1))
@ -53,16 +55,51 @@ func TestGasKVStoreIterator(t *testing.T) {
func TestGasKVStoreOutOfGasSet(t *testing.T) { func TestGasKVStoreOutOfGasSet(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(0) meter := sdk.NewGasMeter(0)
st := NewGasKVStore(meter, mem) st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas") require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas")
} }
func TestGasKVStoreOutOfGasIterator(t *testing.T) { func TestGasKVStoreOutOfGasIterator(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(200) meter := sdk.NewGasMeter(200)
st := NewGasKVStore(meter, mem) st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
st.Set(keyFmt(1), valFmt(1)) st.Set(keyFmt(1), valFmt(1))
iterator := st.Iterator(nil, nil) iterator := st.Iterator(nil, nil)
iterator.Next() iterator.Next()
require.Panics(t, func() { iterator.Value() }, "Expected out-of-gas") require.Panics(t, func() { iterator.Value() }, "Expected out-of-gas")
} }
func testGasKVStoreWrap(t *testing.T, store KVStore) {
meter := sdk.NewGasMeter(10000)
store = store.Gas(meter, sdk.GasConfig{HasCost: 10})
require.Equal(t, int64(0), meter.GasConsumed())
store.Has([]byte("key"))
require.Equal(t, int64(10), meter.GasConsumed())
store = store.Gas(meter, sdk.GasConfig{HasCost: 20})
store.Has([]byte("key"))
require.Equal(t, int64(40), meter.GasConsumed())
}
func TestGasKVStoreWrap(t *testing.T) {
db := dbm.NewMemDB()
tree, _ := newTree(t, db)
iavl := newIAVLStore(tree, numRecent, storeEvery)
testGasKVStoreWrap(t, iavl)
st := NewCacheKVStore(iavl)
testGasKVStoreWrap(t, st)
pref := st.Prefix([]byte("prefix"))
testGasKVStoreWrap(t, pref)
dsa := dbStoreAdapter{dbm.NewMemDB()}
testGasKVStoreWrap(t, dsa)
ts := newTransientStore()
testGasKVStoreWrap(t, ts)
}

View File

@ -67,7 +67,6 @@ func newIAVLStore(tree *iavl.VersionedTree, numRecent int64, storeEvery int64) *
// Implements Committer. // Implements Committer.
func (st *iavlStore) Commit() CommitID { func (st *iavlStore) Commit() CommitID {
// Save a new version. // Save a new version.
hash, version, err := st.tree.SaveVersion() hash, version, err := st.tree.SaveVersion()
if err != nil { if err != nil {
@ -161,6 +160,11 @@ func (st *iavlStore) Prefix(prefix []byte) KVStore {
return prefixStore{st, prefix} return prefixStore{st, prefix}
} }
// Implements KVStore
func (st *iavlStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, st)
}
// Implements KVStore. // Implements KVStore.
func (st *iavlStore) Iterator(start, end []byte) Iterator { func (st *iavlStore) Iterator(start, end []byte) Iterator {
return newIAVLIterator(st.tree.Tree(), start, end, true) return newIAVLIterator(st.tree.Tree(), start, end, true)

View File

@ -446,6 +446,7 @@ func TestIAVLStoreQuery(t *testing.T) {
require.Equal(t, uint32(sdk.CodeOK), qres.Code) require.Equal(t, uint32(sdk.CodeOK), qres.Code)
require.Equal(t, v3, qres.Value) require.Equal(t, v3, qres.Value)
query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version} query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version}
qres = iavlStore.Query(query2) qres = iavlStore.Query(query2)
require.Equal(t, uint32(sdk.CodeOK), qres.Code) require.Equal(t, uint32(sdk.CodeOK), qres.Code)
require.Equal(t, v2, qres.Value) require.Equal(t, v2, qres.Value)

View File

@ -6,14 +6,16 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
var _ KVStore = prefixStore{}
type prefixStore struct { type prefixStore struct {
store KVStore parent KVStore
prefix []byte prefix []byte
} }
// Implements Store // Implements Store
func (s prefixStore) GetStoreType() StoreType { func (s prefixStore) GetStoreType() StoreType {
return sdk.StoreTypePrefix return s.parent.GetStoreType()
} }
// Implements CacheWrap // Implements CacheWrap
@ -28,22 +30,22 @@ func (s prefixStore) CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap
// Implements KVStore // Implements KVStore
func (s prefixStore) Get(key []byte) []byte { func (s prefixStore) Get(key []byte) []byte {
return s.store.Get(append(s.prefix, key...)) return s.parent.Get(append(s.prefix, key...))
} }
// Implements KVStore // Implements KVStore
func (s prefixStore) Has(key []byte) bool { func (s prefixStore) Has(key []byte) bool {
return s.store.Has(append(s.prefix, key...)) return s.parent.Has(append(s.prefix, key...))
} }
// Implements KVStore // Implements KVStore
func (s prefixStore) Set(key, value []byte) { func (s prefixStore) Set(key, value []byte) {
s.store.Set(append(s.prefix, key...), value) s.parent.Set(append(s.prefix, key...), value)
} }
// Implements KVStore // Implements KVStore
func (s prefixStore) Delete(key []byte) { func (s prefixStore) Delete(key []byte) {
s.store.Delete(append(s.prefix, key...)) s.parent.Delete(append(s.prefix, key...))
} }
// Implements KVStore // Implements KVStore
@ -51,6 +53,11 @@ func (s prefixStore) Prefix(prefix []byte) KVStore {
return prefixStore{s, prefix} return prefixStore{s, prefix}
} }
// Implements KVStore
func (s prefixStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, s)
}
// Implements KVStore // Implements KVStore
func (s prefixStore) Iterator(start, end []byte) Iterator { func (s prefixStore) Iterator(start, end []byte) Iterator {
if end == nil { if end == nil {
@ -60,7 +67,7 @@ func (s prefixStore) Iterator(start, end []byte) Iterator {
} }
return prefixIterator{ return prefixIterator{
prefix: s.prefix, prefix: s.prefix,
iter: s.store.Iterator(append(s.prefix, start...), end), iter: s.parent.Iterator(append(s.prefix, start...), end),
} }
} }
@ -73,7 +80,7 @@ func (s prefixStore) ReverseIterator(start, end []byte) Iterator {
} }
return prefixIterator{ return prefixIterator{
prefix: s.prefix, prefix: s.prefix,
iter: s.store.ReverseIterator(start, end), iter: s.parent.ReverseIterator(start, end),
} }
} }

View File

@ -4,7 +4,6 @@ import (
"math/rand" "math/rand"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/iavl" "github.com/tendermint/iavl"
@ -35,32 +34,34 @@ func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) { func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
prefixStore := baseStore.Prefix(prefix) prefixStore := baseStore.Prefix(prefix)
prefixPrefixStore := prefixStore.Prefix([]byte("prefix"))
kvps := setRandomKVPairs(t, prefixStore) kvps := setRandomKVPairs(t, prefixPrefixStore)
buf := make([]byte, 32)
for i := 0; i < 20; i++ {
rand.Read(buf)
assert.False(t, prefixStore.Has(buf))
assert.Nil(t, prefixStore.Get(buf))
assert.False(t, baseStore.Has(append(prefix, buf...)))
assert.Nil(t, baseStore.Get(append(prefix, buf...)))
}
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
key := kvps[i].key key := kvps[i].key
assert.True(t, prefixStore.Has(key)) value := kvps[i].value
assert.Equal(t, kvps[i].value, prefixStore.Get(key)) require.True(t, prefixPrefixStore.Has(key))
assert.True(t, baseStore.Has(append(prefix, key...))) require.Equal(t, value, prefixPrefixStore.Get(key))
assert.Equal(t, kvps[i].value, baseStore.Get(append(prefix, key...)))
prefixStore.Delete(key) key = append([]byte("prefix"), key...)
assert.False(t, prefixStore.Has(key)) require.True(t, prefixStore.Has(key))
assert.Nil(t, prefixStore.Get(key)) require.Equal(t, value, prefixStore.Get(key))
assert.False(t, baseStore.Has(append(prefix, buf...))) key = append(prefix, key...)
assert.Nil(t, baseStore.Get(append(prefix, buf...))) require.True(t, baseStore.Has(key))
require.Equal(t, value, baseStore.Get(key))
key = kvps[i].key
prefixPrefixStore.Delete(key)
require.False(t, prefixPrefixStore.Has(key))
require.Nil(t, prefixPrefixStore.Get(key))
key = append([]byte("prefix"), key...)
require.False(t, prefixStore.Has(key))
require.Nil(t, prefixStore.Get(key))
key = append(prefix, key...)
require.False(t, baseStore.Has(key))
require.Nil(t, baseStore.Get(key))
} }
} }
func TestIAVLStorePrefix(t *testing.T) { func TestIAVLStorePrefix(t *testing.T) {
@ -80,7 +81,7 @@ func TestCacheKVStorePrefix(t *testing.T) {
func TestGasKVStorePrefix(t *testing.T) { func TestGasKVStorePrefix(t *testing.T) {
meter := sdk.NewGasMeter(100000000) meter := sdk.NewGasMeter(100000000)
mem := dbStoreAdapter{dbm.NewMemDB()} mem := dbStoreAdapter{dbm.NewMemDB()}
gasStore := NewGasKVStore(meter, mem) gasStore := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
testPrefixStore(t, gasStore, []byte("test")) testPrefixStore(t, gasStore, []byte("test"))
} }

View File

@ -99,7 +99,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
if ver == 0 { if ver == 0 {
for key, storeParams := range rs.storesParams { for key, storeParams := range rs.storesParams {
id := CommitID{} id := CommitID{}
store, err := rs.loadCommitStoreFromParams(id, storeParams) store, err := rs.loadCommitStoreFromParams(key, id, storeParams)
if err != nil { if err != nil {
return fmt.Errorf("failed to load rootMultiStore: %v", err) return fmt.Errorf("failed to load rootMultiStore: %v", err)
} }
@ -122,19 +122,22 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
for _, storeInfo := range cInfo.StoreInfos { for _, storeInfo := range cInfo.StoreInfos {
key, commitID := rs.nameToKey(storeInfo.Name), storeInfo.Core.CommitID key, commitID := rs.nameToKey(storeInfo.Name), storeInfo.Core.CommitID
storeParams := rs.storesParams[key] storeParams := rs.storesParams[key]
store, err := rs.loadCommitStoreFromParams(commitID, storeParams) store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams)
if err != nil { if err != nil {
return fmt.Errorf("failed to load rootMultiStore: %v", err) return fmt.Errorf("failed to load rootMultiStore: %v", err)
} }
newStores[key] = store newStores[key] = store
} }
// If any CommitStoreLoaders were not used, return error. // TODO: detecting transient is quite adhoc
for key := range rs.storesParams { // If any nontransient CommitStoreLoaders were not used, return error.
for key, param := range rs.storesParams {
if param.typ != sdk.StoreTypeTransient {
if _, ok := newStores[key]; !ok { if _, ok := newStores[key]; !ok {
return fmt.Errorf("unused CommitStoreLoader: %v", key) return fmt.Errorf("unused CommitStoreLoader: %v", key)
} }
} }
}
// Success. // Success.
rs.lastCommitID = cInfo.CommitID() rs.lastCommitID = cInfo.CommitID()
@ -242,10 +245,7 @@ func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore {
return store return store
} }
// Implements MultiStore. // Implements MultiStore
func (rs *rootMultiStore) GetKVStoreWithGas(meter sdk.GasMeter, key StoreKey) KVStore {
return NewGasKVStore(meter, rs.GetKVStore(key))
}
// getStoreByName will first convert the original name to // getStoreByName will first convert the original name to
// a special key, before looking up the CommitStore. // a special key, before looking up the CommitStore.
@ -309,7 +309,7 @@ func parsePath(path string) (storeName string, subpath string, err sdk.Error) {
//---------------------------------------- //----------------------------------------
func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storeParams) (store CommitStore, err error) { func (rs *rootMultiStore) loadCommitStoreFromParams(key sdk.StoreKey, id CommitID, params storeParams) (store CommitStore, err error) {
var db dbm.DB var db dbm.DB
if params.db != nil { if params.db != nil {
db = dbm.NewPrefixDB(params.db, []byte("s/_/")) db = dbm.NewPrefixDB(params.db, []byte("s/_/"))
@ -326,6 +326,14 @@ func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storePar
return return
case sdk.StoreTypeDB: case sdk.StoreTypeDB:
panic("dbm.DB is not a CommitStore") panic("dbm.DB is not a CommitStore")
case sdk.StoreTypeTransient:
_, ok := key.(*sdk.TransientStoreKey)
if !ok {
err = fmt.Errorf("invalid StoreKey for StoreTypeTransient: %s", key.String())
return
}
store = newTransientStore()
return
default: default:
panic(fmt.Sprintf("unrecognized store type %v", params.typ)) panic(fmt.Sprintf("unrecognized store type %v", params.typ))
} }
@ -440,6 +448,10 @@ func commitStores(version int64, storeMap map[StoreKey]CommitStore) commitInfo {
// Commit // Commit
commitID := store.Commit() commitID := store.Commit()
if store.GetStoreType() == sdk.StoreTypeTransient {
continue
}
// Record CommitID // Record CommitID
si := storeInfo{} si := storeInfo{}
si.Name = key.Name() si.Name = key.Name()

View File

@ -13,6 +13,14 @@ import (
const useDebugDB = false const useDebugDB = false
func TestStoreType(t *testing.T) {
db := dbm.NewMemDB()
store := NewCommitMultiStore(db)
store.MountStoreWithDB(
sdk.NewKVStoreKey("store1"), sdk.StoreTypeIAVL, db)
}
func TestMultistoreCommitLoad(t *testing.T) { func TestMultistoreCommitLoad(t *testing.T) {
var db dbm.DB = dbm.NewMemDB() var db dbm.DB = dbm.NewMemDB()
if useDebugDB { if useDebugDB {

View File

@ -82,6 +82,11 @@ func (tkv *TraceKVStore) Prefix(prefix []byte) KVStore {
return prefixStore{tkv, prefix} return prefixStore{tkv, prefix}
} }
// Gas implements the KVStore interface.
func (tkv *TraceKVStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, tkv.parent)
}
// Iterator implements the KVStore interface. It delegates the Iterator call // Iterator implements the KVStore interface. It delegates the Iterator call
// the to the parent KVStore. // the to the parent KVStore.
func (tkv *TraceKVStore) Iterator(start, end []byte) sdk.Iterator { func (tkv *TraceKVStore) Iterator(start, end []byte) sdk.Iterator {

43
store/transientstore.go Normal file
View File

@ -0,0 +1,43 @@
package store
import (
dbm "github.com/tendermint/tendermint/libs/db"
)
var _ KVStore = (*transientStore)(nil)
// transientStore is a wrapper for a MemDB with Commiter implementation
type transientStore struct {
dbStoreAdapter
}
// Constructs new MemDB adapter
func newTransientStore() *transientStore {
return &transientStore{dbStoreAdapter{dbm.NewMemDB()}}
}
// Implements CommitStore
// Commit cleans up transientStore.
func (ts *transientStore) Commit() (id CommitID) {
ts.dbStoreAdapter = dbStoreAdapter{dbm.NewMemDB()}
return
}
// Implements CommitStore
func (ts *transientStore) SetPruning(pruning PruningStrategy) {
}
// Implements CommitStore
func (ts *transientStore) LastCommitID() (id CommitID) {
return
}
// Implements KVStore
func (ts *transientStore) Prefix(prefix []byte) KVStore {
return prefixStore{ts, prefix}
}
// Implements KVStore
func (ts *transientStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, ts)
}

View File

@ -0,0 +1,23 @@
package store
import (
"testing"
"github.com/stretchr/testify/require"
)
var k, v = []byte("hello"), []byte("world")
func TestTransientStore(t *testing.T) {
tstore := newTransientStore()
require.Nil(t, tstore.Get(k))
tstore.Set(k, v)
require.Equal(t, v, tstore.Get(k))
tstore.Commit()
require.Nil(t, tstore.Get(k))
}

View File

@ -7,6 +7,7 @@ import (
// Import cosmos-sdk/types/store.go for convenience. // Import cosmos-sdk/types/store.go for convenience.
// nolint // nolint
type ( type (
PruningStrategy = types.PruningStrategy
Store = types.Store Store = types.Store
Committer = types.Committer Committer = types.Committer
CommitStore = types.CommitStore CommitStore = types.CommitStore
@ -25,4 +26,7 @@ type (
StoreType = types.StoreType StoreType = types.StoreType
Queryable = types.Queryable Queryable = types.Queryable
TraceContext = types.TraceContext TraceContext = types.TraceContext
Gas = types.Gas
GasMeter = types.GasMeter
GasConfig = types.GasConfig
) )

View File

@ -31,7 +31,6 @@ type Context struct {
// create a new context // create a new context
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context { func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
c := Context{ c := Context{
Context: context.Background(), Context: context.Background(),
pst: newThePast(), pst: newThePast(),
@ -70,7 +69,12 @@ func (c Context) Value(key interface{}) interface{} {
// KVStore fetches a KVStore from the MultiStore. // KVStore fetches a KVStore from the MultiStore.
func (c Context) KVStore(key StoreKey) KVStore { func (c Context) KVStore(key StoreKey) KVStore {
return c.multiStore().GetKVStoreWithGas(c.GasMeter(), key) return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedDefaultGasConfig)
}
// TransientStore fetches a TransientStore from the MultiStore.
func (c Context) TransientStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
} }
//---------------------------------------- //----------------------------------------
@ -125,6 +129,7 @@ const (
contextKeyMultiStore contextKey = iota contextKeyMultiStore contextKey = iota
contextKeyBlockHeader contextKeyBlockHeader
contextKeyBlockHeight contextKeyBlockHeight
contextKeyConsensusParams
contextKeyChainID contextKeyChainID
contextKeyTxBytes contextKeyTxBytes
contextKeyLogger contextKeyLogger
@ -146,6 +151,9 @@ func (c Context) BlockHeader() abci.Header {
func (c Context) BlockHeight() int64 { func (c Context) BlockHeight() int64 {
return c.Value(contextKeyBlockHeight).(int64) return c.Value(contextKeyBlockHeight).(int64)
} }
func (c Context) ConsensusParams() abci.ConsensusParams {
return c.Value(contextKeyConsensusParams).(abci.ConsensusParams)
}
func (c Context) ChainID() string { func (c Context) ChainID() string {
return c.Value(contextKeyChainID).(string) return c.Value(contextKeyChainID).(string)
} }
@ -171,6 +179,13 @@ func (c Context) WithBlockHeader(header abci.Header) Context {
func (c Context) WithBlockHeight(height int64) Context { func (c Context) WithBlockHeight(height int64) Context {
return c.withValue(contextKeyBlockHeight, height) return c.withValue(contextKeyBlockHeight, height)
} }
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
if params == nil {
return c
}
return c.withValue(contextKeyConsensusParams, params).
WithGasMeter(NewGasMeter(params.TxSize.MaxGas))
}
func (c Context) WithChainID(chainID string) Context { func (c Context) WithChainID(chainID string) Context {
return c.withValue(contextKeyChainID, chainID) return c.withValue(contextKeyChainID, chainID)
} }

View File

@ -54,3 +54,40 @@ func (g *infiniteGasMeter) GasConsumed() Gas {
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) { func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
g.consumed += amount g.consumed += amount
} }
// GasConfig defines gas cost for each operation on KVStores
type GasConfig struct {
HasCost Gas
ReadCostFlat Gas
ReadCostPerByte Gas
WriteCostFlat Gas
WriteCostPerByte Gas
KeyCostFlat Gas
ValueCostFlat Gas
ValueCostPerByte Gas
}
var (
cachedDefaultGasConfig = DefaultGasConfig()
cachedTransientGasConfig = TransientGasConfig()
)
// Default gas config for KVStores
func DefaultGasConfig() GasConfig {
return GasConfig{
HasCost: 10,
ReadCostFlat: 10,
ReadCostPerByte: 1,
WriteCostFlat: 10,
WriteCostPerByte: 10,
KeyCostFlat: 5,
ValueCostFlat: 10,
ValueCostPerByte: 1,
}
}
// Default gas config for TransientStores
func TransientGasConfig() GasConfig {
// TODO: define gasconfig for transient stores
return DefaultGasConfig()
}

View File

@ -65,7 +65,6 @@ type MultiStore interface { //nolint
// Convenience for fetching substores. // Convenience for fetching substores.
GetStore(StoreKey) Store GetStore(StoreKey) Store
GetKVStore(StoreKey) KVStore GetKVStore(StoreKey) KVStore
GetKVStoreWithGas(GasMeter, StoreKey) KVStore
// TracingEnabled returns if tracing is enabled for the MultiStore. // TracingEnabled returns if tracing is enabled for the MultiStore.
TracingEnabled() bool TracingEnabled() bool
@ -134,9 +133,6 @@ type KVStore interface {
// Delete deletes the key. Panics on nil key. // Delete deletes the key. Panics on nil key.
Delete(key []byte) Delete(key []byte)
// Prefix applied keys with the argument
Prefix(prefix []byte) KVStore
// Iterator over a domain of keys in ascending order. End is exclusive. // Iterator over a domain of keys in ascending order. End is exclusive.
// Start must be less than end, or the Iterator is invalid. // Start must be less than end, or the Iterator is invalid.
// Iterator must be closed by caller. // Iterator must be closed by caller.
@ -155,6 +151,16 @@ type KVStore interface {
// TODO Not yet implemented. // TODO Not yet implemented.
// GetSubKVStore(key *storeKey) KVStore // GetSubKVStore(key *storeKey) KVStore
// Prefix applied keys with the argument
// CONTRACT: when Prefix is called on a KVStore more than once,
// the concatanation of the prefixes is applied
Prefix(prefix []byte) KVStore
// Gas consuming store
// CONTRACT: when Gas is called on a KVStore more than once,
// the concatanation of the meters/configs is applied
Gas(GasMeter, GasConfig) KVStore
} }
// Alias iterator to db's Iterator for convenience. // Alias iterator to db's Iterator for convenience.
@ -186,11 +192,6 @@ type CommitKVStore interface {
KVStore KVStore
} }
// Wrapper for StoreKeys to get KVStores
type KVStoreGetter interface {
KVStore(Context) KVStore
}
//---------------------------------------- //----------------------------------------
// CacheWrap // CacheWrap
@ -245,7 +246,7 @@ const (
StoreTypeMulti StoreType = iota StoreTypeMulti StoreType = iota
StoreTypeDB StoreTypeDB
StoreTypeIAVL StoreTypeIAVL
StoreTypePrefix StoreTypeTransient
) )
//---------------------------------------- //----------------------------------------
@ -279,11 +280,6 @@ func (key *KVStoreKey) String() string {
return fmt.Sprintf("KVStoreKey{%p, %s}", key, key.name) return fmt.Sprintf("KVStoreKey{%p, %s}", key, key.name)
} }
// Implements KVStoreGetter
func (key *KVStoreKey) KVStore(ctx Context) KVStore {
return ctx.KVStore(key)
}
// PrefixEndBytes returns the []byte that would end a // PrefixEndBytes returns the []byte that would end a
// range query for all []byte with a certain prefix // range query for all []byte with a certain prefix
// Deals with last byte of prefix being FF without overflowing // Deals with last byte of prefix being FF without overflowing
@ -310,19 +306,27 @@ func PrefixEndBytes(prefix []byte) []byte {
return end return end
} }
// Getter struct for prefixed stores // TransientStoreKey is used for indexing transient stores in a MultiStore
type PrefixStoreGetter struct { type TransientStoreKey struct {
key StoreKey name string
prefix []byte
} }
func NewPrefixStoreGetter(key StoreKey, prefix []byte) PrefixStoreGetter { // Constructs new TransientStoreKey
return PrefixStoreGetter{key, prefix} // Must return a pointer according to the ocap principle
func NewTransientStoreKey(name string) *TransientStoreKey {
return &TransientStoreKey{
name: name,
}
} }
// Implements sdk.KVStoreGetter // Implements StoreKey
func (getter PrefixStoreGetter) KVStore(ctx Context) KVStore { func (key *TransientStoreKey) Name() string {
return ctx.KVStore(getter.key).Prefix(getter.prefix) return key.name
}
// Implements StoreKey
func (key *TransientStoreKey) String() string {
return fmt.Sprintf("TransientStoreKey{%p, %s}", key, key.name)
} }
//---------------------------------------- //----------------------------------------