Skip to content

Commit

Permalink
feat: add channel halt feature from the permissioned relayers (#256)
Browse files Browse the repository at this point in the history
* add channel halt feature from the permissioned relayers

* fix linter
  • Loading branch information
beer-1 authored Aug 27, 2024
1 parent af972b4 commit 2f96ebe
Show file tree
Hide file tree
Showing 31 changed files with 2,122 additions and 864 deletions.
10 changes: 0 additions & 10 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,7 @@ linters:
- thelper
- varnamelen
- tagliatelle
- interfacer
- wrapcheck
- deadcode
- exhaustivestruct
- golint
- ifshort
- maligned
- nosnakecase
- scopelint
- structcheck
- varcheck
linters-settings:
gocyclo:
min-complexity: 11
Expand Down
2 changes: 1 addition & 1 deletion app/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func appModules(
ica.NewAppModule(app.ICAControllerKeeper, app.ICAHostKeeper),
icaauth.NewAppModule(app.appCodec, *app.ICAAuthKeeper),
ibcfee.NewAppModule(*app.IBCFeeKeeper),
ibcperm.NewAppModule(*app.IBCPermKeeper),
ibcperm.NewAppModule(app.appCodec, *app.IBCPermKeeper),
ibctm.NewAppModule(),
solomachine.NewAppModule(),
packetforward.NewAppModule(app.PacketForwardKeeper, nil),
Expand Down
6 changes: 4 additions & 2 deletions proto/ibc/applications/perm/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ option go_package = "github.com/initia-labs/initia/x/ibc/perm/types";

// GenesisState defines the ibc perm genesis state
message GenesisState {
repeated PermissionedRelayers permissioned_relayers = 1
[(gogoproto.moretags) = "yaml:\"permissioned_relayers\"", (gogoproto.nullable) = false];
repeated ChannelState channel_states = 1 [
(gogoproto.moretags) = "yaml:\"channel_states\"",
(gogoproto.nullable) = false
];
}
55 changes: 25 additions & 30 deletions proto/ibc/applications/perm/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,48 @@ syntax = "proto3";

package ibc.applications.perm.v1;

import "cosmos/base/query/v1beta1/pagination.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/applications/perm/v1/types.proto";

option go_package = "github.com/initia-labs/initia/x/ibc/perm/types";

// Query provides defines the gRPC querier service.
service Query {
// PermissionedRelayersByChannel queries a set of permissioned ibc relayers for the specific channel.
rpc PermissionedRelayersByChannel(QueryPermissionedRelayersByChannelRequest)
returns (QueryPermissionedRelayersByChannelResponse) {
option (google.api.http).get = "/ibc/apps/perm/v1/relayers/{port_id}/{channel_id}";
// ChannelStates queries all channel states.
rpc ChannelStates(QueryChannelStatesRequest) returns (QueryChannelStatesResponse) {
option (google.api.http).get = "/ibc/apps/perm/v1/channel_states";
}

// AllPermissionedRelayers queries all sets of permissioned relayers for all channels.
rpc AllPermissionedRelayers(QueryAllPermissionedRelayersRequest) returns (QueryAllPermissionedRelayersResponse) {
option (google.api.http).get = "/ibc/apps/perm/v1/relayers";
// ChannelState queries the channel state for the specific port-id:channel-id pair.
rpc ChannelState(QueryChannelStateRequest) returns (QueryChannelStateResponse) {
option (google.api.http).get = "/ibc/apps/perm/v1/channel_states/{channel_id}/{port_id}";
}
}

// QueryPermissionedRelayersOfOneChannelRequest is the request type for the Query/PermissionedRelayer RPC
// method
message QueryPermissionedRelayersByChannelRequest {
string port_id = 1;
string channel_id = 2;
}

// QueryPermissionedRelayerResponse is the response type for the Query/PermissionedRelayer RPC
// method.
message QueryPermissionedRelayersByChannelResponse {
// class_trace returns the requested class id trace information.
PermissionedRelayers permissioned_relayers = 1;
}

// QueryAllPermissionedRelayersRequest is the request type for the Query/AllPermissionedRelayers RPC
// method
message QueryAllPermissionedRelayersRequest {
// QueryChannelStatesRequest is the request type for the Query/ChannelStates RPC method.
message QueryChannelStatesRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryAllPermissionedRelayersResponse is the response type for the Query/AllPermissionedRelayers RPC
// method.
message QueryAllPermissionedRelayersResponse {
// class_trace returns the requested class id trace information.
repeated PermissionedRelayers permissioned_relayers = 1 [(gogoproto.nullable) = false];
// QueryChannelStatesResponse is the response type for the Query/ChannelStates RPC method.
message QueryChannelStatesResponse {
// channel_states returns all stored ChannelState objects.
repeated ChannelState channel_states = 1 [(gogoproto.nullable) = false];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryChannelStateRequest is the request type for the Query/ChannelState RPC method.
message QueryChannelStateRequest {
string channel_id = 1;
string port_id = 2;
}

// QueryChannelStateResponse is the response type for the Query/ChannelState RPC method.
message QueryChannelStateResponse {
// channel_state returns the stored ChannelState object.
ChannelState channel_state = 1 [(gogoproto.nullable) = false];
}
62 changes: 57 additions & 5 deletions proto/ibc/applications/perm/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "amino/amino.proto";
import "cosmos/msg/v1/msg.proto";
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";

option go_package = "github.com/initia-labs/initia/x/ibc/perm/types";

// Msg defines the ibc/perm Msg service
Expand All @@ -13,24 +14,75 @@ service Msg {

// SetPermissionedRelayers defines a rpc handler method for MsgSetPermissionedRelayers.
rpc SetPermissionedRelayers(MsgSetPermissionedRelayers) returns (MsgSetPermissionedRelayersResponse);

// HaltChannel defines a rpc handler method for MsgHaltChannel.
rpc HaltChannel(MsgHaltChannel) returns (MsgHaltChannelResponse);

// ResumeChannel defines a rpc handler method for MsgResumeChannel.
rpc ResumeChannel(MsgResumeChannel) returns (MsgResumeChannelResponse);
}

// MsgSetPermissionedRelayers defines msg to set permissioned relyer for
// the specific ibc channel.
message MsgSetPermissionedRelayers {
option (cosmos.msg.v1.signer) = "authority";
option (amino.name) = "perm/MsgSetPermissionedRelayers";
option (amino.name) = "perm/MsgSetPermissionedRelayers";

option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// authority is the address that controls the module
// (defaults to x/gov unless overwritten).
string authority = 1 [(gogoproto.moretags) = "yaml:\"authority\"", (cosmos_proto.scalar) = "cosmos.AddressString"];
string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string authority = 1 [
(gogoproto.moretags) = "yaml:\"authority\"",
(cosmos_proto.scalar) = "cosmos.AddressString"
];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string port_id = 3 [(gogoproto.moretags) = "yaml:\"port_id\""];
repeated string relayers = 4 [(gogoproto.moretags) = "yaml:\"relayers\""];
}

// MsgSetPermissionedRelayersResponse defines the Msg/SetPermissionedRelayer response type.
message MsgSetPermissionedRelayersResponse {}

// MsgHaltChannel defines msg to halt the specific ibc channel.
message MsgHaltChannel {
option (cosmos.msg.v1.signer) = "authority";
option (amino.name) = "perm/MsgHaltChannel";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// authority is the address that controls the module
// (defaults to x/gov unless overwritten).
string authority = 1 [
(gogoproto.moretags) = "yaml:\"authority\"",
(cosmos_proto.scalar) = "cosmos.AddressString"
];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string port_id = 3 [(gogoproto.moretags) = "yaml:\"port_id\""];
}

// MsgHaltChannelResponse defines the Msg/HaltChannel response type.
message MsgHaltChannelResponse {}

// MsgResumeChannel defines msg to resume the specific ibc channel.
message MsgResumeChannel {
option (cosmos.msg.v1.signer) = "authority";
option (amino.name) = "perm/MsgResumeChannel";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// authority is the address that controls the module
// (defaults to x/gov unless overwritten).
string authority = 1 [
(gogoproto.moretags) = "yaml:\"authority\"",
(cosmos_proto.scalar) = "cosmos.AddressString"
];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string port_id = 3 [(gogoproto.moretags) = "yaml:\"port_id\""];
}

// MsgResumeChannelResponse defines the Msg/ResumeChannel response type.
message MsgResumeChannelResponse {}
24 changes: 13 additions & 11 deletions proto/ibc/applications/perm/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ syntax = "proto3";

package ibc.applications.perm.v1;

import "gogoproto/gogo.proto";

option go_package = "github.com/initia-labs/initia/x/ibc/perm/types";

// PermissionedRelayer is used to specifiy the permissioned relayer for
// the specific port-id:channel-id pair.
message PermissionedRelayers {
string port_id = 1;
string channel_id = 2;
repeated string relayers = 3;
// ChannelState defines the channel state for the specific port-id:channel-id pair.
message ChannelState {
string port_id = 1;
string channel_id = 2;
HaltState halt_state = 3 [(gogoproto.nullable) = false];
repeated string relayers = 4;
}

// PermissionedRelayersList is used to specify the list of permissioned relayers
// for the specific port-id:channel-id pair.
message PermissionedRelayersList {
repeated string relayers = 1;
}
// HaltState defines the halt state for the specific port-id:channel-id pair.
message HaltState {
bool halted = 1;
string halted_by = 2;
}
2 changes: 1 addition & 1 deletion x/evidence/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (k Querier) Evidence(c context.Context, req *types.QueryEvidenceRequest) (*

evidenceAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
return nil, status.Error(codes.Internal, err.Error())
}

return &types.QueryEvidenceResponse{Evidence: evidenceAny}, nil
Expand Down
4 changes: 2 additions & 2 deletions x/gov/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (k Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, metadata
return customtypes.Proposal{}, err
}

return customtypes.Proposal{}, errorsmod.Wrapf(types.ErrInvalidSigner, signerStr)
return customtypes.Proposal{}, errorsmod.Wrap(types.ErrInvalidSigner, signerStr)
}

// use the msg service router to see that there is a valid route for that message.
Expand All @@ -85,7 +85,7 @@ func (k Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, metadata
if msg, ok := msg.(*v1.MsgExecLegacyContent); ok {
cacheCtx, _ := sdkCtx.CacheContext()
if _, err := handler(cacheCtx, msg); err != nil {
if errors.Is(types.ErrNoProposalHandlerExists, err) {
if errors.Is(err, types.ErrNoProposalHandlerExists) {
return customtypes.Proposal{}, err
}
return customtypes.Proposal{}, errorsmod.Wrap(types.ErrInvalidProposalContent, err.Error())
Expand Down
29 changes: 9 additions & 20 deletions x/ibc/perm/ibc_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,27 +155,16 @@ func (im IBCMiddleware) OnRecvPacket(
packet channeltypes.Packet,
relayer sdk.AccAddress,
) ibcexported.Acknowledgement {
if ok, err := im.keeper.HasPermission(ctx, packet.DestinationPort, packet.DestinationChannel, relayer); err != nil {
if ok, err := im.keeper.IsHalted(ctx, packet.DestinationPort, packet.DestinationChannel); err != nil {
return newEmitErrorAcknowledgement(ctx, err)
} else if !ok {
/*
Raise a panic to prevent abnormal relayers from disrupting operations by
continuously sending error acknowledgements. For instance, abnormal relaying
can interfere with oracle price fetching.
return newEmitErrorAcknowledgement(
ctx,
fmt.Errorf(
"all packets of the channel `%s` should be relayed by the relayer `%s`",
packet.DestinationChannel,
permissionedRelayer,
),
)
*/
panic(fmt.Errorf(
"all packets of the channel `%s` should be relayed by the permissioned relayers",
packet.DestinationChannel,
))
} else if ok {
return newEmitErrorAcknowledgement(
ctx,
fmt.Errorf(
"channel `%s` is halted, no packets should be relayed",
packet.DestinationChannel,
),
)
}

return im.app.OnRecvPacket(ctx, packet, relayer)
Expand Down
26 changes: 8 additions & 18 deletions x/ibc/perm/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,34 @@
package keeper

import (
"cosmossdk.io/collections"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/initia-labs/initia/x/ibc/perm/types"
)

// InitGenesis initializes the ibc-perm state.
func (k Keeper) InitGenesis(ctx sdk.Context, genesisState types.GenesisState) {

for _, relayersByChannel := range genesisState.PermissionedRelayers {
var channelRelayers []string
for _, channelRelayer := range relayersByChannel.Relayers {
_, err := k.ac.StringToBytes(channelRelayer)
if err != nil {
panic(err)
}
channelRelayers = append(channelRelayers, channelRelayer)
}
if err := k.PermissionedRelayers.Set(ctx, collections.Join(relayersByChannel.PortId, relayersByChannel.ChannelId), types.PermissionedRelayersList{
Relayers: channelRelayers,
}); err != nil {
for _, channelState := range genesisState.ChannelStates {
err := k.SetChannelState(ctx, channelState)
if err != nil {
panic(err)
}
}
}

// ExportGenesis exports ibc-perm module's channel relayers.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
channelRelayerSets := []types.PermissionedRelayers{}
err := k.IteratePermissionedRelayers(ctx, func(channelRelayer types.PermissionedRelayers) (bool, error) {
channelRelayerSets = append(channelRelayerSets, channelRelayer)
channelStates := []types.ChannelState{}
err := k.IterateChannelStates(ctx, func(channelRelayer types.ChannelState) (bool, error) {
channelStates = append(channelStates, channelRelayer)
return false, nil
})

if err != nil {
panic(err)
}

return &types.GenesisState{
PermissionedRelayers: channelRelayerSets,
ChannelStates: channelStates,
}
}
Loading

0 comments on commit 2f96ebe

Please sign in to comment.