mukan-ibc/modules/light-clients/07-tendermint/light_client_module.go
Mukan Erkin Törük 88dd97a9f8
Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:22 +03:00

240 lines
9.4 KiB
Go

package tendermint
import (
"fmt"
errorsmod "cosmossdk.io/errors"
"git.cw.tr/mukan-network/mukan-sdk/codec"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
ibcerrors "git.cw.tr/mukan-network/mukan-ibc/modules/core/errors"
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
)
var _ exported.LightClientModule = (*LightClientModule)(nil)
// LightClientModule implements the core IBC api.LightClientModule interface.
type LightClientModule struct {
cdc codec.BinaryCodec
storeProvider clienttypes.StoreProvider
}
// NewLightClientModule creates and returns a new 07-tendermint LightClientModule.
func NewLightClientModule(cdc codec.BinaryCodec, storeProvider clienttypes.StoreProvider) LightClientModule {
return LightClientModule{
cdc: cdc,
storeProvider: storeProvider,
}
}
// Initialize unmarshals the provided client and consensus states and performs basic validation. It calls into the
// clientState.initialize method.
func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error {
var clientState ClientState
if err := l.cdc.Unmarshal(clientStateBz, &clientState); err != nil {
return fmt.Errorf("failed to unmarshal client state bytes into client state: %w", err)
}
if err := clientState.Validate(); err != nil {
return err
}
var consensusState ConsensusState
if err := l.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil {
return fmt.Errorf("failed to unmarshal consensus state bytes into consensus state: %w", err)
}
if err := consensusState.ValidateBasic(); err != nil {
return err
}
clientStore := l.storeProvider.ClientStore(ctx, clientID)
return clientState.initialize(ctx, l.cdc, clientStore, &consensusState)
}
// VerifyClientMessage obtains the client state associated with the client identifier and calls into the clientState.VerifyClientMessage method.
func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
return clientState.VerifyClientMessage(ctx, l.cdc, clientStore, clientMsg)
}
// CheckForMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.CheckForMisbehaviour method.
func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID))
}
return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg)
}
// UpdateStateOnMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method.
func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID))
}
clientState.UpdateStateOnMisbehaviour(ctx, l.cdc, clientStore, clientMsg)
}
// UpdateState obtains the client state associated with the client identifier and calls into the clientState.UpdateState method.
func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID))
}
return clientState.UpdateState(ctx, l.cdc, clientStore, clientMsg)
}
// VerifyMembership obtains the client state associated with the client identifier and calls into the clientState.verifyMembership method.
func (l LightClientModule) VerifyMembership(
ctx sdk.Context,
clientID string,
height exported.Height,
delayTimePeriod uint64,
delayBlockPeriod uint64,
proof []byte,
path exported.Path,
value []byte,
) error {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
return clientState.verifyMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value)
}
// VerifyNonMembership obtains the client state associated with the client identifier and calls into the clientState.verifyNonMembership method.
func (l LightClientModule) VerifyNonMembership(
ctx sdk.Context,
clientID string,
height exported.Height,
delayTimePeriod uint64,
delayBlockPeriod uint64,
proof []byte,
path exported.Path,
) error {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
return clientState.verifyNonMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path)
}
// Status obtains the client state associated with the client identifier and calls into the clientState.status method.
func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return exported.Unknown
}
return clientState.status(ctx, clientStore, l.cdc)
}
// LatestHeight returns the latest height for the client state for the given client identifier.
// If no client is present for the provided client identifier a zero value height is returned.
func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return clienttypes.ZeroHeight()
}
return clientState.LatestHeight
}
// TimestampAtHeight obtains the client state associated with the client identifier and calls into the clientState.getTimestampAtHeight method.
func (l LightClientModule) TimestampAtHeight(
ctx sdk.Context,
clientID string,
height exported.Height,
) (uint64, error) {
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
return clientState.getTimestampAtHeight(clientStore, l.cdc, height)
}
// RecoverClient asserts that the substitute client is a tendermint client. It obtains the client state associated with the
// subject client and calls into the subjectClientState.CheckSubstituteAndUpdateState method.
func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error {
substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID)
if err != nil {
return err
}
if substituteClientType != exported.Tendermint {
return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, substituteClientType)
}
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
substituteClientStore := l.storeProvider.ClientStore(ctx, substituteClientID)
substituteClient, found := getClientState(substituteClientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID)
}
return clientState.CheckSubstituteAndUpdateState(ctx, l.cdc, clientStore, substituteClientStore, substituteClient)
}
// VerifyUpgradeAndUpdateState obtains the client state associated with the client identifier and calls into the clientState.VerifyUpgradeAndUpdateState method.
// The new client and consensus states will be unmarshaled and an error is returned if the new client state is not at a height greater
// than the existing client.
func (l LightClientModule) VerifyUpgradeAndUpdateState(
ctx sdk.Context,
clientID string,
newClient []byte,
newConsState []byte,
upgradeClientProof,
upgradeConsensusStateProof []byte,
) error {
var newClientState ClientState
if err := l.cdc.Unmarshal(newClient, &newClientState); err != nil {
return errorsmod.Wrap(clienttypes.ErrInvalidClient, err.Error())
}
var newConsensusState ConsensusState
if err := l.cdc.Unmarshal(newConsState, &newConsensusState); err != nil {
return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, err.Error())
}
clientStore := l.storeProvider.ClientStore(ctx, clientID)
clientState, found := getClientState(clientStore, l.cdc)
if !found {
return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)
}
// last height of current counterparty chain must be client's latest height
lastHeight := clientState.LatestHeight
if !newClientState.LatestHeight.GT(lastHeight) {
return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", newClientState.LatestHeight, lastHeight)
}
return clientState.VerifyUpgradeAndUpdateState(ctx, l.cdc, clientStore, &newClientState, &newConsensusState, upgradeClientProof, upgradeConsensusStateProof)
}