diff --git a/app/app.go b/app/app.go index 978ded469..d161e3fcd 100644 --- a/app/app.go +++ b/app/app.go @@ -512,6 +512,7 @@ func NewpStakeApp( icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) var icaControllerStack porttypes.IBCModule = liquidStakeIBCModule + icaControllerStack = ratesync.NewIBCModule(*app.RatesyncKeeper, icaHostStack) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) ibcRouter := porttypes.NewRouter() @@ -519,7 +520,8 @@ func NewpStakeApp( AddRoute(ibctransfertypes.ModuleName, transferStack). AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(liquidstakeibctypes.ModuleName, icaControllerStack) + AddRoute(liquidstakeibctypes.ModuleName, icaControllerStack). + AddRoute(ratesynctypes.ModuleName, icaControllerStack) app.IBCKeeper.SetRouter(ibcRouter) diff --git a/x/liquidstakeibc/keeper/ibc.go b/x/liquidstakeibc/keeper/ibc.go index 8d1f930f1..871c9292f 100644 --- a/x/liquidstakeibc/keeper/ibc.go +++ b/x/liquidstakeibc/keeper/ibc.go @@ -76,7 +76,7 @@ func (k *Keeper) OnChanOpenAck( hc.RewardsAccount.Owner = portOwner hc.RewardsAccount.ChannelState = types.ICAAccount_ICA_CHANNEL_CREATED default: - k.Logger(ctx).Error("Unrecognised ICA account type for the module", "port-id:", portID, "chain-id", chainID) + k.Logger(ctx).Info("Unrecognised ICA account type for the module", "port-id:", portID, "chain-id", chainID) return nil } diff --git a/x/ratesync/keeper/abci.go b/x/ratesync/keeper/abci.go index a49b43b57..09e420f50 100644 --- a/x/ratesync/keeper/abci.go +++ b/x/ratesync/keeper/abci.go @@ -31,7 +31,7 @@ func (k *Keeper) DoRecreateICA(ctx sdk.Context, hc types.HostChain) { } // if the channel is closed, and it is not being recreated, recreate it - portID := types.MustICAPortIDfromOwner(hc.IcaAccount.Owner) + portID := types.MustICAPortIDFromOwner(hc.IcaAccount.Owner) _, isActive := k.icaControllerKeeper.GetOpenActiveChannel(ctx, hc.ConnectionId, portID) if !isActive { if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, hc.ConnectionId, portID, ""); err != nil { diff --git a/x/ratesync/keeper/ibc.go b/x/ratesync/keeper/ibc.go index 3193cd9f2..f3f7d608e 100644 --- a/x/ratesync/keeper/ibc.go +++ b/x/ratesync/keeper/ibc.go @@ -7,7 +7,6 @@ import ( wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -17,19 +16,6 @@ import ( "github.com/persistenceOne/pstake-native/v2/x/ratesync/types" ) -func (k *Keeper) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - return version, nil -} - func (k *Keeper) OnChanOpenAck( ctx sdk.Context, portID string, @@ -49,8 +35,8 @@ func (k *Keeper) OnChanOpenAck( return fmt.Errorf("couldn't find address for %s/%s", connID, portID) } - // get the port owner from the port id - portOwner, err := types.OwnerfromPortID(portID) + // get the port owner from the port id, duplicated check as of ibc-go controller stack + portOwner, err := types.OwnerFromPortID(portID) if err != nil { return fmt.Errorf("unable to parse port id %s, err: %v", portID, err) } @@ -61,14 +47,16 @@ func (k *Keeper) OnChanOpenAck( return fmt.Errorf("unable to get chain id for connection %s: %w", connID, err) } - id, err := types.IDfromPortID(portID) + id, err := types.IDFromPortID(portID) if err != nil { - return err + // Port is not related to this module + return nil } // get host chain hc, found := k.GetHostChain(ctx, id) if !found { - return fmt.Errorf("host chain with id %s is not registered", chainID) + k.Logger(ctx).Info(fmt.Sprintf("host chain with id %s is not registered", id)) + return nil } switch { @@ -114,6 +102,18 @@ func (k *Keeper) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { + + id, err := types.IDFromPortID(packet.SourcePort) + if err != nil { + // Port is not related to this module + return nil + } + // get host chain + hc, found := k.GetHostChain(ctx, id) + if !found { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "host chain with id %s is not present", id) + } + var ack channeltypes.Acknowledgement if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { return errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal packet acknowledgement: %v", err) @@ -125,10 +125,13 @@ func (k *Keeper) OnAcknowledgementPacket( } var icaMemo types.ICAMemo - err := json.Unmarshal([]byte(icaPacket.Memo), &icaMemo) + err = json.Unmarshal([]byte(icaPacket.Memo), &icaMemo) if err != nil { return err } + if hc.Id != icaMemo.HostChainId { + return errorsmod.Wrapf(types.ErrInvalid, "host chain ID should match ID in memo") + } switch resp := ack.Response.(type) { case *channeltypes.Acknowledgement_Error: err := k.handleUnsuccessfulAck(ctx, icaPacket, packet, icaMemo) @@ -175,17 +178,31 @@ func (k *Keeper) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { + + id, err := types.IDFromPortID(packet.SourcePort) + if err != nil { + // Port is not related to this module + return nil + } + // get host chain + hc, found := k.GetHostChain(ctx, id) + if !found { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "host chain with id %s is not present", id) + } var icaPacket icatypes.InterchainAccountPacketData if err := icatypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &icaPacket); err != nil { return errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 tx message data: %v", err) } var icaMemo types.ICAMemo - err := json.Unmarshal([]byte(icaPacket.Memo), &icaMemo) + err = json.Unmarshal([]byte(icaPacket.Memo), &icaMemo) if err != nil { return err } + if hc.Id != icaMemo.HostChainId { + return errorsmod.Wrapf(types.ErrInvalid, "host chain ID should match ID in memo") + } if err := k.handleUnsuccessfulAck(ctx, icaPacket, packet, icaMemo); err != nil { return err } diff --git a/x/ratesync/keeper/msg_server.go b/x/ratesync/keeper/msg_server.go index 8d7437255..19f5ed7c2 100644 --- a/x/ratesync/keeper/msg_server.go +++ b/x/ratesync/keeper/msg_server.go @@ -6,12 +6,12 @@ import ( "fmt" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/gogoproto/proto" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "slices" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" liquidstakeibctypes "github.com/persistenceOne/pstake-native/v2/x/liquidstakeibc/types" "github.com/persistenceOne/pstake-native/v2/x/ratesync/types" @@ -52,7 +52,7 @@ func (k msgServer) CreateHostChain(goCtx context.Context, msg *types.MsgCreateHo if msg.HostChain.IcaAccount.Owner == "" { msg.HostChain.IcaAccount.Owner = types.DefaultPortOwner(id) - } + } // else handled in msg.ValidateBasic() // register ratesyn ICA if msg.HostChain.IcaAccount.ChannelState == liquidstakeibctypes.ICAAccount_ICA_CHANNEL_CREATING { err = k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.HostChain.ConnectionId, msg.HostChain.IcaAccount.Owner, "") @@ -64,16 +64,7 @@ func (k msgServer) CreateHostChain(goCtx context.Context, msg *types.MsgCreateHo err.Error(), ) } - } else { - //check for proper address - addr, found := k.icaControllerKeeper.GetInterchainAccountAddress(ctx, msg.HostChain.ConnectionId, types.MustICAPortIDfromOwner(msg.HostChain.IcaAccount.Owner)) - if !found { - return nil, errorsmod.Wrapf(icatypes.ErrInterchainAccountNotFound, "no address found for given port, expected %s", msg.HostChain.IcaAccount.Address) - } - if addr != msg.HostChain.IcaAccount.Address { - return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "ica address mismatch, expected %s, found %s", msg.HostChain.IcaAccount.Address, addr) - } - } + } // else handled in validate basic (not allowed to create new host chain with previous ICA as portID is default and suffixed by ID k.SetHostChain( ctx, @@ -112,14 +103,11 @@ func (k msgServer) UpdateHostChain(goCtx context.Context, msg *types.MsgUpdateHo // only allow enable disable feature && instantiate. // to change chain-id etc, add delete and create new hostchain with same details - if msg.HostChain.ChainId != oldHC.ChainId { - return nil, errorsmod.Wrapf(types.ErrInvalid, "invalid chainID, chainID cannot be updated, "+ - "chainID mismatch got %s, found %s", msg.HostChain.ChainId, oldHC.ChainId) - } if msg.HostChain.ConnectionId != oldHC.ConnectionId { return nil, errorsmod.Wrapf(types.ErrInvalid, "invalid connectionID, connectionID cannot be updated, "+ "connectionID mismatch got %s, found %s", msg.HostChain.ConnectionId, oldHC.ConnectionId) } + if oldHC.IcaAccount.ChannelState != liquidstakeibctypes.ICAAccount_ICA_CHANNEL_CREATED { return nil, errorsmod.Wrapf(types.ErrInvalid, "invalid ICAAccount state, should already be active") } @@ -136,8 +124,21 @@ func (k msgServer) UpdateHostChain(goCtx context.Context, msg *types.MsgUpdateHo saveUpdate := func(updates string) (bool, string) { return true, updates } + + chainID, err := k.GetChainID(ctx, msg.HostChain.ConnectionId) + if err != nil { + return nil, errorsmod.Wrapf(sdkerrors.ErrNotFound, "chain id not found for connection \"%s\": \"%s\"", msg.HostChain.ConnectionId, err) + } + if chainID != msg.HostChain.ChainId { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidChainID, "chain id does not match connection-chainID input \"%s\": found\"%s\"", msg.HostChain.ChainId, chainID) + } + if msg.HostChain.ChainId != oldHC.ChainId { + oldHC.ChainId = msg.HostChain.ChainId + isOneUpdated, updateStr = saveUpdate(fmt.Sprintf("updates host chain chainID %v to %v \n", oldHC.ChainId, msg.HostChain.ChainId)) + } + //allow only one feature update per tx. - if !msg.HostChain.Features.LiquidStakeIBC.Equals(oldHC.Features.LiquidStakeIBC) { + if !isOneUpdated && !msg.HostChain.Features.LiquidStakeIBC.Equals(oldHC.Features.LiquidStakeIBC) { if oldHC.Features.LiquidStakeIBC.Instantiation == types.InstantiationState_INSTANTIATION_NOT_INITIATED { // allow to add details and instantiate or just save if trying to recover. switch msg.HostChain.Features.LiquidStakeIBC.Instantiation { @@ -188,7 +189,7 @@ func (k msgServer) UpdateHostChain(goCtx context.Context, msg *types.MsgUpdateHo } isOneUpdated, updateStr = saveUpdate(fmt.Sprintf("updates LiquidStakeIBC feature from %v to %v \n", oldHC.Features.LiquidStakeIBC, msg.HostChain.Features.LiquidStakeIBC)) } - if isOneUpdated && !msg.HostChain.Features.LiquidStake.Equals(oldHC.Features.LiquidStake) { + if !isOneUpdated && !msg.HostChain.Features.LiquidStake.Equals(oldHC.Features.LiquidStake) { if oldHC.Features.LiquidStake.Instantiation == types.InstantiationState_INSTANTIATION_NOT_INITIATED { // allow to add details and instantiate or just save if trying to recover. switch msg.HostChain.Features.LiquidStake.Instantiation { @@ -239,7 +240,7 @@ func (k msgServer) UpdateHostChain(goCtx context.Context, msg *types.MsgUpdateHo } isOneUpdated, updateStr = saveUpdate(fmt.Sprintf("updates LiquidStake feature from %v to %v", oldHC.Features.LiquidStake, msg.HostChain.Features.LiquidStake)) } - err := oldHC.Features.ValdidateBasic() + err = oldHC.Features.ValdidateBasic() if err != nil { return nil, err } @@ -277,6 +278,24 @@ func (k msgServer) DeleteHostChain(goCtx context.Context, msg *types.MsgDeleteHo return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "id not set") } + // check pending packets, do not allow to delete if packets are pending. + portID := types.MustICAPortIDFromOwner(hc.IcaAccount.Owner) + channelID, ok := k.icaControllerKeeper.GetOpenActiveChannel(ctx, hc.ChainId, portID) + if !ok { + return nil, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "PortID: %s, connectionID: %s", portID, hc.ConnectionId) + } + nextSendSeq, ok := k.ibcKeeper.ChannelKeeper.GetNextSequenceSend(ctx, portID, channelID) + if !ok { + return nil, errorsmod.Wrapf(channeltypes.ErrSequenceSendNotFound, "PortID: %s, channelID: %s", portID, channelID) + } + nextAckSeq, ok := k.ibcKeeper.ChannelKeeper.GetNextSequenceAck(ctx, portID, channelID) + if !ok { + return nil, errorsmod.Wrapf(channeltypes.ErrSequenceAckNotFound, "PortID: %s, channelID: %s", portID, channelID) + } + if nextSendSeq != nextAckSeq { + return nil, errorsmod.Wrapf(channeltypes.ErrPacketSequenceOutOfOrder, "PortID: %s, channelID: %s, NextSendSequence: %v, NextAckSequence: %v", portID, channelID, nextSendSeq, nextAckSeq) + } + k.RemoveHostChain( ctx, msg.Id, diff --git a/x/ratesync/module_ibc.go b/x/ratesync/module_ibc.go index a48a24fde..ace1134cf 100644 --- a/x/ratesync/module_ibc.go +++ b/x/ratesync/module_ibc.go @@ -1,8 +1,6 @@ package ratesync import ( - "errors" - sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -17,12 +15,14 @@ var _ porttypes.IBCModule = &IBCModule{} // IBCModule implements the ICS26 callbacks for the fee middleware given the // fee keeper and the underlying application. type IBCModule struct { - keeper keeper.Keeper + appStack porttypes.IBCModule + keeper keeper.Keeper } -func NewIBCModule(keeper keeper.Keeper) IBCModule { +func NewIBCModule(keeper keeper.Keeper, appStack porttypes.IBCModule) IBCModule { return IBCModule{ - keeper: keeper, + appStack: appStack, + keeper: keeper, } } @@ -36,7 +36,7 @@ func (m IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - return m.keeper.OnChanOpenInit( + return m.appStack.OnChanOpenInit( ctx, order, connectionHops, @@ -55,13 +55,18 @@ func (m IBCModule) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - return m.keeper.OnChanOpenAck( + err := m.keeper.OnChanOpenAck( ctx, portID, channelID, counterpartyChannelID, counterpartyVersion, ) + if err != nil { + return err + } + return m.appStack.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + } func (m IBCModule) OnAcknowledgementPacket( @@ -70,12 +75,16 @@ func (m IBCModule) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - return m.keeper.OnAcknowledgementPacket( + err := m.keeper.OnAcknowledgementPacket( ctx, packet, acknowledgement, relayer, ) + if err != nil { + return err + } + return m.appStack.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } func (m IBCModule) OnTimeoutPacket( @@ -83,11 +92,15 @@ func (m IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - return m.keeper.OnTimeoutPacket( + err := m.keeper.OnTimeoutPacket( ctx, packet, relayer, ) + if err != nil { + return err + } + return m.appStack.OnTimeoutPacket(ctx, packet, relayer) } func (m IBCModule) OnChanOpenTry( @@ -100,21 +113,21 @@ func (m IBCModule) OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) { - return "", nil + return m.appStack.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) } -func (m IBCModule) OnChanOpenConfirm(_ sdk.Context, _, _ string) error { - return nil +func (m IBCModule) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + return m.appStack.OnChanOpenConfirm(ctx, portID, channelID) } -func (m IBCModule) OnChanCloseInit(_ sdk.Context, _, _ string) error { - return nil +func (m IBCModule) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { + return m.appStack.OnChanCloseInit(ctx, portID, channelID) } -func (m IBCModule) OnChanCloseConfirm(_ sdk.Context, _, _ string) error { - return nil +func (m IBCModule) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { + return m.appStack.OnChanCloseConfirm(ctx, portID, channelID) } -func (m IBCModule) OnRecvPacket(_ sdk.Context, _ channeltypes.Packet, _ sdk.AccAddress) ibcexported.Acknowledgement { - return channeltypes.NewErrorAcknowledgement(errors.New("ICA packets can't be received by the auth module")) +func (m IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { + return m.appStack.OnRecvPacket(ctx, packet, relayer) } diff --git a/x/ratesync/types/genesis_test.go b/x/ratesync/types/genesis_test.go index b4f7ba513..fdb1026dc 100644 --- a/x/ratesync/types/genesis_test.go +++ b/x/ratesync/types/genesis_test.go @@ -21,7 +21,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "valid genesis state", genState: &types.GenesisState{ - + Params: types.DefaultParams(), HostChains: []types.HostChain{ { Id: 0, @@ -37,6 +37,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "duplicated chain", genState: &types.GenesisState{ + Params: types.DefaultParams(), HostChains: []types.HostChain{ { Id: 0, diff --git a/x/ratesync/types/msgs.go b/x/ratesync/types/msgs.go index af923fe57..ec1efc5e7 100644 --- a/x/ratesync/types/msgs.go +++ b/x/ratesync/types/msgs.go @@ -4,6 +4,7 @@ import ( "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + liquidstakeibctypes "github.com/persistenceOne/pstake-native/v2/x/liquidstakeibc/types" ) const TypeMsgUpdateParams = "msg_update_params" @@ -98,7 +99,12 @@ func (msg *MsgCreateHostChain) ValidateBasic() error { if msg.HostChain.Id != 0 { return errors.Wrapf(sdkerrors.ErrInvalidRequest, "hostchain ID for create msg should be 0") } - + if msg.HostChain.IcaAccount.Owner != "" { + return errors.Wrapf(sdkerrors.ErrInvalidRequest, "owner should not be specified as app uses default") + } + if msg.HostChain.IcaAccount.ChannelState != liquidstakeibctypes.ICAAccount_ICA_CHANNEL_CREATING { + return errors.Wrapf(sdkerrors.ErrInvalidRequest, "channel state should be creating") + } return nil } diff --git a/x/ratesync/types/msgs_test.go b/x/ratesync/types/msgs_test.go index 2425818aa..1b167cfad 100644 --- a/x/ratesync/types/msgs_test.go +++ b/x/ratesync/types/msgs_test.go @@ -1,6 +1,8 @@ package types import ( + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/persistenceOne/pstake-native/v2/x/liquidstakeibc/types" "testing" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -8,6 +10,21 @@ import ( "github.com/stretchr/testify/require" ) +var ValidHostChainInMsg = HostChain{ + Id: 1, + ChainId: "test-1", + ConnectionId: ibcexported.LocalhostConnectionID, + IcaAccount: types.ICAAccount{}, + Features: Feature{LiquidStakeIBC: LiquidStake{ + FeatureType: 0, + CodeID: 0, + Instantiation: 0, + ContractAddress: "", + Denoms: []string{}, + Enabled: false, + }}, +} + func TestMsgUpdateParams_ValidateBasic(t *testing.T) { tests := []struct { name string @@ -117,6 +134,7 @@ func TestMsgDeleteHostChain_ValidateBasic(t *testing.T) { name: "valid address", msg: MsgDeleteHostChain{ Authority: authtypes.NewModuleAddress("addr1").String(), + Id: 1, }, }, } diff --git a/x/ratesync/types/types.go b/x/ratesync/types/types.go index 86d320cca..1d49ce206 100644 --- a/x/ratesync/types/types.go +++ b/x/ratesync/types/types.go @@ -30,6 +30,11 @@ func (hc HostChain) ValidateBasic() error { if err != nil { return err } + //Make sure it matches default. + _, err = IDFromPortID(portID) + if err != nil { + return err + } } switch hc.IcaAccount.ChannelState { @@ -162,7 +167,7 @@ func (lsConfig LiquidStake) Equals(l2 LiquidStake) bool { return true } -func MustICAPortIDfromOwner(owner string) string { +func MustICAPortIDFromOwner(owner string) string { id, err := icatypes.NewControllerPortID(owner) if err != nil { panic(err) @@ -174,7 +179,7 @@ func MustICAPortIDfromOwner(owner string) string { func DefaultPortOwner(id uint64) string { return fmt.Sprintf("%s%v", DefaultPortOwnerPrefix, id) } -func OwnerfromPortID(portID string) (string, error) { +func OwnerFromPortID(portID string) (string, error) { prefix := fmt.Sprintf("%s", icatypes.ControllerPortPrefix) idStr, found := strings.CutPrefix(portID, prefix) if !found { @@ -184,7 +189,7 @@ func OwnerfromPortID(portID string) (string, error) { return idStr, nil } -func IDfromPortID(portID string) (uint64, error) { +func IDFromPortID(portID string) (uint64, error) { prefix := fmt.Sprintf("%s%s", icatypes.ControllerPortPrefix, DefaultPortOwnerPrefix) idStr, found := strings.CutPrefix(portID, prefix) if !found {