@@ -3,7 +3,6 @@ package keeper
33import (
44 "errors"
55 "fmt"
6- "reflect"
76 "strings"
87
98 errorsmod "cosmossdk.io/errors"
@@ -15,12 +14,8 @@ import (
1514 "github.com/cosmos/cosmos-sdk/codec"
1615 sdk "github.com/cosmos/cosmos-sdk/types"
1716
18- "github.com/cometbft/cometbft/light"
19-
2017 "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
21- commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
2218 host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
23- ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors"
2419 "github.com/cosmos/ibc-go/v8/modules/core/exported"
2520 ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
2621 localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost"
@@ -29,21 +24,23 @@ import (
2924// Keeper represents a type that grants read and write permissions to any client
3025// state information
3126type Keeper struct {
32- storeKey storetypes.StoreKey
33- cdc codec.BinaryCodec
34- legacySubspace types.ParamSubspace
35- stakingKeeper types.StakingKeeper
36- upgradeKeeper types.UpgradeKeeper
27+ storeKey storetypes.StoreKey
28+ cdc codec.BinaryCodec
29+ legacySubspace types.ParamSubspace
30+ selfClientValidator types.SelfClientValidator
31+ stakingKeeper types.StakingKeeper
32+ upgradeKeeper types.UpgradeKeeper
3733}
3834
3935// NewKeeper creates a new NewKeeper instance
4036func NewKeeper (cdc codec.BinaryCodec , key storetypes.StoreKey , legacySubspace types.ParamSubspace , sk types.StakingKeeper , uk types.UpgradeKeeper ) Keeper {
4137 return Keeper {
42- storeKey : key ,
43- cdc : cdc ,
44- legacySubspace : legacySubspace ,
45- stakingKeeper : sk ,
46- upgradeKeeper : uk ,
38+ storeKey : key ,
39+ cdc : cdc ,
40+ legacySubspace : legacySubspace ,
41+ selfClientValidator : NewTendermintClientValidator (sk ),
42+ stakingKeeper : sk ,
43+ upgradeKeeper : uk ,
4744 }
4845}
4946
@@ -63,6 +60,15 @@ func (k Keeper) UpdateLocalhostClient(ctx sdk.Context, clientState exported.Clie
6360 return clientState .UpdateState (ctx , k .cdc , k .ClientStore (ctx , exported .LocalhostClientID ), nil )
6461}
6562
63+ // SetSelfClientValidator sets a custom self client validation function.
64+ func (k * Keeper ) SetSelfClientValidator (selfClientValidator types.SelfClientValidator ) {
65+ if selfClientValidator == nil {
66+ panic (fmt .Errorf ("cannot set a nil self client validator" ))
67+ }
68+
69+ k .selfClientValidator = selfClientValidator
70+ }
71+
6672// GenerateClientIdentifier returns the next client identifier.
6773func (k Keeper ) GenerateClientIdentifier (ctx sdk.Context , clientType string ) string {
6874 nextClientSeq := k .GetNextClientSequence (ctx )
@@ -282,96 +288,15 @@ func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string)
282288// and returns the expected consensus state at that height.
283289// For now, can only retrieve self consensus states for the current revision
284290func (k Keeper ) GetSelfConsensusState (ctx sdk.Context , height exported.Height ) (exported.ConsensusState , error ) {
285- selfHeight , ok := height .(types.Height )
286- if ! ok {
287- return nil , errorsmod .Wrapf (ibcerrors .ErrInvalidType , "expected %T, got %T" , types.Height {}, height )
288- }
289- // check that height revision matches chainID revision
290- revision := types .ParseChainID (ctx .ChainID ())
291- if revision != height .GetRevisionNumber () {
292- return nil , errorsmod .Wrapf (types .ErrInvalidHeight , "chainID revision number does not match height revision number: expected %d, got %d" , revision , height .GetRevisionNumber ())
293- }
294- histInfo , err := k .stakingKeeper .GetHistoricalInfo (ctx , int64 (selfHeight .RevisionHeight ))
295- if err != nil {
296- return nil , errorsmod .Wrapf (err , "height %d" , selfHeight .RevisionHeight )
297- }
298-
299- consensusState := & ibctm.ConsensusState {
300- Timestamp : histInfo .Header .Time ,
301- Root : commitmenttypes .NewMerkleRoot (histInfo .Header .GetAppHash ()),
302- NextValidatorsHash : histInfo .Header .NextValidatorsHash ,
303- }
304-
305- return consensusState , nil
291+ return k .selfClientValidator .GetSelfConsensusState (ctx , height )
306292}
307293
308- // ValidateSelfClient validates the client parameters for a client of the running chain
309- // This function is only used to validate the client state the counterparty stores for this chain
310- // Client must be in same revision as the executing chain
294+ // ValidateSelfClient validates the client parameters for a client of the running chain.
295+ // This function is only used to validate the client state the counterparty stores for this chain.
296+ // NOTE: If the client type is not of type Tendermint then delegate to a custom client validator function.
297+ // This allows support for non-Tendermint clients, for example 08-wasm clients.
311298func (k Keeper ) ValidateSelfClient (ctx sdk.Context , clientState exported.ClientState ) error {
312- tmClient , ok := clientState .(* ibctm.ClientState )
313- if ! ok {
314- return errorsmod .Wrapf (types .ErrInvalidClient , "client must be a Tendermint client, expected: %T, got: %T" ,
315- & ibctm.ClientState {}, tmClient )
316- }
317-
318- if ! tmClient .FrozenHeight .IsZero () {
319- return types .ErrClientFrozen
320- }
321-
322- if ctx .ChainID () != tmClient .ChainId {
323- return errorsmod .Wrapf (types .ErrInvalidClient , "invalid chain-id. expected: %s, got: %s" ,
324- ctx .ChainID (), tmClient .ChainId )
325- }
326-
327- revision := types .ParseChainID (ctx .ChainID ())
328-
329- // client must be in the same revision as executing chain
330- if tmClient .LatestHeight .RevisionNumber != revision {
331- return errorsmod .Wrapf (types .ErrInvalidClient , "client is not in the same revision as the chain. expected revision: %d, got: %d" ,
332- tmClient .LatestHeight .RevisionNumber , revision )
333- }
334-
335- selfHeight := types .NewHeight (revision , uint64 (ctx .BlockHeight ()))
336- if tmClient .LatestHeight .GTE (selfHeight ) {
337- return errorsmod .Wrapf (types .ErrInvalidClient , "client has LatestHeight %d greater than or equal to chain height %d" ,
338- tmClient .LatestHeight , selfHeight )
339- }
340-
341- expectedProofSpecs := commitmenttypes .GetSDKSpecs ()
342- if ! reflect .DeepEqual (expectedProofSpecs , tmClient .ProofSpecs ) {
343- return errorsmod .Wrapf (types .ErrInvalidClient , "client has invalid proof specs. expected: %v got: %v" ,
344- expectedProofSpecs , tmClient .ProofSpecs )
345- }
346-
347- if err := light .ValidateTrustLevel (tmClient .TrustLevel .ToTendermint ()); err != nil {
348- return errorsmod .Wrapf (types .ErrInvalidClient , "trust-level invalid: %v" , err )
349- }
350-
351- expectedUbdPeriod , err := k .stakingKeeper .UnbondingTime (ctx )
352- if err != nil {
353- return errorsmod .Wrapf (err , "failed to retrieve unbonding period" )
354- }
355-
356- if expectedUbdPeriod != tmClient .UnbondingPeriod {
357- return errorsmod .Wrapf (types .ErrInvalidClient , "invalid unbonding period. expected: %s, got: %s" ,
358- expectedUbdPeriod , tmClient .UnbondingPeriod )
359- }
360-
361- if tmClient .UnbondingPeriod < tmClient .TrustingPeriod {
362- return errorsmod .Wrapf (types .ErrInvalidClient , "unbonding period must be greater than trusting period. unbonding period (%d) < trusting period (%d)" ,
363- tmClient .UnbondingPeriod , tmClient .TrustingPeriod )
364- }
365-
366- if len (tmClient .UpgradePath ) != 0 {
367- // For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module
368- expectedUpgradePath := []string {upgradetypes .StoreKey , upgradetypes .KeyUpgradedIBCState }
369- if ! reflect .DeepEqual (expectedUpgradePath , tmClient .UpgradePath ) {
370- return errorsmod .Wrapf (types .ErrInvalidClient , "upgrade path must be the upgrade path defined by upgrade module. expected %v, got %v" ,
371- expectedUpgradePath , tmClient .UpgradePath )
372- }
373- }
374- return nil
299+ return k .selfClientValidator .ValidateSelfClient (ctx , clientState )
375300}
376301
377302// GetUpgradePlan executes the upgrade keeper GetUpgradePlan function.
0 commit comments