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
152 lines
6.3 KiB
Go
152 lines
6.3 KiB
Go
package keeper
|
|
|
|
import (
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
|
|
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/internal/telemetry"
|
|
)
|
|
|
|
// CreateClient generates a new client identifier and invokes the associated light client module in order to
|
|
// initialize a new client. An isolated prefixed store will be reserved for this client using the generated
|
|
// client identifier. The light client module is responsible for setting any client-specific data in the store
|
|
// via the Initialize method. This includes the client state, initial consensus state and any associated
|
|
// metadata. The generated client identifier will be returned if a client was successfully initialized.
|
|
func (k *Keeper) CreateClient(ctx sdk.Context, clientType string, clientState, consensusState []byte) (string, error) {
|
|
if clientType == exported.Localhost {
|
|
return "", errorsmod.Wrapf(types.ErrInvalidClientType, "cannot create client of type: %s", clientType)
|
|
}
|
|
|
|
clientID := k.GenerateClientIdentifier(ctx, clientType)
|
|
|
|
clientModule, err := k.Route(ctx, clientID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := clientModule.Initialize(ctx, clientID, clientState, consensusState); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if status := clientModule.Status(ctx, clientID); status != exported.Active {
|
|
return "", errorsmod.Wrapf(types.ErrClientNotActive, "cannot create client (%s) with status %s", clientID, status)
|
|
}
|
|
|
|
initialHeight := clientModule.LatestHeight(ctx, clientID)
|
|
k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", initialHeight.String())
|
|
|
|
defer telemetry.ReportCreateClient(clientType)
|
|
emitCreateClientEvent(ctx, clientID, clientType, initialHeight)
|
|
|
|
return clientID, nil
|
|
}
|
|
|
|
// UpdateClient updates the consensus state and the state root from a provided header.
|
|
func (k *Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error {
|
|
clientModule, err := k.Route(ctx, clientID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if status := clientModule.Status(ctx, clientID); status != exported.Active {
|
|
return errorsmod.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status)
|
|
}
|
|
|
|
if err := clientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil {
|
|
return err
|
|
}
|
|
|
|
foundMisbehaviour := clientModule.CheckForMisbehaviour(ctx, clientID, clientMsg)
|
|
if foundMisbehaviour {
|
|
clientModule.UpdateStateOnMisbehaviour(ctx, clientID, clientMsg)
|
|
|
|
k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID)
|
|
|
|
clientType := types.MustParseClientIdentifier(clientID)
|
|
defer telemetry.ReportUpdateClient(foundMisbehaviour, clientType, clientID)
|
|
emitSubmitMisbehaviourEvent(ctx, clientID, clientType)
|
|
|
|
return nil
|
|
}
|
|
|
|
consensusHeights := clientModule.UpdateState(ctx, clientID, clientMsg)
|
|
|
|
k.Logger(ctx).Info("client state updated", "client-id", clientID, "heights", consensusHeights)
|
|
|
|
clientType := types.MustParseClientIdentifier(clientID)
|
|
defer telemetry.ReportUpdateClient(foundMisbehaviour, clientType, clientID)
|
|
emitUpdateClientEvent(ctx, clientID, clientType, consensusHeights, k.cdc, clientMsg)
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpgradeClient upgrades the client to a new client state if this new client was committed to
|
|
// by the old client at the specified upgrade height
|
|
func (k *Keeper) UpgradeClient(
|
|
ctx sdk.Context,
|
|
clientID string,
|
|
upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof []byte,
|
|
) error {
|
|
clientModule, err := k.Route(ctx, clientID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if status := clientModule.Status(ctx, clientID); status != exported.Active {
|
|
return errorsmod.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status)
|
|
}
|
|
|
|
if err := clientModule.VerifyUpgradeAndUpdateState(ctx, clientID, upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof); err != nil {
|
|
return errorsmod.Wrapf(err, "cannot upgrade client with ID %s", clientID)
|
|
}
|
|
|
|
latestHeight := clientModule.LatestHeight(ctx, clientID)
|
|
k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", latestHeight.String())
|
|
|
|
clientType := types.MustParseClientIdentifier(clientID)
|
|
defer telemetry.ReportUpgradeClient(clientType, clientID)
|
|
emitUpgradeClientEvent(ctx, clientID, clientType, latestHeight)
|
|
|
|
return nil
|
|
}
|
|
|
|
// RecoverClient will invoke the light client module associated with the subject clientID requesting it to
|
|
// recover the subject client given a substitute client identifier. The light client implementation
|
|
// is responsible for validating the parameters of the substitute (ensuring they match the subject's parameters)
|
|
// as well as copying the necessary consensus states from the substitute to the subject client store.
|
|
// The substitute must be Active and the subject must not be Active.
|
|
func (k *Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClientID string) error {
|
|
clientModule, err := k.Route(ctx, subjectClientID)
|
|
if err != nil {
|
|
return errorsmod.Wrap(types.ErrRouteNotFound, subjectClientID)
|
|
}
|
|
|
|
if status := clientModule.Status(ctx, subjectClientID); status == exported.Active {
|
|
return errorsmod.Wrapf(types.ErrInvalidRecoveryClient, "cannot recover subject client (%s) with status %s", subjectClientID, status)
|
|
}
|
|
|
|
if status := clientModule.Status(ctx, substituteClientID); status != exported.Active {
|
|
return errorsmod.Wrapf(types.ErrClientNotActive, "cannot recover client using substitute client (%s) with status %s", substituteClientID, status)
|
|
}
|
|
|
|
subjectLatestHeight := clientModule.LatestHeight(ctx, subjectClientID)
|
|
substituteLatestHeight := clientModule.LatestHeight(ctx, substituteClientID)
|
|
if subjectLatestHeight.GTE(substituteLatestHeight) {
|
|
return errorsmod.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", subjectLatestHeight, substituteLatestHeight)
|
|
}
|
|
|
|
if err := clientModule.RecoverClient(ctx, subjectClientID, substituteClientID); err != nil {
|
|
return err
|
|
}
|
|
|
|
k.Logger(ctx).Info("client recovered", "client-id", subjectClientID)
|
|
|
|
clientType := types.MustParseClientIdentifier(subjectClientID)
|
|
defer telemetry.ReportRecoverClient(clientType, subjectClientID)
|
|
emitRecoverClientEvent(ctx, subjectClientID, clientType)
|
|
|
|
return nil
|
|
}
|