Skip to content

Commit

Permalink
Merge PR #5828: ADR-003: Dynamic Capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Mar 24, 2020
2 parents 6f2a9dd + 9b4f448 commit dc737f5
Show file tree
Hide file tree
Showing 20 changed files with 1,119 additions and 20 deletions.
8 changes: 8 additions & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ func (app *BaseApp) MountTransientStores(keys map[string]*sdk.TransientStoreKey)
}
}

// MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal
// commit multi-store.
func (app *BaseApp) MountMemoryStores(keys map[string]*sdk.MemoryStoreKey) {
for _, memKey := range keys {
app.MountStore(memKey, sdk.StoreTypeMemory)
}
}

// MountStoreWithDB mounts a store to the provided key in the BaseApp
// multistore, using a specified DB.
func (app *BaseApp) MountStoreWithDB(key sdk.StoreKey, typ sdk.StoreType, db dbm.DB) {
Expand Down
3 changes: 1 addition & 2 deletions docs/architecture/adr-003-dynamic-capability-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ func (sck ScopedCapabilityKeeper) ClaimCapability(ctx Context, capability Capabi
}
```

`GetCapability` allows a module to fetch a capability which it has previously claimed by name. The module is not allowed to retrieve capabilities which it does not own. If another module
claims a capability, the previously owning module will no longer be able to claim it.
`GetCapability` allows a module to fetch a capability which it has previously claimed by name. The module is not allowed to retrieve capabilities which it does not own.

```golang
func (sck ScopedCapabilityKeeper) GetCapability(ctx Context, name string) (Capability, error) {
Expand Down
58 changes: 41 additions & 17 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
Expand Down Expand Up @@ -54,6 +55,7 @@ var (
supply.AppModuleBasic{},
genutil.AppModuleBasic{},
bank.AppModuleBasic{},
capability.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
Expand Down Expand Up @@ -98,27 +100,29 @@ type SimApp struct {
invCheckPeriod uint

// keys to access the substores
keys map[string]*sdk.KVStoreKey
tkeys map[string]*sdk.TransientStoreKey
keys map[string]*sdk.KVStoreKey
tkeys map[string]*sdk.TransientStoreKey
memKeys map[string]*sdk.MemoryStoreKey

// subspaces
subspaces map[string]params.Subspace

// keepers
AccountKeeper auth.AccountKeeper
BankKeeper bank.Keeper
SupplyKeeper supply.Keeper
StakingKeeper staking.Keeper
SlashingKeeper slashing.Keeper
MintKeeper mint.Keeper
DistrKeeper distr.Keeper
GovKeeper gov.Keeper
CrisisKeeper crisis.Keeper
UpgradeKeeper upgrade.Keeper
ParamsKeeper params.Keeper
IBCKeeper ibc.Keeper
EvidenceKeeper evidence.Keeper
TransferKeeper transfer.Keeper
AccountKeeper auth.AccountKeeper
BankKeeper bank.Keeper
CapabilityKeeper *capability.Keeper
SupplyKeeper supply.Keeper
StakingKeeper staking.Keeper
SlashingKeeper slashing.Keeper
MintKeeper mint.Keeper
DistrKeeper distr.Keeper
GovKeeper gov.Keeper
CrisisKeeper crisis.Keeper
UpgradeKeeper upgrade.Keeper
ParamsKeeper params.Keeper
IBCKeeper ibc.Keeper
EvidenceKeeper evidence.Keeper
TransferKeeper transfer.Keeper

// the module manager
mm *module.Manager
Expand All @@ -145,16 +149,18 @@ func NewSimApp(
bam.MainStoreKey, auth.StoreKey, bank.StoreKey, staking.StoreKey,
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
gov.StoreKey, params.StoreKey, ibc.StoreKey, upgrade.StoreKey,
evidence.StoreKey, transfer.StoreKey,
evidence.StoreKey, transfer.StoreKey, capability.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
memKeys := sdk.NewMemoryStoreKeys(capability.MemStoreKey)

app := &SimApp{
BaseApp: bApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
memKeys: memKeys,
subspaces: make(map[string]params.Subspace),
}

Expand All @@ -177,6 +183,9 @@ func NewSimApp(
app.BankKeeper = bank.NewBaseKeeper(
appCodec, keys[bank.StoreKey], app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(),
)
app.CapabilityKeeper = capability.NewKeeper(
app.cdc, keys[capability.StoreKey], memKeys[capability.MemStoreKey],
)
app.SupplyKeeper = supply.NewKeeper(
appCodec, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms,
)
Expand Down Expand Up @@ -242,6 +251,7 @@ func NewSimApp(
genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx),
auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper),
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(*app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper),
supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper),
gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper),
Expand Down Expand Up @@ -293,6 +303,7 @@ func NewSimApp(
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tkeys)
app.MountMemoryStores(memKeys)

// initialize BaseApp
app.SetInitChainer(app.InitChainer)
Expand All @@ -312,6 +323,12 @@ func NewSimApp(
}
}

// Initialize and seal the capability keeper so all persistent capabilities
// are loaded in-memory and prevent any further modules from creating scoped
// sub-keepers.
ctx := app.BaseApp.NewContext(true, abci.Header{})
app.CapabilityKeeper.InitializeAndSeal(ctx)

return app
}

Expand Down Expand Up @@ -382,6 +399,13 @@ func (app *SimApp) GetTKey(storeKey string) *sdk.TransientStoreKey {
return app.tkeys[storeKey]
}

// GetMemKey returns the MemoryStoreKey for the provided store key.
//
// NOTE: This is solely to be used for testing purposes.
func (app *SimApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey {
return app.memKeys[storeKey]
}

// GetSubspace returns a param subspace for a given module name.
//
// NOTE: This is solely to be used for testing purposes.
Expand Down
39 changes: 39 additions & 0 deletions store/mem/mem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package mem_test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/store/mem"
"github.com/cosmos/cosmos-sdk/store/types"
)

func TestStore(t *testing.T) {
db := mem.NewStore()
key, value := []byte("key"), []byte("value")

require.Equal(t, types.StoreTypeMemory, db.GetStoreType())

require.Nil(t, db.Get(key))
db.Set(key, value)
require.Equal(t, value, db.Get(key))

newValue := []byte("newValue")
db.Set(key, newValue)
require.Equal(t, newValue, db.Get(key))

db.Delete(key)
require.Nil(t, db.Get(key))
}

func TestCommit(t *testing.T) {
db := mem.NewStore()
key, value := []byte("key"), []byte("value")

db.Set(key, value)
id := db.Commit()
require.True(t, id.IsZero())
require.True(t, db.LastCommitID().IsZero())
require.Equal(t, value, db.Get(key))
}
53 changes: 53 additions & 0 deletions store/mem/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mem

import (
"io"

dbm "github.com/tendermint/tm-db"

"github.com/cosmos/cosmos-sdk/store/cachekv"
"github.com/cosmos/cosmos-sdk/store/dbadapter"
"github.com/cosmos/cosmos-sdk/store/tracekv"
"github.com/cosmos/cosmos-sdk/store/types"
)

var (
_ types.KVStore = (*Store)(nil)
_ types.Committer = (*Store)(nil)
)

// Store implements an in-memory only KVStore. Entries are persisted between
// commits and thus between blocks. State in Memory store is not committed as part of app state but maintained privately by each node
type Store struct {
dbadapter.Store
}

func NewStore() *Store {
return NewStoreWithDB(dbm.NewMemDB())
}

func NewStoreWithDB(db *dbm.MemDB) *Store { // nolint: interfacer
return &Store{Store: dbadapter.Store{DB: db}}
}

// GetStoreType returns the Store's type.
func (s Store) GetStoreType() types.StoreType {
return types.StoreTypeMemory
}

// CacheWrap cache wraps the underlying store.
func (s Store) CacheWrap() types.CacheWrap {
return cachekv.NewStore(s)
}

// CacheWrapWithTrace implements KVStore.
func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
return cachekv.NewStore(tracekv.NewStore(s, w, tc))
}

