/
ibc_module.go
227 lines (201 loc) · 6.78 KB
/
ibc_module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package envoy
import (
"encoding/hex"
"github.com/gogo/protobuf/proto"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
ibcchanneltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
ibcporttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
ibcexported "github.com/cosmos/ibc-go/v6/modules/core/exported"
"github.com/CosmWasm/wasmd/x/wasm"
"github.com/mars-protocol/hub/v2/x/envoy/keeper"
)
// IBCModule implements the ICS26 interface for the envoy module.
type IBCModule struct{ k keeper.Keeper }
// NewIBCModule creates a new IBCModule given the keeper.
func NewIBCModule(k keeper.Keeper) ibcporttypes.IBCModule {
return IBCModule{k}
}
func (im IBCModule) OnChanOpenInit(
_ sdk.Context,
_ ibcchanneltypes.Order,
_ []string,
_ string,
_ string,
_ *capabilitytypes.Capability,
_ ibcchanneltypes.Counterparty,
version string,
) (string, error) {
// the module is supposed to validate the version string here.
// however, the version string is provided by the module's msgServer as an
// empty string. therefore we skip the validation here.
return version, nil
}
func (im IBCModule) OnChanOpenTry(
_ sdk.Context,
_ ibcchanneltypes.Order,
_ []string,
_,
_ string,
_ *capabilitytypes.Capability,
_ ibcchanneltypes.Counterparty,
_ string,
) (string, error) {
// ICA channel handshake cannot be initiated from the host chain.
// the controller middleware should have rejected this request.
// if not, something seriously wrong must have happened, e.g. modules wired
// incorrectly in app.go. we panic in this case.
panic("UNREACHABLE: envoy module OnChanOpenTry")
}
func (im IBCModule) OnChanOpenAck(
_ sdk.Context,
_,
_ string,
_ string,
_ string,
) error {
// counterpartyVersion is already validated by the controller middleware.
// we assume it's valid and don't validate again here.
return nil
}
func (im IBCModule) OnChanOpenConfirm(
_ sdk.Context,
_,
_ string,
) error {
// see the comment in OnChanOpenTry on why we panic here
panic("UNREACHABLE: envoy module OnChanOpenConfirm")
}
func (im IBCModule) OnChanCloseInit(
_ sdk.Context,
_,
_ string,
) error {
return nil
}
func (im IBCModule) OnChanCloseConfirm(
_ sdk.Context,
_,
_ string,
) error {
return nil
}
func (im IBCModule) OnRecvPacket(
_ sdk.Context,
_ ibcchanneltypes.Packet,
_ sdk.AccAddress,
) ibcexported.Acknowledgement {
// the ICA controller does not expect to receive any packet.
// the controller middleware should have rejected this request.
panic("UNREACHABLE: envoy module OnRecvPacket")
}
// OnAcknowledgementPacket parses the acknowledgement and prints log messages.
//
// Although the envoy module can send both ICS-20 and ICS-27 packets, only
// ICS-27 acknowledgements are routed here. ICS-20 packets are handled by the
// ibctransfer module alone.
//
// This function is mostly copied from interchain-account-demo:
// https://github.com/cosmos/interchain-accounts-demo/blob/v0.4.3/x/inter-tx/ibc_module.go#L108
func (im IBCModule) OnAcknowledgementPacket(
ctx sdk.Context,
packet ibcchanneltypes.Packet,
acknowledgement []byte,
_ sdk.AccAddress,
) error {
logger := im.k.Logger(ctx)
logger.Info(
"received ICS-27 packet acknowledgement",
"channel", packet.DestinationChannel,
"sequence", packet.Sequence,
)
var ack ibcchanneltypes.Acknowledgement
if err := ibcchanneltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil {
return sdkerrors.ErrUnknownRequest.Wrapf("cannot unmarshal ICS-27 packet acknowledgement: %v", err)
}
var txMsgData sdk.TxMsgData
if err := proto.Unmarshal(ack.GetResult(), &txMsgData); err != nil {
return sdkerrors.ErrUnknownRequest.Wrapf("cannot unmarshal ICS-27 tx message data: %v", err)
}
switch len(txMsgData.Data) {
// sdk 0.46
case 0:
for _, msgResp := range txMsgData.GetMsgResponses() {
logger.Info(
"message response in ICS-27 packet",
"msgType", msgResp.TypeUrl,
"response", msgResp.GoString(),
)
}
return nil
// sdk 0.45 or below
default:
for _, msgData := range txMsgData.Data {
response, err := handleMsgData(msgData)
if err != nil {
return err
}
logger.Info(
"message response in ICS-27 packet response",
"msgType", msgData.MsgType,
"response", response,
)
}
return nil
}
}
// handleMsgData parses the message response and return a human readable string
// representing the response data, for use in logging.
//
// We can't support every existing message types out there. Instead we only
// support a selected few:
//
// - bank: MsgSend
// - staking: MsgDelegate, MsgUndelegate
// - distribution: MsgWithdrawRewards
// - wasm: MsgExecuteContract, MsgMigrateContract
//
// For the others, we simply return the hex encoded bytes.
func handleMsgData(msgData *sdk.MsgData) (string, error) { //nolint:staticcheck // This function parses data from sdk 0.45 chains, so of course it contains deprecated stuff. Not my problem lol
switch msgData.MsgType {
case sdk.MsgTypeURL(&banktypes.MsgSend{}):
return handleProtoMsg[*banktypes.MsgSendResponse](msgData.Data, "bank/MsgSend")
case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}):
return handleProtoMsg[*stakingtypes.MsgDelegateResponse](msgData.Data, "staking/MsgDelegate")
case sdk.MsgTypeURL(&stakingtypes.MsgUndelegate{}):
return handleProtoMsg[*stakingtypes.MsgUndelegateResponse](msgData.Data, "staking/MsgUndelegate")
case sdk.MsgTypeURL(&distrtypes.MsgWithdrawDelegatorReward{}):
return handleProtoMsg[*distrtypes.MsgWithdrawDelegatorRewardResponse](msgData.Data, "distr/MsgWithdrawDelegatorReward")
case sdk.MsgTypeURL(&wasm.MsgExecuteContract{}):
return handleProtoMsg[*wasm.MsgExecuteContractResponse](msgData.Data, "wasm/MsgExecuteContract")
case sdk.MsgTypeURL(&wasm.MsgMigrateContract{}):
return handleProtoMsg[*wasm.MsgMigrateContractResponse](msgData.Data, "wasm/MsgMigrateContract")
default:
return hex.EncodeToString(msgData.Data), nil
}
}
// handleProtoMsg unmarshals bytes into a given proto message and stringifies it.
func handleProtoMsg[T proto.Message](bz []byte, tyName string) (string, error) {
var msg T
if err := proto.Unmarshal(bz, msg); err != nil {
return "", sdkerrors.ErrJSONUnmarshal.Wrapf("cannot unmarshal %s response: %v", tyName, err)
}
return msg.String(), nil
}
// OnTimeoutPacket prints a log message indicating the packet has timed out.
func (im IBCModule) OnTimeoutPacket(
ctx sdk.Context,
packet ibcchanneltypes.Packet,
_ sdk.AccAddress,
) error {
im.k.Logger(ctx).Info(
"ICS-27 packet timed out",
"channel", packet.DestinationChannel,
"sequence", packet.Sequence,
)
return nil
}