@@ -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"
@@ -32,8 +27,8 @@ type Keeper struct {
3227 storeKey storetypes.StoreKey
3328 cdc codec.BinaryCodec
3429 router * types.Router
30+ consensusHost types.ConsensusHost
3531 legacySubspace types.ParamSubspace
36- stakingKeeper types.StakingKeeper
3732 upgradeKeeper types.UpgradeKeeper
3833}
3934
@@ -47,8 +42,8 @@ func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace ty
4742 storeKey : key ,
4843 cdc : cdc ,
4944 router : router ,
45+ consensusHost : ibctm .NewConsensusHost (sk ),
5046 legacySubspace : legacySubspace ,
51- stakingKeeper : sk ,
5247 upgradeKeeper : uk ,
5348 }
5449}
@@ -88,6 +83,15 @@ func (k Keeper) UpdateLocalhostClient(ctx sdk.Context, clientState exported.Clie
8883 return clientModule .UpdateState (ctx , exported .LocalhostClientID , nil )
8984}
9085
86+ // SetSelfConsensusHost sets a custom ConsensusHost for self client state and consensus state validation.
87+ func (k * Keeper ) SetSelfConsensusHost (consensusHost types.ConsensusHost ) {
88+ if consensusHost == nil {
89+ panic (fmt .Errorf ("cannot set a nil self consensus host" ))
90+ }
91+
92+ k .consensusHost = consensusHost
93+ }
94+
9195// GenerateClientIdentifier returns the next client identifier.
9296func (k Keeper ) GenerateClientIdentifier (ctx sdk.Context , clientType string ) string {
9397 nextClientSeq := k .GetNextClientSequence (ctx )
@@ -99,7 +103,7 @@ func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) str
99103}
100104
101105// GetClientState gets a particular client from the store
102- func (k Keeper ) GetClientState (ctx sdk.Context , clientID string ) (exported.ClientState , bool ) {
106+ func (k * Keeper ) GetClientState (ctx sdk.Context , clientID string ) (exported.ClientState , bool ) {
103107 store := k .ClientStore (ctx , clientID )
104108 bz := store .Get (host .ClientStateKey ())
105109 if len (bz ) == 0 {
@@ -111,13 +115,13 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.Clien
111115}
112116
113117// SetClientState sets a particular Client to the store
114- func (k Keeper ) SetClientState (ctx sdk.Context , clientID string , clientState exported.ClientState ) {
118+ func (k * Keeper ) SetClientState (ctx sdk.Context , clientID string , clientState exported.ClientState ) {
115119 store := k .ClientStore (ctx , clientID )
116120 store .Set (host .ClientStateKey (), k .MustMarshalClientState (clientState ))
117121}
118122
119123// GetClientConsensusState gets the stored consensus state from a client at a given height.
120- func (k Keeper ) GetClientConsensusState (ctx sdk.Context , clientID string , height exported.Height ) (exported.ConsensusState , bool ) {
124+ func (k * Keeper ) GetClientConsensusState (ctx sdk.Context , clientID string , height exported.Height ) (exported.ConsensusState , bool ) {
121125 store := k .ClientStore (ctx , clientID )
122126 bz := store .Get (host .ConsensusStateKey (height ))
123127 if len (bz ) == 0 {
@@ -308,96 +312,15 @@ func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string)
308312// and returns the expected consensus state at that height.
309313// For now, can only retrieve self consensus states for the current revision
310314func (k Keeper ) GetSelfConsensusState (ctx sdk.Context , height exported.Height ) (exported.ConsensusState , error ) {
311- selfHeight , ok := height .(types.Height )
312- if ! ok {
313- return nil , errorsmod .Wrapf (ibcerrors .ErrInvalidType , "expected %T, got %T" , types.Height {}, height )
314- }
315- // check that height revision matches chainID revision
316- revision := types .ParseChainID (ctx .ChainID ())
317- if revision != height .GetRevisionNumber () {
318- return nil , errorsmod .Wrapf (types .ErrInvalidHeight , "chainID revision number does not match height revision number: expected %d, got %d" , revision , height .GetRevisionNumber ())
319- }
320- histInfo , err := k .stakingKeeper .GetHistoricalInfo (ctx , int64 (selfHeight .RevisionHeight ))
321- if err != nil {
322- return nil , errorsmod .Wrapf (err , "height %d" , selfHeight .RevisionHeight )
323- }
324-
325- consensusState := & ibctm.ConsensusState {
326- Timestamp : histInfo .Header .Time ,
327- Root : commitmenttypes .NewMerkleRoot (histInfo .Header .GetAppHash ()),
328- NextValidatorsHash : histInfo .Header .NextValidatorsHash ,
329- }
330-
331- return consensusState , nil
315+ return k .consensusHost .GetSelfConsensusState (ctx , height )
332316}
333317
334- // ValidateSelfClient validates the client parameters for a client of the running chain
335- // This function is only used to validate the client state the counterparty stores for this chain
336- // Client must be in same revision as the executing chain
318+ // ValidateSelfClient validates the client parameters for a client of the running chain.
319+ // This function is only used to validate the client state the counterparty stores for this chain.
320+ // NOTE: If the client type is not of type Tendermint then delegate to a custom client validator function.
321+ // This allows support for non-Tendermint clients, for example 08-wasm clients.
337322func (k Keeper ) ValidateSelfClient (ctx sdk.Context , clientState exported.ClientState ) error {
338- tmClient , ok := clientState .(* ibctm.ClientState )
339- if ! ok {
340- return errorsmod .Wrapf (types .ErrInvalidClient , "client must be a Tendermint client, expected: %T, got: %T" ,
341- & ibctm.ClientState {}, tmClient )
342- }
343-
344- if ! tmClient .FrozenHeight .IsZero () {
345- return types .ErrClientFrozen
346- }
347-
348- if ctx .ChainID () != tmClient .ChainId {
349- return errorsmod .Wrapf (types .ErrInvalidClient , "invalid chain-id. expected: %s, got: %s" ,
350- ctx .ChainID (), tmClient .ChainId )
351- }
352-
353- revision := types .ParseChainID (ctx .ChainID ())
354-
355- // client must be in the same revision as executing chain
356- if tmClient .LatestHeight .RevisionNumber != revision {
357- return errorsmod .Wrapf (types .ErrInvalidClient , "client is not in the same revision as the chain. expected revision: %d, got: %d" ,
358- tmClient .LatestHeight .RevisionNumber , revision )
359- }
360-
361- selfHeight := types .NewHeight (revision , uint64 (ctx .BlockHeight ()))
362- if tmClient .LatestHeight .GTE (selfHeight ) {
363- return errorsmod .Wrapf (types .ErrInvalidClient , "client has LatestHeight %d greater than or equal to chain height %d" ,
364- tmClient .LatestHeight , selfHeight )
365- }
366-
367- expectedProofSpecs := commitmenttypes .GetSDKSpecs ()
368- if ! reflect .DeepEqual (expectedProofSpecs , tmClient .ProofSpecs ) {
369- return errorsmod .Wrapf (types .ErrInvalidClient , "client has invalid proof specs. expected: %v got: %v" ,
370- expectedProofSpecs , tmClient .ProofSpecs )
371- }
372-
373- if err := light .ValidateTrustLevel (tmClient .TrustLevel .ToTendermint ()); err != nil {
374- return errorsmod .Wrapf (types .ErrInvalidClient , "trust-level invalid: %v" , err )
375- }
376-
377- expectedUbdPeriod , err := k .stakingKeeper .UnbondingTime (ctx )
378- if err != nil {
379- return errorsmod .Wrapf (err , "failed to retrieve unbonding period" )
380- }
381-
382- if expectedUbdPeriod != tmClient .UnbondingPeriod {
383- return errorsmod .Wrapf (types .ErrInvalidClient , "invalid unbonding period. expected: %s, got: %s" ,
384- expectedUbdPeriod , tmClient .UnbondingPeriod )
385- }
386-
387- if tmClient .UnbondingPeriod < tmClient .TrustingPeriod {
388- return errorsmod .Wrapf (types .ErrInvalidClient , "unbonding period must be greater than trusting period. unbonding period (%d) < trusting period (%d)" ,
389- tmClient .UnbondingPeriod , tmClient .TrustingPeriod )
390- }
391-
392- if len (tmClient .UpgradePath ) != 0 {
393- // For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module
394- expectedUpgradePath := []string {upgradetypes .StoreKey , upgradetypes .KeyUpgradedIBCState }
395- if ! reflect .DeepEqual (expectedUpgradePath , tmClient .UpgradePath ) {
396- return errorsmod .Wrapf (types .ErrInvalidClient , "upgrade path must be the upgrade path defined by upgrade module. expected %v, got %v" ,
397- expectedUpgradePath , tmClient .UpgradePath )
398- }
399- }
400- return nil
323+ return k .consensusHost .ValidateSelfClient (ctx , clientState )
401324}
402325
403326// GetUpgradePlan executes the upgrade keeper GetUpgradePlan function.
0 commit comments