// Commit performs a no-op as entries are persistent between commitments.
func (s *Store) Commit() (id types.CommitID) { return }

// nolint
func (s *Store) SetPruning(pruning types.PruningOptions) {}
func (s Store) LastCommitID() (id types.CommitID) { return }
11 changes: 10 additions & 1 deletion store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/cachemulti"
"github.com/cosmos/cosmos-sdk/store/dbadapter"
"github.com/cosmos/cosmos-sdk/store/iavl"
"github.com/cosmos/cosmos-sdk/store/mem"
"github.com/cosmos/cosmos-sdk/store/tracekv"
"github.com/cosmos/cosmos-sdk/store/transient"
"github.com/cosmos/cosmos-sdk/store/types"
Expand Down Expand Up @@ -169,12 +170,13 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {

// load each Store (note this doesn't panic on unmounted keys now)
var newStores = make(map[types.StoreKey]types.CommitKVStore)

for key, storeParams := range rs.storesParams {
// Load it
store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams)
if err != nil {
return errors.Wrap(err, "failed to load store")
}

newStores[key] = store

// If it was deleted, remove all data
Expand Down Expand Up @@ -527,6 +529,13 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID

return transient.NewStore(), nil

case types.StoreTypeMemory:
if _, ok := key.(*types.MemoryStoreKey); !ok {
return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s", key.String())
}

return mem.NewStore(), nil

default:
panic(fmt.Sprintf("unrecognized store type %v", params.typ))
}
Expand Down
41 changes: 41 additions & 0 deletions store/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,30 @@ const (
StoreTypeDB
StoreTypeIAVL
StoreTypeTransient
StoreTypeMemory
)

