Skip to content

Commit

Permalink
feat: add ClientStoreProvider interface for isolated prefix stores (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
damiannolan authored Jan 31, 2024
1 parent 8efa5be commit 3020f38
Show file tree
Hide file tree
Showing 17 changed files with 147 additions and 153 deletions.
8 changes: 4 additions & 4 deletions modules/apps/callbacks/testing/simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,11 @@ func NewSimApp(

clientRouter := app.IBCKeeper.ClientKeeper.GetRouter()

tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String())
clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule)
tmLightClientModule := ibctm.NewLightClientModule(appCodec, authtypes.NewModuleAddress(govtypes.ModuleName).String())
clientRouter.AddRoute(ibctm.ModuleName, &tmLightClientModule)

smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey])
clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule)
smLightClientModule := solomachine.NewLightClientModule(appCodec)
clientRouter.AddRoute(solomachine.ModuleName, &smLightClientModule)

// create evidence keeper with router
evidenceKeeper := evidencekeeper.NewKeeper(
Expand Down
4 changes: 2 additions & 2 deletions modules/core/02-client/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ type Keeper struct {
}

// NewKeeper creates a new NewKeeper instance
func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, router *types.Router, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper {
func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper {
return Keeper{
storeKey: key,
cdc: cdc,
router: router,
router: types.NewRouter(key),
legacySubspace: legacySubspace,
stakingKeeper: sk,
upgradeKeeper: uk,
Expand Down
19 changes: 12 additions & 7 deletions modules/core/02-client/types/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,38 @@ package types
import (
"fmt"

storetypes "cosmossdk.io/store/types"

"github.com/cosmos/ibc-go/v8/modules/core/exported"
)

// The router is a map from module name to the LightClientModule
// which contains all the module-defined callbacks required by ICS-26
type Router struct {
routes map[string]exported.LightClientModule
sealed bool
routes map[string]exported.LightClientModule
storeProvider exported.ClientStoreProvider
}

func NewRouter() *Router {
func NewRouter(key storetypes.StoreKey) *Router {
return &Router{
routes: make(map[string]exported.LightClientModule),
routes: make(map[string]exported.LightClientModule),
storeProvider: NewStoreProvider(key),
}
}

// AddRoute adds LightClientModule for a given module name. It returns the Router
// so AddRoute calls can be linked. It will panic if the Router is sealed.
func (rtr *Router) AddRoute(module string, cbs exported.LightClientModule) *Router {
func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router {
// if !sdk.IsAlphaNumeric(module) {
// panic(errors.New("route expressions can only contain alphanumeric characters"))
// }
if rtr.HasRoute(module) {
if rtr.HasRoute(clientType) {
panic(fmt.Errorf("route %s has already been registered", module))
}

rtr.routes[module] = cbs
rtr.routes[clientType] = module

module.RegisterStoreProvider(rtr.storeProvider)
return rtr
}

Expand Down
31 changes: 31 additions & 0 deletions modules/core/02-client/types/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package types

import (
"fmt"

"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"

sdk "github.com/cosmos/cosmos-sdk/types"
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
)

var _ exported.ClientStoreProvider = (*storeProvider)(nil)

type storeProvider struct {
storeKey storetypes.StoreKey
}

func NewStoreProvider(storeKey storetypes.StoreKey) exported.ClientStoreProvider {
return storeProvider{
storeKey: storeKey,
}
}

// ClientStore returns isolated prefix store for each client so they can read/write in separate
// namespace without being able to read/write other client's data
func (s storeProvider) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore {
clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID))
return prefix.NewStore(ctx.KVStore(s.storeKey), clientPrefix)
}
9 changes: 9 additions & 0 deletions modules/core/exported/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,16 @@ const (
Unauthorized Status = "Unauthorized"
)

type ClientStoreProvider interface {
ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore
}

type LightClientModule interface {
// RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router.
// It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores
// to IBC light client instances.
RegisterStoreProvider(storeProvider ClientStoreProvider)

// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the
// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store.
Initialize(ctx sdk.Context, clientID string, clientState, consensusState []byte) error
Expand Down
2 changes: 1 addition & 1 deletion modules/core/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func NewKeeper(
panic(errors.New("authority must be non-empty"))
}

clientKeeper := clientkeeper.NewKeeper(cdc, key, clienttypes.NewRouter(), paramSpace, stakingKeeper, upgradeKeeper)
clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper)
connectionKeeper := connectionkeeper.NewKeeper(cdc, key, paramSpace, clientKeeper)
portKeeper := portkeeper.NewKeeper(scopedKeeper)
channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, &portKeeper, scopedKeeper)
Expand Down
23 changes: 4 additions & 19 deletions modules/light-clients/06-solomachine/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,23 @@
package keeper

import (
"fmt"

"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
)

// Keeper defines the 06-solomachine Keeper.
// TODO(damian): delete the keeper and put the codec on the LightClientModule?
type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
}

// NewKeeper creates and returns a new 06-solomachine keeper.
func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper {
func NewKeeper(cdc codec.BinaryCodec) Keeper {
return Keeper{
cdc: cdc,
storeKey: storeKey,
cdc: cdc,
}
}

// Codec returns the keeper codec.
func (k Keeper) Codec() codec.BinaryCodec {
return k.cdc
}

// ClientStore returns a namespaced prefix store for the provided IBC client identifier.
func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore {
clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID))
return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix)
}
30 changes: 17 additions & 13 deletions modules/light-clients/06-solomachine/light_client_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package solomachine

import (
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -16,16 +15,21 @@ var _ exported.LightClientModule = (*LightClientModule)(nil)

// LightClientModule implements the core IBC api.LightClientModule interface?
type LightClientModule struct {
keeper keeper.Keeper
keeper keeper.Keeper
storeProvider exported.ClientStoreProvider
}

// NewLightClientModule creates and returns a new 06-solomachine LightClientModule.
func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) LightClientModule {
func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule {
return LightClientModule{
keeper: keeper.NewKeeper(cdc, key),
keeper: keeper.NewKeeper(cdc),
}
}

func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) {
l.storeProvider = storeProvider
}

// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the
// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store.
func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error {
Expand All @@ -51,7 +55,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt
return err
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

return clientState.Initialize(ctx, cdc, clientStore, &consensusState)
Expand All @@ -66,7 +70,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string,
return err
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -84,7 +88,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string
panic(err)
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -101,7 +105,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s
panic(err)
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -119,7 +123,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM
panic(err)
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -146,7 +150,7 @@ func (l LightClientModule) VerifyMembership(
return err
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -172,7 +176,7 @@ func (l LightClientModule) VerifyNonMembership(
return err
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -189,7 +193,7 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta
return exported.Unknown // TODO: or panic
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand All @@ -206,7 +210,7 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h
return 0, err
}

clientStore := l.keeper.ClientStore(ctx, clientID)
clientStore := l.storeProvider.ClientStore(ctx, clientID)
cdc := l.keeper.Codec()

clientState, found := getClientState(clientStore, cdc)
Expand Down
23 changes: 2 additions & 21 deletions modules/light-clients/07-tendermint/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,31 @@ package keeper

import (
"errors"
"fmt"
"strings"

"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
)

// Keeper defines the tendermint light client module keeper
type Keeper struct {
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
cdc codec.BinaryCodec

// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string
}

func NewKeeper(
cdc codec.BinaryCodec,
key storetypes.StoreKey,
authority string,
) Keeper {
func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper {
if strings.TrimSpace(authority) == "" {
panic(errors.New("authority must be non-empty"))
}

return Keeper{
cdc: cdc,
storeKey: key,
authority: authority,
}
}

// ClientStore returns isolated prefix store for each client so they can read/write in separate
// namespace without being able to read/write other client's data
func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore {
clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID))
return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix)
}

func (k Keeper) Codec() codec.BinaryCodec {
return k.cdc
}
Loading

0 comments on commit 3020f38

Please sign in to comment.