Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VerifyMembership to 07-tendermint #1297

Merged
merged 9 commits into from
Apr 28, 2022
110 changes: 88 additions & 22 deletions modules/light-clients/07-tendermint/types/client_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientSto

// VerifyClientState verifies a proof of the client state of the running chain
// stored on the target machine
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyClientState(
store sdk.KVStore,
cdc codec.BinaryCodec,
Expand Down Expand Up @@ -231,6 +232,7 @@ func (cs ClientState) VerifyClientState(

// VerifyClientConsensusState verifies a proof of the consensus state of the
// Tendermint client stored on the target machine.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyClientConsensusState(
store sdk.KVStore,
cdc codec.BinaryCodec,
Expand Down Expand Up @@ -275,6 +277,7 @@ func (cs ClientState) VerifyClientConsensusState(

// VerifyConnectionState verifies a proof of the connection state of the
// specified connection end stored on the target machine.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyConnectionState(
store sdk.KVStore,
cdc codec.BinaryCodec,
Expand Down Expand Up @@ -314,6 +317,7 @@ func (cs ClientState) VerifyConnectionState(

// VerifyChannelState verifies a proof of the channel state of the specified
// channel end, under the specified port, stored on the target machine.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyChannelState(
store sdk.KVStore,
cdc codec.BinaryCodec,
Expand Down Expand Up @@ -354,6 +358,7 @@ func (cs ClientState) VerifyChannelState(

// VerifyPacketCommitment verifies a proof of an outgoing packet commitment at
// the specified port, specified channel, and specified sequence.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyPacketCommitment(
ctx sdk.Context,
store sdk.KVStore,
Expand Down Expand Up @@ -393,6 +398,7 @@ func (cs ClientState) VerifyPacketCommitment(

// VerifyPacketAcknowledgement verifies a proof of an incoming packet
// acknowledgement at the specified port, specified channel, and specified sequence.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyPacketAcknowledgement(
ctx sdk.Context,
store sdk.KVStore,
Expand Down Expand Up @@ -433,6 +439,7 @@ func (cs ClientState) VerifyPacketAcknowledgement(
// VerifyPacketReceiptAbsence verifies a proof of the absence of an
// incoming packet receipt at the specified port, specified channel, and
// specified sequence.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyPacketReceiptAbsence(
ctx sdk.Context,
store sdk.KVStore,
Expand Down Expand Up @@ -471,6 +478,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence(

// VerifyNextSequenceRecv verifies a proof of the next sequence number to be
// received of the specified channel at the specified port.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func (cs ClientState) VerifyNextSequenceRecv(
ctx sdk.Context,
store sdk.KVStore,
Expand Down Expand Up @@ -509,39 +517,97 @@ func (cs ClientState) VerifyNextSequenceRecv(
return nil
}

// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height.
// 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(
ctx sdk.Context,
clientStore sdk.KVStore,
cdc codec.BinaryCodec,
height exported.Height,
delayTimePeriod uint64,
delayBlockPeriod uint64,
proof []byte,
path []byte,
value []byte,
) error {
if cs.GetLatestHeight().LT(height) {
return sdkerrors.Wrapf(
sdkerrors.ErrInvalidHeight,
"client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height,
)
}

if err := verifyDelayPeriodPassed(ctx, clientStore, height, delayTimePeriod, delayBlockPeriod); err != nil {
return err
}

var merkleProof commitmenttypes.MerkleProof
if err := cdc.Unmarshal(proof, &merkleProof); err != nil {
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into ICS 23 commitment merkle proof")
}

var merklePath commitmenttypes.MerklePath
if err := cdc.Unmarshal(path, &merklePath); err != nil {
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal path into ICS 23 commitment merkle path")
}

consensusState, found := GetConsensusState(clientStore, cdc, height)
if !found {
return sdkerrors.Wrap(clienttypes.ErrConsensusStateNotFound, "please ensure the proof was constructed against a height that exists on the client")
}

if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), merklePath, value); err != nil {
return err
}

return nil
}

// verifyDelayPeriodPassed will ensure that at least delayTimePeriod amount of time and delayBlockPeriod number of blocks have passed
// since consensus state was submitted before allowing verification to continue.
func verifyDelayPeriodPassed(ctx sdk.Context, store sdk.KVStore, proofHeight exported.Height, delayTimePeriod, delayBlockPeriod uint64) error {
// check that executing chain's timestamp has passed consensusState's processed time + delay time period
processedTime, ok := GetProcessedTime(store, proofHeight)
if !ok {
return sdkerrors.Wrapf(ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight)
}
currentTimestamp := uint64(ctx.BlockTime().UnixNano())
validTime := processedTime + delayTimePeriod
// NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error
if currentTimestamp < validTime {
return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d",
validTime, currentTimestamp)
}
// check that executing chain's height has passed consensusState's processed height + delay block period
processedHeight, ok := GetProcessedHeight(store, proofHeight)
if !ok {
return sdkerrors.Wrapf(ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight)
if delayTimePeriod != 0 {
// check that executing chain's timestamp has passed consensusState's processed time + delay time period
processedTime, ok := GetProcessedTime(store, proofHeight)
if !ok {
return sdkerrors.Wrapf(ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight)
}

currentTimestamp := uint64(ctx.BlockTime().UnixNano())
validTime := processedTime + delayTimePeriod

// NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error
if currentTimestamp < validTime {
return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d",
validTime, currentTimestamp)
}

}
currentHeight := clienttypes.GetSelfHeight(ctx)
validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod)
// NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error
if currentHeight.LT(validHeight) {
return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s",
validHeight, currentHeight)

if delayBlockPeriod != 0 {
// check that executing chain's height has passed consensusState's processed height + delay block period
processedHeight, ok := GetProcessedHeight(store, proofHeight)
if !ok {
return sdkerrors.Wrapf(ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight)
}

currentHeight := clienttypes.GetSelfHeight(ctx)
validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod)

// NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error
if currentHeight.LT(validHeight) {
return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s",
validHeight, currentHeight)
}
}

return nil
}

// produceVerificationArgs perfoms the basic checks on the arguments that are
// shared between the verification functions and returns the unmarshalled
// merkle proof, the consensus state and an error if one occurred.
// TODO: remove, https://github.com/cosmos/ibc-go/issues/1294
func produceVerificationArgs(
store sdk.KVStore,
cdc codec.BinaryCodec,
Expand Down
Loading