-
Notifications
You must be signed in to change notification settings - Fork 637
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
Add host cli to generate ica packet data #2297
Changes from 8 commits
22d9e1b
3ecdc1d
1f12260
fe4880a
4f3ef30
4e6ed4e
47abc0b
96f1f24
e067218
8645a8b
d520833
2a43f5c
c5f7fdd
cf2179f
d477702
5ae13d3
e306637
7411b53
5076fbd
30b7907
8bfbf57
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 |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/version" | ||
"github.com/spf13/cobra" | ||
|
||
icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
const ( | ||
memoFlag string = "memo" | ||
) | ||
|
||
func generatePacketDataCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "generate-packet-data [message]", | ||
Short: "Generates ICA packet data.", | ||
Long: fmt.Sprintf(`generate-packet-data accepts a message string and serializes it | ||
into packet data which is outputted to stdout. It can be used in conjunction with "%s ica controller send-tx" | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
which submits pre-built packet data containing messages to be executed on the host chain. | ||
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. Would it be possible to add an example here? Maybe we can just use the regular bank transfer message used in the example in the ica-demo repo?
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. great suggestions, I'll add this as an example 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. @crodriguezvega I added this example and also a multi message example. 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. Thanks, @chatton! |
||
`, version.AppName), | ||
Args: cobra.ExactArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
clientCtx, err := client.GetClientTxContext(cmd) | ||
if err != nil { | ||
return err | ||
} | ||
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) | ||
memo, err := cmd.Flags().GetString(memoFlag) | ||
if err != nil { | ||
return err | ||
} | ||
packetDataBytes, err := generatePacketData(cdc, []byte(args[0]), memo) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
cmd.Println(string(packetDataBytes)) | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil | ||
}, | ||
} | ||
|
||
cmd.Flags().String(memoFlag, "", "an optional memo to be included in the interchain account packet data") | ||
return cmd | ||
} | ||
|
||
// generatePacketData takes in message bytes and a memo and serializes the message into an | ||
// instance of InterchainAccountPacketData which is returned as bytes. | ||
func generatePacketData(cdc *codec.ProtoCodec, msgBytes []byte, memo string) ([]byte, error) { | ||
var msg sdk.Msg | ||
if err := cdc.UnmarshalInterfaceJSON(msgBytes, &msg); err != nil { | ||
return nil, err | ||
} | ||
|
||
icaPacketDataBytes, err := icatypes.SerializeCosmosTx(cdc, []sdk.Msg{msg}) | ||
if err != nil { | ||
return nil, err | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
icaPacketData := icatypes.InterchainAccountPacketData{ | ||
Type: icatypes.EXECUTE_TX, | ||
Data: icaPacketDataBytes, | ||
Memo: memo, | ||
} | ||
|
||
if err := icaPacketData.ValidateBasic(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return cdc.MarshalJSON(&icaPacketData) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package cli | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
"github.com/stretchr/testify/require" | ||
|
||
icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
const msgDelegateMessage = `{ | ||
"@type": "/cosmos.staking.v1beta1.MsgDelegate", | ||
"delegator_address": "cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", | ||
"validator_address": "cosmosvaloper1qnk2n4nlkpw9xfqntladh74w6ujtulwnmxnh3k", | ||
"amount": { | ||
"denom": "stake", | ||
"amount": "1000" | ||
} | ||
}` | ||
|
||
const bankSendMessage = `{ | ||
"@type":"/cosmos.bank.v1beta1.MsgSend", | ||
"from_address":"cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", | ||
"to_address":"cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw", | ||
"amount": [ | ||
{ | ||
"denom": "stake", | ||
"amount": "1000" | ||
} | ||
] | ||
}` | ||
|
||
func TestGeneratePacketData(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
memo string | ||
expectedPass bool | ||
message string | ||
registerInterfaceFn func(registry codectypes.InterfaceRegistry) | ||
assertionFn func(msg sdk.Msg) | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}{ | ||
{ | ||
name: "packet data generation succeeds (MsgDelegate)", | ||
memo: "non-empty-memo", | ||
expectedPass: true, | ||
message: msgDelegateMessage, | ||
registerInterfaceFn: stakingtypes.RegisterInterfaces, | ||
assertionFn: func(msg sdk.Msg) { | ||
msgDelegate, ok := msg.(*stakingtypes.MsgDelegate) | ||
require.True(t, ok) | ||
require.Equal(t, "cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", msgDelegate.DelegatorAddress) | ||
require.Equal(t, "cosmosvaloper1qnk2n4nlkpw9xfqntladh74w6ujtulwnmxnh3k", msgDelegate.ValidatorAddress) | ||
require.Equal(t, "stake", msgDelegate.Amount.Denom) | ||
require.Equal(t, uint64(1000), msgDelegate.Amount.Amount.Uint64()) | ||
}, | ||
}, | ||
{ | ||
name: "packet data generation succeeds (MsgSend)", | ||
memo: "non-empty-memo", | ||
expectedPass: true, | ||
message: bankSendMessage, | ||
registerInterfaceFn: banktypes.RegisterInterfaces, | ||
assertionFn: func(msg sdk.Msg) { | ||
bankSendMsg, ok := msg.(*banktypes.MsgSend) | ||
require.True(t, ok) | ||
require.Equal(t, "cosmos15ccshhmp0gsx29qpqq6g4zmltnnvgmyu9ueuadh9y2nc5zj0szls5gtddz", bankSendMsg.FromAddress) | ||
require.Equal(t, "cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw", bankSendMsg.ToAddress) | ||
require.Equal(t, "stake", bankSendMsg.Amount.GetDenomByIndex(0)) | ||
require.Equal(t, uint64(1000), bankSendMsg.Amount[0].Amount.Uint64()) | ||
}, | ||
}, | ||
{ | ||
name: "empty memo is valid", | ||
memo: "", | ||
expectedPass: true, | ||
message: msgDelegateMessage, | ||
registerInterfaceFn: stakingtypes.RegisterInterfaces, | ||
assertionFn: func(msg sdk.Msg) {}, | ||
}, | ||
{ | ||
name: "invalid message string", | ||
expectedPass: false, | ||
message: "<invalid-message-body>", | ||
registerInterfaceFn: func(codectypes.InterfaceRegistry) {}, | ||
assertionFn: func(sdk.Msg) {}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tt := tt | ||
ir := codectypes.NewInterfaceRegistry() | ||
tt.registerInterfaceFn(ir) | ||
|
||
cdc := codec.NewProtoCodec(ir) | ||
t.Run(tt.name, func(t *testing.T) { | ||
bz, err := generatePacketData(cdc, []byte(tt.message), tt.memo) | ||
if !tt.expectedPass { | ||
require.Error(t, err) | ||
require.Nil(t, bz) | ||
return | ||
} | ||
require.NoError(t, err) | ||
require.NotNil(t, bz) | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
packetData := icatypes.InterchainAccountPacketData{} | ||
err = cdc.UnmarshalJSON(bz, &packetData) | ||
require.NoError(t, err) | ||
|
||
require.NoError(t, err) | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
require.Equal(t, icatypes.EXECUTE_TX, packetData.Type) | ||
require.Equal(t, tt.memo, packetData.Memo) | ||
|
||
data := packetData.Data | ||
messages, err := icatypes.DeserializeCosmosTx(cdc, data) | ||
|
||
require.NoError(t, err) | ||
require.NotNil(t, messages) | ||
|
||
tt.assertionFn(messages[0]) | ||
}) | ||
} | ||
} |
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.
See this PR.