-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
ICS5: Integrate Dynamic Capabilities into IBC #5872
Changes from 3 commits
57aacb4
1ed4923
8ef8225
06e7b80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,15 @@ package keeper | |
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/x/capability" | ||
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" | ||
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" | ||
porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" | ||
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" | ||
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" | ||
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" | ||
) | ||
|
||
// CounterpartyHops returns the connection hops of the counterparty channel. | ||
|
@@ -33,38 +36,44 @@ func (k Keeper) ChanOpenInit( | |
connectionHops []string, | ||
portID, | ||
channelID string, | ||
portCap capability.Capability, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passed in by caller as described in spec:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's correct. Working on updating the spec. |
||
counterparty types.Counterparty, | ||
version string, | ||
) error { | ||
) (capability.Capability, error) { | ||
// channel identifier and connection hop length checked on msg.ValidateBasic() | ||
|
||
_, found := k.GetChannel(ctx, portID, channelID) | ||
if found { | ||
return sdkerrors.Wrap(types.ErrChannelExists, channelID) | ||
return nil, sdkerrors.Wrap(types.ErrChannelExists, channelID) | ||
} | ||
|
||
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) | ||
if !found { | ||
return sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) | ||
return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) | ||
} | ||
|
||
if connectionEnd.GetState() == connectionexported.UNINITIALIZED { | ||
return sdkerrors.Wrap( | ||
return nil, sdkerrors.Wrap( | ||
connection.ErrInvalidConnectionState, | ||
"connection state cannot be UNINITIALIZED", | ||
) | ||
} | ||
|
||
if !k.portKeeper.Authenticate(ctx, portCap, portID) { | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability") | ||
} | ||
|
||
channel := types.NewChannel(exported.INIT, order, counterparty, connectionHops, version) | ||
k.SetChannel(ctx, portID, channelID, channel) | ||
|
||
// TODO: blocked by #5542 | ||
// key := "" | ||
// k.SetChannelCapability(ctx, portID, channelID, key) | ||
capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID)) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error()) | ||
} | ||
k.SetNextSequenceSend(ctx, portID, channelID, 1) | ||
k.SetNextSequenceRecv(ctx, portID, channelID, 1) | ||
|
||
return nil | ||
return capKey, nil | ||
} | ||
|
||
// ChanOpenTry is called by a module to accept the first step of a channel opening | ||
|
@@ -75,12 +84,13 @@ func (k Keeper) ChanOpenTry( | |
connectionHops []string, | ||
portID, | ||
channelID string, | ||
portCap capability.Capability, | ||
counterparty types.Counterparty, | ||
version, | ||
counterpartyVersion string, | ||
proofInit commitmentexported.Proof, | ||
proofHeight uint64, | ||
) error { | ||
) (capability.Capability, error) { | ||
// channel identifier and connection hop length checked on msg.ValidateBasic() | ||
|
||
previousChannel, found := k.GetChannel(ctx, portID, channelID) | ||
|
@@ -93,19 +103,17 @@ func (k Keeper) ChanOpenTry( | |
sdkerrors.Wrap(types.ErrInvalidChannel, "cannot relay connection attempt") | ||
} | ||
|
||
// TODO: blocked by #5542 | ||
// key := sdk.NewKVStoreKey(portID) | ||
// if !k.portKeeper.Authenticate(key, portID) { | ||
// return sdkerrors.Wrap(port.ErrInvalidPort, portID) | ||
// } | ||
if !k.portKeeper.Authenticate(ctx, portCap, portID) { | ||
return nil, sdkerrors.Wrap(porttypes.ErrInvalidPort, "caller does not own port capability") | ||
} | ||
|
||
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) | ||
if !found { | ||
return sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) | ||
return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, connectionHops[0]) | ||
} | ||
|
||
if connectionEnd.GetState() != connectionexported.OPEN { | ||
return sdkerrors.Wrapf( | ||
return nil, sdkerrors.Wrapf( | ||
connection.ErrInvalidConnectionState, | ||
"connection state is not OPEN (got %s)", connectionEnd.GetState().String(), | ||
) | ||
|
@@ -133,26 +141,28 @@ func (k Keeper) ChanOpenTry( | |
ctx, connectionEnd, proofHeight, proofInit, | ||
counterparty.PortID, counterparty.ChannelID, expectedChannel, | ||
); err != nil { | ||
return err | ||
return nil, err | ||
} | ||
|
||
k.SetChannel(ctx, portID, channelID, channel) | ||
|
||
// TODO: blocked by #5542 | ||
// key := "" | ||
// k.SetChannelCapability(ctx, portID, channelID, key) | ||
capKey, err := k.scopedKeeper.NewCapability(ctx, ibctypes.ChannelCapabilityPath(portID, channelID)) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(types.ErrInvalidChannelCapability, err.Error()) | ||
} | ||
k.SetNextSequenceSend(ctx, portID, channelID, 1) | ||
k.SetNextSequenceRecv(ctx, portID, channelID, 1) | ||
|
||
return nil | ||
return capKey, nil | ||
} | ||
|
||
// ChanOpenAck is called by the handshake-originating module to acknowledge the | ||
// acceptance of the initial request by the counterparty module on the other chain. | ||
func (k Keeper) ChanOpenAck( | ||
ctx sdk.Context, | ||
portID, | ||
channelID, | ||
channelID string, | ||
chanCap capability.Capability, | ||
counterpartyVersion string, | ||
proofTry commitmentexported.Proof, | ||
proofHeight uint64, | ||
|
@@ -169,11 +179,9 @@ func (k Keeper) ChanOpenAck( | |
) | ||
} | ||
|
||
// TODO: blocked by #5542 | ||
// key := sdk.NewKVStoreKey(portID) | ||
// if !k.portKeeper.Authenticate(key, portID) { | ||
// return sdkerrors.Wrap(port.ErrInvalidPort, portID) | ||
// } | ||
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { | ||
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") | ||
} | ||
|
||
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) | ||
if !found { | ||
|
@@ -221,6 +229,7 @@ func (k Keeper) ChanOpenConfirm( | |
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
chanCap capability.Capability, | ||
proofAck commitmentexported.Proof, | ||
proofHeight uint64, | ||
) error { | ||
|
@@ -236,16 +245,9 @@ func (k Keeper) ChanOpenConfirm( | |
) | ||
} | ||
|
||
// TODO: blocked by #5542 | ||
// capkey, found := k.GetChannelCapability(ctx, portID, channelID) | ||
// if !found { | ||
// return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, channelID) | ||
// } | ||
|
||
// key := sdk.NewKVStoreKey(capkey) | ||
// if !k.portKeeper.Authenticate(key, portID) { | ||
// return sdkerrors.Wrap(port.ErrInvalidPort, portID) | ||
// } | ||
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { | ||
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") | ||
} | ||
|
||
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) | ||
if !found { | ||
|
@@ -296,17 +298,11 @@ func (k Keeper) ChanCloseInit( | |
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
chanCap capability.Capability, | ||
) error { | ||
// TODO: blocked by #5542 | ||
// capkey, found := k.GetChannelCapability(ctx, portID, channelID) | ||
// if !found { | ||
// return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, channelID) | ||
// } | ||
|
||
// key := sdk.NewKVStoreKey(capkey) | ||
// if !k.portKeeper.Authenticate(key, portID) { | ||
// return sdkerrors.Wrap(port.ErrInvalidPort, portID) | ||
// } | ||
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { | ||
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") | ||
} | ||
|
||
channel, found := k.GetChannel(ctx, portID, channelID) | ||
if !found { | ||
|
@@ -341,19 +337,13 @@ func (k Keeper) ChanCloseConfirm( | |
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
chanCap capability.Capability, | ||
proofInit commitmentexported.Proof, | ||
proofHeight uint64, | ||
) error { | ||
// TODO: blocked by #5542 | ||
// capkey, found := k.GetChannelCapability(ctx, portID, channelID) | ||
// if !found { | ||
// return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, channelID) | ||
// } | ||
|
||
// key := sdk.NewKVStoreKey(capkey) | ||
// if !k.portKeeper.Authenticate(key, portID) { | ||
// return sdkerrors.Wrap(port.ErrInvalidPort, portID) | ||
// } | ||
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, ibctypes.ChannelCapabilityPath(portID, channelID)) { | ||
return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel") | ||
} | ||
|
||
channel, found := k.GetChannel(ctx, portID, channelID) | ||
if !found { | ||
|
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.
Not sure what to do with the returned capability here. I see how a module can call the keeper's ChanOpenInit method, claim the returned capability and continue the handshake from there.
However, I don't see how to return the capability to an end user since it's only the same capability if the end user somehow gets the same reference passed to it. For example, I don't see how this would work at all in the current relayer flow since the relayer can't be given the channel capability here and then pass it to the next
ChanOpenAck
msgSeems like enforcing capabilities will disallow bare creation of channels? Instead all channel creation would have to be mediated through the modules themselves which can bind ports and then start the channel handshake amongst themselves with users prompting the modules to move forward on the handshake
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 capability should be passed back to the module which has bound to the port - the module can then call
ClaimCapability
and use the capability to continue the handshake & send packets later on. The relayer can send the actual transactions; that's fine - the module just needs to claim the capability and fetch it (under some new name) when required.