Merge PR #1481: Transient Stores
This commit is contained in:
parent
74e06d8b96
commit
d46140a392
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
|
|
Binary file not shown.
|
@ -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()
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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))
|
||||||
|
}
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
37
types/gas.go
37
types/gas.go
|
@ -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()
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue