-
Notifications
You must be signed in to change notification settings - Fork 390
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
ICS3: Add Connection Upgrade Spec #621
Conversation
Some notes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent!! Concept makes sense to me. Architecturally not difficult to introduce into existing ibc implementations
} | ||
|
||
provableStore.set(statusPath(identifier), upgradeStatus) | ||
provableStore.set(connectionPath(identifier), proposedUpgrade.connection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I'd think you'd want to leave the connection unchanged until the upgrade process successfully completes. Otherwise you could potentially disrupt packet flow if the connection is in UPGRADE_INIT instead of OPEN?
I'd expect you to store the proposed upgrade connection under a proposed upgrade connection path. Use that for proofs and then if successful update the connection on ack/confirm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want the case where chainA has its connectionEnd OPEN with the old parameters, and chainB has its connectionEnd OPEN with the new parameters as that may cause unexpected consequences.
If a connection is OPEN
on both ends it should be a valid connection always.
So either both ends are OPEN
running the old parameters, or both ends are OPEN
running the new parameters.
The only way to accomplish this is to temporarily close the connection on both sides (INIT and TRY), then reopen after the upgrade is complete on either end (ACK and CONFIRM).
This does mean packet flow is temporarily halted but i believe this is fine. Once the connection is back up, the relayers can either receive or timeout the pending packets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also why I specify a timeout, because I don't want the "temporary pause" to last arbitrarily long
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, this makes sense to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK; most changes ACK (modulo open question of crossing hellos); see a few minor comments.
I will also note that I would like to see re-verification of IBC safety / liveness with this logic incorporated.
} | ||
|
||
provableStore.set(statusPath(identifier), upgradeStatus) | ||
provableStore.set(connectionPath(identifier), proposedUpgrade.connection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, this makes sense to me
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK. I agree with Christopher that we need to make sure that the IBC safety and liveness are preserved with this logic incorporated. See comments below.
Co-authored-by: Marius Poke <marius.poke@posteo.de>
|
||
```typescript | ||
// Client VerifyUpgradeError | ||
function verifyConnectionUpgradeError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function verifyConnectionUpgradeError( | |
function VerifyUpgradeError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added Connection here to the name because there are identical functions for channel upgradability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but the comment above is // Client VerifyUpgradeError
and in the above function, i.e.,
// Connection VerifyConnectionUpgradeError method
function verifyConnectionUpgradeError(
you call client.verifyUpgradeError
|
||
```typescript | ||
// Client VerifyUpgradeTimeout | ||
function verifyConnectionUpgradeTimeout( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function verifyConnectionUpgradeTimeout( | |
function VerifyUpgradeTimeout( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
```typescript | ||
// Client VerifyUpgradeError | ||
function verifyConnectionUpgradeError( | ||
clientState: ClientState, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clientState
is not passed when calling client.verifyUpgradeError()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same pattern used in ICS3 and ICS2. I believe it is the standard for Typescript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I've seen that. I find it very confusing. Until now I thought it's an inconsistency. Still not convinced that it's not :)
```typescript | ||
// Client VerifyUpgradeTimeout | ||
function verifyConnectionUpgradeTimeout( | ||
clientState: ClientState, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clientState
is not passed when calling client.verifyUpgradeTimeout()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
path = applyPrefix(prefix, timeoutPath(counterpartyConnectionIdentifier)) | ||
abortTransactionUnless(!clientState.frozen) | ||
timeoutBytes = protobuf.marshal(upgradeTimeout) | ||
return clientState.verifiedRoots[height].verifyMembership(path, timeoutBytes, proof) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems very Tendermint specific, i.e., https://github.com/cosmos/ibc/blob/master/spec/client/ics-007-tendermint-client/README.md#state-verification-functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not assume anything about Tendermint, but just says we will verify membership against a consensus state at provided height. This is taken from ICS2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes. The protocol seems correct. I left some comments, most of them minor.
Co-authored-by: Marius Poke <marius.poke@posteo.de>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only reviewed up to the Sub-Protocols
section. LGTM so far
if counterpartyConnection.State != UPGRADE_TRY { | ||
restoreConnection() | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have to be careful to not use relayer provided information unless verified (especially if we are restoring/cancelling an upgrade)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. I have just one concern regarding the transition from UPGRADE_TRY
to OPEN
(i.e., connUpgradeConfirm
). The rest of the comments are just nits.
} | ||
``` | ||
|
||
The UpgradeError MUST have an associated verification function added to the connection and client interfaces so that a counterparty may verify that chain has stored an error in the UpgradeError path. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A verification function is no longer needed for the client interface.
} | ||
``` | ||
|
||
The timeout path MUST have associated verification methods on the connection and client interfaces in order for a counterparty to prove that a chain stored a particular `UpgradeTimeout`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
// construct CommitmentPath | ||
path = applyPrefix(connection.counterpartyPrefix, connectionTimeoutPath(connection.counterpartyConnectionIdentifier)) | ||
// marshal upgradeTimeout into bytes with standardized protobuf codec | ||
timeoutBytes = protobuf.marshal(upgradeTimeout) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a detail of implementation. Not sure it's needed in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No because both sides must agree on an encoding, otherwise they won't be able to verify correctly. So it must be part of spec. I think this is a downside in the rest of spec, that it doesn't explicitly define the encoding you need to use to speak with other IBC chains
restoreConnection() | ||
return | ||
} | ||
upgradeTimeout = UpgradeTimeout{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
upgradeTimeout
is not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh oops, it gets used above in proof verification. Will reorder
|
||
// verify proofs of counterparty state | ||
abortTransactionUnless(verifyConnectionState(currentConnection, proofHeight, proofConnection, currentConnection.counterpartyConnectionIdentifier, counterpartyConnection)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before changing the local connection state to OPEN, shouldn't we check again that the remote connection is compatible with the local one? During connUpgradeAck
, the remote side could restore the connection, which means moving to a connection with state OPEN. Just verifying that the remote side is OPEN may not be enough.
connUpgradeConfirm
should also contain a proof that UpgradeError
was not set by the remote side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh thank you, nice catch
Co-authored-by: Marius Poke <marius.poke@posteo.de>
This is a rough draft proposal for the ability to upgrade a connection once it has already been established