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

Implement Channel Upgrade Try functionality for 04 channel #3333

Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
50e84bc
WIP - adding scaffolding for channel upgrade init
damiannolan Mar 20, 2023
72d2c75
adding application callbacks and no-op implementations
chatton Mar 22, 2023
cef2f6b
Merge branch 'cian/damian/add-noop-application-callbacks' into damian…
damiannolan Mar 22, 2023
ca6bc94
refactoring init upgrade handler and adding tests
damiannolan Mar 22, 2023
c3bc3ae
adding additional testing, response values and events
damiannolan Mar 23, 2023
43eeaab
adding rough impl of subset of ordering method
damiannolan Mar 23, 2023
86753be
adding additional test for upgrade ordering
damiannolan Mar 23, 2023
95b6a2c
Merge branch '04-channel-upgrades' into damian/1618-chan-upgrade-init
damiannolan Mar 23, 2023
21dfc70
adding godocs
damiannolan Mar 23, 2023
524ec5e
updating testing endpoint func to accept timeout args
damiannolan Mar 23, 2023
f1f8e69
satisfy the linter... waaaahh
damiannolan Mar 23, 2023
012d768
cap -> chanCap
damiannolan Mar 23, 2023
186c279
test: adding test for VerifyUpgradeSequenceRecv
chatton Mar 23, 2023
a823c2f
rename test function
chatton Mar 23, 2023
16ced5b
Update modules/core/03-connection/keeper/verify.go
chatton Mar 23, 2023
bde47ac
wip: added most of ChannelUpgradeTry
chatton Mar 23, 2023
ac962e1
adding generic contains method
damiannolan Mar 24, 2023
39fead1
adding upgrade seq to events and response, move version check to vali…
damiannolan Mar 24, 2023
add66ad
Merge branch 'damian/1618-chan-upgrade-init' into cian/issue#1608-add…
damiannolan Mar 24, 2023
903396f
Merge branch 'cian/issue#1608-add-verifychannelupgradesequence-method…
damiannolan Mar 24, 2023
032551f
adding getter/setter for ErrorReceipt, adding tests
damiannolan Mar 24, 2023
0c6cbfb
adding testing scaffolding for chan upgrade try
damiannolan Mar 24, 2023
6287f1b
adding more test coverage
damiannolan Mar 24, 2023
165e23d
use proposed upgrade channel connection, adding test case
damiannolan Mar 24, 2023
f34298d
move empty version checking of proposed channel upgrade to validate b…
damiannolan Mar 24, 2023
9ecf67b
fix port and channel ids passed to verify funcs
damiannolan Mar 24, 2023
5dc87f1
use counterparty ids from upgrade channel
damiannolan Mar 24, 2023
474a7d8
adding upgrade sequence return value, inline comments and some refactor
damiannolan Mar 24, 2023
e56607f
adding restore channel scaffolding
damiannolan Mar 24, 2023
30d076c
adding write func for successful upgrade try
damiannolan Mar 24, 2023
18e81a8
discard redundant proofHeights in test endpoint
damiannolan Mar 24, 2023
1696a70
commit error receipt to state and abort channel upgrade early
damiannolan Mar 24, 2023
4c51388
ensure upgraded channel connection end is relative to counterparty
damiannolan Mar 27, 2023
e797812
merge with feature branch and add calls to verifiy and restore functions
chatton Mar 29, 2023
e5fd5d6
updated error message
chatton Mar 29, 2023
eed9b91
added previous version as return argument
chatton Mar 29, 2023
f1b19ba
re-added tests for UpgradeTry
chatton Mar 29, 2023
c5cf6e6
wip: adding test for crossing hellos
chatton Mar 29, 2023
9b750c1
refactor chan upgrade try to accomodate crossing hellos, adding test …
damiannolan Mar 30, 2023
1dde2ea
adding additional test cases for connection not found, invalid counte…
damiannolan Mar 30, 2023
3f4205e
adding more tests and timeout checks commented out
damiannolan Mar 30, 2023
fcc0c34
cleanup
damiannolan Mar 30, 2023
0de9d39
appeased the linting overlords
chatton Mar 30, 2023
564ddec
adding timeout tests
chatton Mar 30, 2023
3124a14
cleaning up some testcases
damiannolan Mar 31, 2023
ba9b2c4
adding happy path response values
damiannolan Mar 31, 2023
ccced69
adding upgrade try events
damiannolan Mar 31, 2023
438ea63
cleanup errors file
damiannolan Mar 31, 2023
7f7c399
Merge branch '04-channel-upgrades' into cian/issue#1619-implement-cha…
damiannolan Mar 31, 2023
ddf179d
removing check that is already in validate basic
damiannolan Mar 31, 2023
900e632
merge 04-channel-upgrades
chatton Apr 3, 2023
8ddc924
update with spec changes
charleenfei Apr 3, 2023
0d49837
update upgrade sequence code blockk
charleenfei Apr 3, 2023
8fcca78
created separate function to return the connection end
chatton Apr 3, 2023
1886a50
update missing test coverage
charleenfei Apr 3, 2023
ea1d7dc
fix linting issues
chatton Apr 4, 2023
9352b30
Merge branch 'separate-out-happypath-crossing-hellos' into cian/issue…
chatton Apr 4, 2023
e389c77
adding additional test cases and assigning fields to existing channel
chatton Apr 4, 2023
4839088
added check to verify the computed upgrade channel equals the expecte…
chatton Apr 4, 2023
05a299f
todos
charleenfei Apr 4, 2023
4eea882
mv event emission to other pr
charleenfei Apr 4, 2023
004162b
fix linter
chatton Apr 5, 2023
7df0e52
small error message change
crodriguezvega Apr 5, 2023
35c7e35
remove callback word from log messages
crodriguezvega Apr 5, 2023
64ef5aa
add log message on failed upgrade try callback
crodriguezvega Apr 5, 2023
abe38fe
addressing PR feedback
chatton Apr 5, 2023
01b883f
Merge branch '04-channel-upgrades' into cian/issue#1619-implement-cha…
chatton Apr 5, 2023
bc145f9
rm deep equal check in favour of zeroing custom fields
charleenfei Apr 5, 2023
dab7eb1
update test coverage to test for channel state
charleenfei Apr 5, 2023
163cd9a
lint
charleenfei Apr 5, 2023
6547783
pr review updates
charleenfei Apr 5, 2023
f445158
precommit
charleenfei Apr 5, 2023
5874333
rm references to chanCap
charleenfei Apr 5, 2023
00a3136
update
charleenfei Apr 5, 2023
c158a98
addressing PR feedback
chatton Apr 6, 2023
d6660b0
remove restore call from timeout checks
chatton Apr 6, 2023
b79cdfc
Merge branch '04-channel-upgrades' into channel-upgrade-try
charleenfei Apr 11, 2023
946d3c5
Merge branch 'cian/issue#1619-implement-channelupgradetry-functionali…
charleenfei Apr 11, 2023
61427c0
merge conflicts
charleenfei Apr 11, 2023
bd8574c
Merge branch 'cian/issue#1619-implement-channelupgradetry-functionali…
chatton Apr 11, 2023
f9d0ee6
Merge branch '04-channel-upgrades' into cian/issue#1619-implement-cha…
chatton Apr 11, 2023
a3603f8
Merge branch 'cian/issue#1619-implement-channelupgradetry-functionali…
chatton Apr 11, 2023
77848dd
fixing tests for init and try
chatton Apr 12, 2023
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
11 changes: 11 additions & 0 deletions internal/collections/collections.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package collections

// Contains is a generic function which returns true if elem T exists within the list of elements []T.
func Contains[T comparable](elem T, elements []T) bool {
for _, e := range elements {
if elem == e {
return true
}
}
return false
}
38 changes: 38 additions & 0 deletions modules/core/03-connection/keeper/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,44 @@ func (k Keeper) VerifyNextSequenceRecv(
return nil
}

// VerifyChannelUpgradeSequence verifies a proof of the upgrade sequence number to be
// used during channel upgrades.
func (k Keeper) VerifyChannelUpgradeSequence(
ctx sdk.Context,
connection exported.ConnectionI,
height exported.Height,
proof []byte,
portID,
channelID string,
upgradeSequence uint64,
) error {
clientID := connection.GetClientID()
clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID)
if err != nil {
return err
}

if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active {
return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status)
}

merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeSequencePath(portID, channelID))
merklePath, err = commitmenttypes.ApplyPrefix(connection.GetCounterparty().GetPrefix(), merklePath)
if err != nil {
return err
}

if err := clientState.VerifyMembership(
ctx, clientStore, k.cdc, height,
0, 0, // skip delay period checks for non-packet processing verification
proof, merklePath, sdk.Uint64ToBigEndian(upgradeSequence),
); err != nil {
return errorsmod.Wrapf(err, "failed upgrade sequence verification for client (%s)", clientID)
}

return nil
}

// getBlockDelay calculates the block delay period from the time delay of the connection
// and the maximum expected time per block.
func (k Keeper) getBlockDelay(ctx sdk.Context, connection exported.ConnectionI) uint64 {
Expand Down
83 changes: 83 additions & 0 deletions modules/core/03-connection/keeper/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,89 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() {
}
}

func (suite *KeeperTestSuite) TestVerifyUpgradeSequence() {
var (
path *ibctesting.Path
expectedUpgradeSequence uint64
)

cases := []struct {
name string
malleate func()
expPass bool
}{
{
name: "success",
malleate: func() {},
expPass: true,
},
{
name: "fails with different upgrade sequence",
malleate: func() {
expectedUpgradeSequence = 10
},
expPass: false,
},
{
name: "fails when client state is frozen",
malleate: func() {
clientState := path.EndpointB.GetClientState().(*ibctm.ClientState)
clientState.FrozenHeight = clienttypes.NewHeight(0, 1)
path.EndpointB.SetClientState(clientState)
},
expPass: false,
},
{
name: "fails with bad client id",
malleate: func() {
connection := path.EndpointB.GetConnection()
connection.ClientId = ibctesting.InvalidID
path.EndpointB.SetConnection(connection)
},
expPass: false,
},
{
name: "verification fails when the key does not exist",
malleate: func() {
storeKey := path.EndpointA.Chain.GetSimApp().GetKey(exported.StoreKey)
kvStore := path.EndpointA.Chain.GetContext().KVStore(storeKey)
kvStore.Delete(host.ChannelUpgradeSequenceKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID))
suite.coordinator.CommitBlock(suite.chainA)
},
expPass: false,
},
}

for _, tc := range cases {
tc := tc

suite.Run(tc.name, func() {
suite.SetupTest() // reset

expectedUpgradeSequence = 1

path = ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.Setup(path)

err := path.EndpointA.ChanUpgradeInit(path.EndpointB.Chain.GetTimeoutHeight(), 0)
suite.Require().NoError(err)

tc.malleate()

upgradeSequenceKey := host.ChannelUpgradeSequenceKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
proof, proofHeight := suite.chainA.QueryProof(upgradeSequenceKey)

err = suite.chainB.GetSimApp().IBCKeeper.ConnectionKeeper.VerifyChannelUpgradeSequence(suite.chainB.GetContext(), path.EndpointB.GetConnection(), malleateHeight(proofHeight, 0), proof, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, expectedUpgradeSequence)

if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

func malleateHeight(height exported.Height, diff uint64) exported.Height {
return clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+diff)
}
20 changes: 20 additions & 0 deletions modules/core/04-channel/keeper/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,23 @@ func emitChannelClosedEvent(ctx sdk.Context, packet exported.PacketI, channel ty
),
})
}

// emitChannelUpgradeInitEvent emits a channel upgrade init event
func emitChannelUpgradeInitEvent(ctx sdk.Context, portID string, channelID string, upgradeSequence uint64, channel types.Channel) {
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeChannelUpgradeInit,
sdk.NewAttribute(types.AttributeKeyPortID, portID),
sdk.NewAttribute(types.AttributeKeyChannelID, channelID),
sdk.NewAttribute(types.AttributeCounterpartyPortID, channel.Counterparty.PortId),
sdk.NewAttribute(types.AttributeCounterpartyChannelID, channel.Counterparty.ChannelId),
sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]),
sdk.NewAttribute(types.AttributeVersion, channel.Version),
sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", upgradeSequence)),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
})
}
60 changes: 60 additions & 0 deletions modules/core/04-channel/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,66 @@ func (k Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string)
return porttypes.GetModuleOwner(modules), capability, nil
}

// GetUpgradeRestoreChannel returns the upgrade restore channel for the provided port and channel identifiers.
func (k Keeper) GetUpgradeRestoreChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.ChannelRestoreKey(portID, channelID))
if bz == nil {
return types.Channel{}, false
}

