ICS3: Add Connection Upgrade Spec#621
Conversation
|
Some notes:
|
colin-axner
left a comment
There was a problem hiding this comment.
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.
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.
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.
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.
yeah, this makes sense to me
| } | ||
|
|
||
| provableStore.set(statusPath(identifier), upgradeStatus) | ||
| provableStore.set(connectionPath(identifier), proposedUpgrade.connection) |
There was a problem hiding this comment.
yeah, this makes sense to me
Co-authored-by: Christopher Goes <cwgoes@pluranimity.org>
mpoke
left a comment
There was a problem hiding this comment.
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.
| function verifyConnectionUpgradeError( | |
| function VerifyUpgradeError( |
There was a problem hiding this comment.
I've added Connection here to the name because there are identical functions for channel upgradability.
There was a problem hiding this comment.
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.
| function verifyConnectionUpgradeTimeout( | |
| function VerifyUpgradeTimeout( |
| ```typescript | ||
| // Client VerifyUpgradeError | ||
| function verifyConnectionUpgradeError( | ||
| clientState: ClientState, |
There was a problem hiding this comment.
clientState is not passed when calling client.verifyUpgradeError()
There was a problem hiding this comment.
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.
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.
clientState is not passed when calling client.verifyUpgradeTimeout()
| 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.
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.
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.
Co-authored-by: Marius Poke <marius.poke@posteo.de>
colin-axner
left a comment
There was a problem hiding this comment.
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.
we have to be careful to not use relayer provided information unless verified (especially if we are restoring/cancelling an upgrade)
mpoke
left a comment
There was a problem hiding this comment.
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.
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`. |
| // 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.
I find this a detail of implementation. Not sure it's needed in the spec.
There was a problem hiding this comment.
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.
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.
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.
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