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

feat: allow governance to update the TrustingPeriod of the 07-tendermint light client #1713

Merged
merged 16 commits into from
Jul 21, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`.
* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed.
* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour`. See ADR-026 for context.
* (modules/light-clients/07-tendermint) [\#1713](https://github.com/cosmos/ibc-go/pull/1713) Allow client upgrade proposals to update `TrustingPeriod`. See ADR-026 for context.

### Features

Expand Down
4 changes: 4 additions & 0 deletions docs/architecture/adr-026-ibc-client-recovery-mechanisms.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- 2021/01/15: Revision to support substitute clients for unfreezing
- 2021/05/20: Revision to simplify consensus state copying, remove initial height
- 2022/04/08: Revision to deprecate AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour
- 2022/07/15: Revision to allow updating of TrustingPeriod

## Status

Expand Down Expand Up @@ -51,6 +52,9 @@ We elect not to deal with chains which have actually halted, which is necessaril

Previously, `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour` were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same.

In addition, `TrustingPeriod` was initally not allowed to be updated by a client upgrade proposal. However, due to the number of situations experienced in production where the `TrustingPeriod` of a client should be allowed to be updated because of ie: initial misconfiguration for a canonical channel, governance should be allowed to update this client parameter.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved

Note that this should NOT be lightly updated, as there may be a gap in time between when misbehaviour has occured and when the evidence of misbehaviour is submitted. For example, if the `UnbondingPeriod` is 2 weeks and the `TrustingPeriod` has also been set to two weeks, a validator could wait until right before `UnbondingPeriod` finishes, submit false information, then unbond and exit without being slashed for misbehaviour. Therefore, we recommend that the trusting period for the 07-tendermint client be set at a minimum to 2/3 of the `UnbondingPeriod`.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Note that this should NOT be lightly updated, as there may be a gap in time between when misbehaviour has occured and when the evidence of misbehaviour is submitted. For example, if the `UnbondingPeriod` is 2 weeks and the `TrustingPeriod` has also been set to two weeks, a validator could wait until right before `UnbondingPeriod` finishes, submit false information, then unbond and exit without being slashed for misbehaviour. Therefore, we recommend that the trusting period for the 07-tendermint client be set at a minimum to 2/3 of the `UnbondingPeriod`.
Note that this should NOT be lightly updated, as there may be a gap in time between when misbehaviour has occured and when the evidence of misbehaviour is submitted. For example, if the `UnbondingPeriod` is 2 weeks and the `TrustingPeriod` has also been set to two weeks, a validator could wait until right before `UnbondingPeriod` finishes, submit false information, then unbond and exit without being slashed for misbehaviour. Therefore, we recommend that the trusting period for the 07-tendermint client be set at 2/3 of the `UnbondingPeriod`.

Minimum doesn't make sense here since it is really more of a maximum. It's bad for it to be 999/1000 of the unbonding period for example. But really the relevant point here isn't a ratio of the two, but rather the delta between them.

i.e. UnbondingPeriod - TrustingPeriod is more relevant than TrustingPeriod / UnbondingPeriod

I think its fine to leave 2/3 as sensible default but wouldn't say that people should treat the ratio as being semantically significant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense! i'll take it out


Note that clients frozen due to misbehaviour must wait for the evidence to expire to avoid becoming refrozen.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"reflect"
"time"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -70,20 +71,25 @@ func (cs ClientState) CheckSubstituteAndUpdateState(
cs.LatestHeight = substituteClientState.LatestHeight
cs.ChainId = substituteClientState.ChainId

// set new trusting period based on the substitute client state
cs.TrustingPeriod = substituteClientState.TrustingPeriod

// no validation is necessary since the substitute is verified to be Active
// in 02-client.

return &cs, nil
}

// IsMatchingClientState returns true if all the client state parameters match
// except for frozen height, latest height, and chain-id.
// except for frozen height, latest height, trusting period, chain-id.
func IsMatchingClientState(subject, substitute ClientState) bool {
// zero out parameters which do not need to match
subject.LatestHeight = clienttypes.ZeroHeight()
subject.FrozenHeight = clienttypes.ZeroHeight()
subject.TrustingPeriod = time.Duration(0)
substitute.LatestHeight = clienttypes.ZeroHeight()
substitute.FrozenHeight = clienttypes.ZeroHeight()
substitute.TrustingPeriod = time.Duration(0)
subject.ChainId = ""
substitute.ChainId = ""
// sets both sets of flags to true as these flags have been DEPRECATED, see ADR-026 for more information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() {
substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(substitutePath)
substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState)
// update trusting period of substitute client state
substituteClientState.TrustingPeriod = time.Hour * 24 * 7
suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID, substituteClientState)

// update substitute a few times
Expand Down Expand Up @@ -191,6 +193,7 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() {
suite.Require().Equal(expectedIterationKey, subjectIterationKey)

suite.Require().Equal(newChainID, updatedClient.(*types.ClientState).ChainId)
suite.Require().Equal(time.Hour*24*7, updatedClient.(*types.ClientState).TrustingPeriod)
} else {
suite.Require().Error(err)
suite.Require().Nil(updatedClient)
Expand Down Expand Up @@ -235,9 +238,15 @@ func (suite *TendermintTestSuite) TestIsMatchingClientState() {
}, true,
},
{
"not matching, trusting period is different", func() {
"matching, trusting period is different", func() {
subjectClientState.TrustingPeriod = time.Duration(time.Hour * 10)
substituteClientState.TrustingPeriod = time.Duration(time.Hour * 1)
}, true,
},
{
"not matching, trust level is different", func() {
subjectClientState.TrustLevel = types.Fraction{2, 3}
substituteClientState.TrustLevel = types.Fraction{1, 3}
}, false,
},
}
Expand Down