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
194 lines
6.2 KiB
Go
194 lines
6.2 KiB
Go
package solomachine
|
|
|
|
import (
|
|
errorsmod "cosmossdk.io/errors"
|
|
storetypes "cosmossdk.io/store/types"
|
|
|
|
"git.cw.tr/mukan-network/mukan-sdk/codec"
|
|
cryptotypes "git.cw.tr/mukan-network/mukan-sdk/crypto/types"
|
|
"git.cw.tr/mukan-network/mukan-sdk/types/tx/signing"
|
|
|
|
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
|
|
commitmenttypesv2 "git.cw.tr/mukan-network/mukan-ibc/modules/core/23-commitment/types/v2"
|
|
host "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host"
|
|
ibcerrors "git.cw.tr/mukan-network/mukan-ibc/modules/core/errors"
|
|
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
|
|
)
|
|
|
|
var _ exported.ClientState = (*ClientState)(nil)
|
|
|
|
// NewClientState creates a new ClientState instance.
|
|
func NewClientState(latestSequence uint64, consensusState *ConsensusState) *ClientState {
|
|
return &ClientState{
|
|
Sequence: latestSequence,
|
|
IsFrozen: false,
|
|
ConsensusState: consensusState,
|
|
}
|
|
}
|
|
|
|
// ClientType is Solo Machine.
|
|
func (ClientState) ClientType() string {
|
|
return exported.Solomachine
|
|
}
|
|
|
|
// Validate performs basic validation of the client state fields.
|
|
func (cs ClientState) Validate() error {
|
|
if cs.Sequence == 0 {
|
|
return errorsmod.Wrap(clienttypes.ErrInvalidClient, "sequence cannot be 0")
|
|
}
|
|
if cs.ConsensusState == nil {
|
|
return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil")
|
|
}
|
|
return cs.ConsensusState.ValidateBasic()
|
|
}
|
|
|
|
// verifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the latest sequence.
|
|
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
|
|
func (cs *ClientState) verifyMembership(
|
|
clientStore storetypes.KVStore,
|
|
cdc codec.BinaryCodec,
|
|
proof []byte,
|
|
path exported.Path,
|
|
value []byte,
|
|
) error {
|
|
publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, proof)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
// in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
|
|
key, err := merklePath.GetKey(1)
|
|
if err != nil {
|
|
return errorsmod.Wrapf(host.ErrInvalidPath, "key not found at index 1: %v", err)
|
|
}
|
|
|
|
signBytes := &SignBytes{
|
|
Sequence: sequence,
|
|
Timestamp: timestamp,
|
|
Diversifier: cs.ConsensusState.Diversifier,
|
|
Path: key,
|
|
Data: value,
|
|
}
|
|
|
|
signBz, err := cdc.Marshal(signBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := VerifySignature(publicKey, signBz, sigData); err != nil {
|
|
return err
|
|
}
|
|
|
|
cs.Sequence++
|
|
cs.ConsensusState.Timestamp = timestamp
|
|
setClientState(clientStore, cdc, cs)
|
|
|
|
return nil
|
|
}
|
|
|
|
// verifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at the latest sequence.
|
|
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
|
|
func (cs *ClientState) verifyNonMembership(
|
|
clientStore storetypes.KVStore,
|
|
cdc codec.BinaryCodec,
|
|
proof []byte,
|
|
path exported.Path,
|
|
) error {
|
|
publicKey, sigData, timestamp, sequence, err := produceVerificationArgs(cdc, cs, proof)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
// in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
|
|
key, err := merklePath.GetKey(1)
|
|
if err != nil {
|
|
return errorsmod.Wrapf(host.ErrInvalidPath, "key not found at index 1: %v", err)
|
|
}
|
|
|
|
signBytes := &SignBytes{
|
|
Sequence: sequence,
|
|
Timestamp: timestamp,
|
|
Diversifier: cs.ConsensusState.Diversifier,
|
|
Path: key,
|
|
Data: nil,
|
|
}
|
|
|
|
signBz, err := cdc.Marshal(signBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := VerifySignature(publicKey, signBz, sigData); err != nil {
|
|
return err
|
|
}
|
|
|
|
cs.Sequence++
|
|
cs.ConsensusState.Timestamp = timestamp
|
|
setClientState(clientStore, cdc, cs)
|
|
|
|
return nil
|
|
}
|
|
|
|
// produceVerificationArgs performs the basic checks on the arguments that are
|
|
// shared between the verification functions and returns the public key of the
|
|
// consensus state, the unmarshalled proof representing the signature and timestamp.
|
|
func produceVerificationArgs(
|
|
cdc codec.BinaryCodec,
|
|
cs *ClientState,
|
|
proof []byte,
|
|
) (cryptotypes.PubKey, signing.SignatureData, uint64, uint64, error) {
|
|
if proof == nil {
|
|
return nil, nil, 0, 0, errorsmod.Wrap(ErrInvalidProof, "proof cannot be empty")
|
|
}
|
|
|
|
var timestampedSigData TimestampedSignatureData
|
|
if err := cdc.Unmarshal(proof, ×tampedSigData); err != nil {
|
|
return nil, nil, 0, 0, errorsmod.Wrapf(err, "failed to unmarshal proof into type %T", timestampedSigData)
|
|
}
|
|
|
|
timestamp := timestampedSigData.Timestamp
|
|
if len(timestampedSigData.SignatureData) == 0 {
|
|
return nil, nil, 0, 0, errorsmod.Wrap(ErrInvalidProof, "signature data cannot be empty")
|
|
}
|
|
|
|
sigData, err := UnmarshalSignatureData(cdc, timestampedSigData.SignatureData)
|
|
if err != nil {
|
|
return nil, nil, 0, 0, err
|
|
}
|
|
|
|
if cs.ConsensusState.GetTimestamp() > timestamp {
|
|
return nil, nil, 0, 0, errorsmod.Wrapf(ErrInvalidProof, "the consensus state timestamp is greater than the signature timestamp (%d >= %d)", cs.ConsensusState.GetTimestamp(), timestamp)
|
|
}
|
|
|
|
sequence := cs.Sequence
|
|
publicKey, err := cs.ConsensusState.GetPubKey()
|
|
if err != nil {
|
|
return nil, nil, 0, 0, err
|
|
}
|
|
|
|
return publicKey, sigData, timestamp, sequence, nil
|
|
}
|
|
|
|
// sets the client state to the store
|
|
func setClientState(store storetypes.KVStore, cdc codec.BinaryCodec, clientState exported.ClientState) {
|
|
bz := clienttypes.MustMarshalClientState(cdc, clientState)
|
|
store.Set(host.ClientStateKey(), bz)
|
|
}
|