Some checks failed
CodeQL / Analyze (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (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
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Buf-Push / push (push) Has been cancelled
181 lines
7.1 KiB
Go
181 lines
7.1 KiB
Go
package localhost
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
corestore "cosmossdk.io/core/store"
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
|
|
commitmenttypes "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types"
|
|
commitmenttypesv2 "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types/v2"
|
|
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
|
|
ibcerrors "github.com/cosmos/ibc-go/v10/modules/core/errors"
|
|
"github.com/cosmos/ibc-go/v10/modules/core/exported"
|
|
)
|
|
|
|
const (
|
|
// ModuleName defines the 09-localhost light client module name
|
|
ModuleName = "09-localhost"
|
|
)
|
|
|
|
// SentinelProof defines the 09-localhost sentinel proof.
|
|
// Submission of nil or empty proofs is disallowed in core IBC messaging.
|
|
// This serves as a placeholder value for relayers to leverage as the proof field in various message types.
|
|
// Localhost client state verification will fail if the sentintel proof value is not provided.
|
|
var SentinelProof = []byte{0x01}
|
|
|
|
var _ exported.LightClientModule = (*LightClientModule)(nil)
|
|
|
|
// LightClientModule implements the core IBC api.LightClientModule interface.
|
|
type LightClientModule struct {
|
|
cdc codec.BinaryCodec
|
|
storeService corestore.KVStoreService
|
|
}
|
|
|
|
// NewLightClientModule creates and returns a new 09-localhost LightClientModule.
|
|
func NewLightClientModule(cdc codec.BinaryCodec, storeService corestore.KVStoreService) *LightClientModule {
|
|
return &LightClientModule{
|
|
cdc: cdc,
|
|
storeService: storeService,
|
|
}
|
|
}
|
|
|
|
// Initialize returns an error because it is stateless.
|
|
func (LightClientModule) Initialize(_ sdk.Context, _ string, _, _ []byte) error {
|
|
return errorsmod.Wrap(clienttypes.ErrClientExists, "localhost is stateless and cannot be initialized")
|
|
}
|
|
|
|
// VerifyClientMessage is unsupported by the 09-localhost client type and returns an error.
|
|
func (LightClientModule) VerifyClientMessage(_ sdk.Context, _ string, _ exported.ClientMessage) error {
|
|
return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "client message verification is unsupported by the localhost client")
|
|
}
|
|
|
|
// CheckForMisbehaviour is unsupported by the 09-localhost client type and performs a no-op, returning false.
|
|
func (LightClientModule) CheckForMisbehaviour(_ sdk.Context, _ string, _ exported.ClientMessage) bool {
|
|
return false
|
|
}
|
|
|
|
// UpdateStateOnMisbehaviour is unsupported by the 09-localhost client type and performs a no-op.
|
|
func (LightClientModule) UpdateStateOnMisbehaviour(_ sdk.Context, _ string, _ exported.ClientMessage) {
|
|
// no-op
|
|
}
|
|
|
|
// UpdateState performs a no-op and returns the context height in the updated heights return value.
|
|
func (LightClientModule) UpdateState(ctx sdk.Context, _ string, _ exported.ClientMessage) []exported.Height {
|
|
return []exported.Height{clienttypes.GetSelfHeight(ctx)}
|
|
}
|
|
|
|
// VerifyMembership is a generic proof verification method which verifies the existence of a given key and value within the IBC store.
|
|
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
|
|
// The caller must provide the full IBC store.
|
|
func (l LightClientModule) VerifyMembership(
|
|
ctx sdk.Context,
|
|
clientID string,
|
|
height exported.Height,
|
|
delayTimePeriod uint64,
|
|
delayBlockPeriod uint64,
|
|
proof []byte,
|
|
path exported.Path,
|
|
value []byte,
|
|
) error {
|
|
ibcStore := l.storeService.OpenKVStore(ctx)
|
|
|
|
// ensure the proof provided is the expected sentinel localhost client proof
|
|
if !bytes.Equal(proof, SentinelProof) {
|
|
return errorsmod.Wrapf(commitmenttypes.ErrInvalidProof, "expected %s, got %s", string(SentinelProof), string(proof))
|
|
}
|
|
|
|
merklePath, ok := path.(commitmenttypesv2.MerklePath)
|
|
if !ok {
|
|
return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", commitmenttypesv2.MerklePath{}, path)
|
|
}
|
|
|
|
if len(merklePath.GetKeyPath()) != 2 {
|
|
return errorsmod.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
|
|
}
|
|
|
|
// The commitment prefix (eg: "ibc") is omitted when operating on the core IBC store
|
|
bz, err := ibcStore.Get(merklePath.KeyPath[1])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if bz == nil {
|
|
return errorsmod.Wrapf(clienttypes.ErrFailedMembershipVerification, "value not found for path %s", path)
|
|
}
|
|
|
|
if !bytes.Equal(bz, value) {
|
|
return errorsmod.Wrapf(clienttypes.ErrFailedMembershipVerification, "value provided does not equal value stored at path: %s", path)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath within the IBC store.
|
|
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
|
|
// The caller must provide the full IBC store.
|
|
func (l LightClientModule) VerifyNonMembership(
|
|
ctx sdk.Context,
|
|
clientID string,
|
|
height exported.Height,
|
|
delayTimePeriod uint64,
|
|
delayBlockPeriod uint64,
|
|
proof []byte,
|
|
path exported.Path,
|
|
) error {
|
|
ibcStore := l.storeService.OpenKVStore(ctx)
|
|
|
|
// ensure the proof provided is the expected sentinel localhost client proof
|
|
if !bytes.Equal(proof, SentinelProof) {
|
|
return errorsmod.Wrapf(commitmenttypes.ErrInvalidProof, "expected %s, got %s", string(SentinelProof), string(proof))
|
|
}
|
|
|
|
merklePath, ok := path.(commitmenttypesv2.MerklePath)
|
|
if !ok {
|
|
return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", commitmenttypesv2.MerklePath{}, path)
|
|
}
|
|
|
|
if len(merklePath.GetKeyPath()) != 2 {
|
|
return errorsmod.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
|
|
}
|
|
|
|
// The commitment prefix (eg: "ibc") is omitted when operating on the core IBC store
|
|
has, err := ibcStore.Has(merklePath.KeyPath[1])
|
|
if err != nil {
|
|
return errorsmod.Wrapf(err, "error checking for value for path %s", path)
|
|
}
|
|
if has {
|
|
return errorsmod.Wrapf(clienttypes.ErrFailedNonMembershipVerification, "value found for path %s", path)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Status always returns Active. The 09-localhost status cannot be changed.
|
|
func (LightClientModule) Status(_ sdk.Context, _ string) exported.Status {
|
|
return exported.Active
|
|
}
|
|
|
|
// LatestHeight returns the context height.
|
|
func (LightClientModule) LatestHeight(ctx sdk.Context, _ string) exported.Height {
|
|
return clienttypes.GetSelfHeight(ctx)
|
|
}
|
|
|
|
// TimestampAtHeight returns the current block time retrieved from the application context. The localhost client does not store consensus states and thus
|
|
// cannot provide a timestamp for the provided height.
|
|
func (LightClientModule) TimestampAtHeight(ctx sdk.Context, _ string, _ exported.Height) (uint64, error) {
|
|
return uint64(ctx.BlockTime().UnixNano()), nil
|
|
}
|
|
|
|
// RecoverClient returns an error. The localhost cannot be modified by proposals.
|
|
func (LightClientModule) RecoverClient(_ sdk.Context, _, _ string) error {
|
|
return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal")
|
|
}
|
|
|
|
// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded.
|
|
func (LightClientModule) VerifyUpgradeAndUpdateState(_ sdk.Context, _ string, _, _, _, _ []byte) error {
|
|
return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client")
|
|
}
|