var channel types.Channel
k.cdc.MustUnmarshal(bz, &channel)

return channel, true
}

// SetUpgradeRestoreChannel sets the provided channel in store using the port and channel identifiers.
func (k Keeper) SetUpgradeRestoreChannel(ctx sdk.Context, portID, channelID string, channel types.Channel) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&channel)
store.Set(host.ChannelRestoreKey(portID, channelID), bz)
}

// GetUpgradeSequence returns the upgrade sequence for the provided port and channel identifers.
func (k Keeper) GetUpgradeSequence(ctx sdk.Context, portID, channelID string) (uint64, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.ChannelUpgradeSequenceKey(portID, channelID))
if bz == nil {
return 0, false
}

return sdk.BigEndianToUint64(bz), true
}

// SetUpgradeSequence sets the upgrade sequence using the provided port and channel identifiers.
func (k Keeper) SetUpgradeSequence(ctx sdk.Context, portID, channelID string, sequence uint64) {
store := ctx.KVStore(k.storeKey)
bz := sdk.Uint64ToBigEndian(sequence)
store.Set(host.ChannelUpgradeSequenceKey(portID, channelID), bz)
}

// GetUpgradeTimeout returns the upgrade timeout stored in state for the provided port and channel identifiers.
func (k Keeper) GetUpgradeTimeout(ctx sdk.Context, portID, channelID string) (types.UpgradeTimeout, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.ChannelUpgradeTimeoutKey(portID, channelID))
if bz == nil {
return types.UpgradeTimeout{}, false
}

var upgradeTimeout types.UpgradeTimeout
k.cdc.MustUnmarshal(bz, &upgradeTimeout)

return upgradeTimeout, true
}

// SetUpgradeTimeout sets the upgrade timeout in store using the provided port and channel identifiers.
func (k Keeper) SetUpgradeTimeout(ctx sdk.Context, portID, channelID string, upgradeTimeout types.UpgradeTimeout) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&upgradeTimeout)
store.Set(host.ChannelUpgradeTimeoutKey(portID, channelID), bz)
}

// common functionality for IteratePacketCommitment and IteratePacketAcknowledgement
func (k Keeper) iterateHashes(ctx sdk.Context, iterator db.Iterator, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() })
Expand Down
52 changes: 52 additions & 0 deletions modules/core/04-channel/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/suite"

transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v7/testing"
ibcmock "github.com/cosmos/ibc-go/v7/testing/mock"
Expand Down Expand Up @@ -465,3 +466,54 @@ func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() {
suite.Require().Equal(ackHash, storedAckHash)
suite.Require().True(suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketAcknowledgement(ctxA, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, seq))
}

func (suite *KeeperTestSuite) TestSetRestoreChannel() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
suite.coordinator.CreateChannels(path)

restoreChannel, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeRestoreChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().False(found)
suite.Require().Empty(restoreChannel)

expChannel := types.NewChannel(types.OPEN, types.UNORDERED, types.NewCounterparty(ibcmock.PortID, ibctesting.FirstChannelID), []string{ibctesting.FirstConnectionID}, ibcmock.Version)
suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetUpgradeRestoreChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, expChannel)

restoreChannel, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeRestoreChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().True(found)
suite.Require().Equal(expChannel, restoreChannel)
}

func (suite *KeeperTestSuite) TestSetUpgradeSequence() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
suite.coordinator.CreateChannels(path)

sequence, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().False(found)
suite.Require().Zero(sequence)

expSequence := uint64(1)
suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetUpgradeSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, expSequence)

sequence, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeSequence(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().True(found)
suite.Require().Equal(expSequence, sequence)
}

func (suite *KeeperTestSuite) TestSetUpgradeTimeout() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
suite.coordinator.CreateChannels(path)

upgradeTimeout, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeTimeout(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().False(found)
suite.Require().Empty(upgradeTimeout)

expUpgradeTimeout := types.UpgradeTimeout{TimeoutHeight: clienttypes.NewHeight(1, 10), TimeoutTimestamp: uint64(suite.coordinator.CurrentTime.UnixNano())}
suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetUpgradeTimeout(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, expUpgradeTimeout)

upgradeTimeout, found = suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetUpgradeTimeout(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
suite.Require().True(found)
suite.Require().Equal(expUpgradeTimeout, upgradeTimeout)
}
Loading