func (st StoreType) String() string {
switch st {
case StoreTypeMulti:
return "StoreTypeMulti"

case StoreTypeDB:
return "StoreTypeDB"

case StoreTypeIAVL:
return "StoreTypeIAVL"

case StoreTypeTransient:
return "StoreTypeTransient"

case StoreTypeMemory:
return "StoreTypeMemory"
}

return "unknown store type"
}

//----------------------------------------
// Keys for accessing substores

Expand Down Expand Up @@ -333,6 +355,25 @@ func (key *TransientStoreKey) String() string {
return fmt.Sprintf("TransientStoreKey{%p, %s}", key, key.name)
}

// MemoryStoreKey defines a typed key to be used with an in-memory KVStore.
type MemoryStoreKey struct {
name string
}

func NewMemoryStoreKey(name string) *MemoryStoreKey {
return &MemoryStoreKey{name: name}
}

// Name returns the name of the MemoryStoreKey.
func (key *MemoryStoreKey) Name() string {
return key.name
}

// String returns a stringified representation of the MemoryStoreKey.
func (key *MemoryStoreKey) String() string {
return fmt.Sprintf("MemoryStoreKey{%p, %s}", key, key.name)
}

//----------------------------------------

// key-value result for iterator queries
Expand Down
15 changes: 15 additions & 0 deletions types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const (
StoreTypeDB = types.StoreTypeDB
StoreTypeIAVL = types.StoreTypeIAVL
StoreTypeTransient = types.StoreTypeTransient
StoreTypeMemory = types.StoreTypeMemory
)

// nolint - reexport
Expand All @@ -84,6 +85,7 @@ type (
CapabilityKey = types.CapabilityKey
KVStoreKey = types.KVStoreKey
TransientStoreKey = types.TransientStoreKey
MemoryStoreKey = types.MemoryStoreKey
)

// NewKVStoreKey returns a new pointer to a KVStoreKey.
Expand All @@ -99,6 +101,7 @@ func NewKVStoreKeys(names ...string) map[string]*KVStoreKey {
for _, name := range names {
keys[name] = NewKVStoreKey(name)
}

return keys
}

Expand All @@ -115,6 +118,18 @@ func NewTransientStoreKeys(names ...string) map[string]*TransientStoreKey {
for _, name := range names {
keys[name] = NewTransientStoreKey(name)
}

return keys
}

// NewMemoryStoreKeys constructs a new map matching store key names to their
// respective MemoryStoreKey references.
func NewMemoryStoreKeys(names ...string) map[string]*MemoryStoreKey {
keys := make(map[string]*MemoryStoreKey)
for _, name := range names {
keys[name] = types.NewMemoryStoreKey(name)
}

return keys
}

Expand Down
Loading

0 comments on commit dc737f5

Please sign in to comment.