Skip to content

Commit

Permalink
Add CLI commands for sanction Tx gov props (#510)
Browse files Browse the repository at this point in the history
  • Loading branch information
SpicyLemon committed Feb 16, 2023
1 parent 18f2234 commit b1248e3
Show file tree
Hide file tree
Showing 9 changed files with 832 additions and 39 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Unreleased

* nothing
### Features

* [#510](https://github.com/provenance-io/cosmos-sdk/pull/510) Add Sanction Tx commands.

---

Expand Down
1 change: 1 addition & 0 deletions client/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const (
FlagReverse = "reverse"
FlagTip = "tip"
FlagAux = "aux"
FlagAuthority = "authority"

// Tendermint logging flags
FlagLogLevel = "log_level"
Expand Down
30 changes: 30 additions & 0 deletions x/gov/client/cli/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"github.com/spf13/pflag"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
govutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
Expand Down Expand Up @@ -148,3 +150,31 @@ func ReadGovPropFlags(clientCtx client.Context, flagSet *pflag.FlagSet) (*govv1.

return rv, nil
}

// GenerateOrBroadcastTxCLIAsGovProp wraps the provided msgs in a governance proposal
// and calls GenerateOrBroadcastTxCLI for that proposal.
// At least one msg is required.
// This uses flags added by AddGovPropFlagsToCmd to fill in the rest of the proposal.
func GenerateOrBroadcastTxCLIAsGovProp(clientCtx client.Context, flagSet *pflag.FlagSet, msgs ...sdk.Msg) error {
if len(msgs) == 0 {
return fmt.Errorf("no messages to submit")
}

prop, err := ReadGovPropFlags(clientCtx, flagSet)
if err != nil {
return err
}

prop.Messages = make([]*codectypes.Any, len(msgs))
for i, msg := range msgs {
prop.Messages[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
if len(msgs) == 1 {
return fmt.Errorf("could not wrap %T message as Any: %w", msg, err)
}
return fmt.Errorf("could not wrap message %d (%T) as Any: %w", i, msg, err)
}
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, flagSet, prop)
}
153 changes: 153 additions & 0 deletions x/gov/client/cli/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package cli

import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"os"
"runtime/debug"
"strings"
"testing"

Expand All @@ -14,6 +16,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil"
Expand All @@ -25,6 +28,23 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// convertPanicToErrorWithStack runs the provided runner.
// If it neither panics nor returns an error, nil is returned.
// If it returns an error, that error is returned.
// If it panics, an error with the panic message and stack trace is returned.
func convertPanicToErrorWithStack(runner func() error) (err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
err = fmt.Errorf("%w\n%s", e, string(debug.Stack()))
} else {
err = fmt.Errorf("%#v%s", r, string(debug.Stack()))
}
}
}()
return runner()
}

func TestParseSubmitLegacyProposalFlags(t *testing.T) {
okJSON := testutil.WriteToNewTempFile(t, `
{
Expand Down Expand Up @@ -461,3 +481,136 @@ func TestReadGovPropFlags(t *testing.T) {
})
}
}

func TestGenerateOrBroadcastTxCLIAsGovProp(t *testing.T) {
fromAddr := sdk.AccAddress("another_from_address")
argDeposit := "--" + FlagDeposit

tests := []struct {
name string
args []string
msgs []sdk.Msg
expErr []string
}{
{
name: "control",
args: []string{argDeposit, "30goodcoin"},
msgs: []sdk.Msg{
&stakingtypes.MsgDelegate{
DelegatorAddress: fromAddr.String(),
ValidatorAddress: sdk.ValAddress("1_validator_address_").String(),
Amount: sdk.NewInt64Coin("blargh", 42),
},
&stakingtypes.MsgDelegate{
DelegatorAddress: fromAddr.String(),
ValidatorAddress: sdk.ValAddress("2_validator_address_").String(),
Amount: sdk.NewInt64Coin("hgralb", 24),
},
},
// I don't care to test what happens in GenerateOrBroadcastTxCLI,
// which is the last thing called in GenerateOrBroadcastTxCLIAsGovProp.
// And setting it up so that GenerateOrBroadcastTxCLI has everything needed
// to not give an error is a major pain.
// But, I can test that execution got to that point by checking for
// a standard thing in the panic/error/stack.
expErr: []string{
".GenerateOrBroadcastTxCLI(",
".GenerateOrBroadcastTxWithFactory(",
".Factory.Prepare(",
"runtime error: invalid memory address or nil pointer dereference",
},
},
{
name: "no messages",
args: []string{argDeposit, "30emptycoin"},
msgs: nil,
expErr: []string{"no messages to submit"},
},
{
name: "read gov prop flags fails",
args: []string{argDeposit, "notcoins"},
msgs: []sdk.Msg{
&stakingtypes.MsgDelegate{
DelegatorAddress: fromAddr.String(),
ValidatorAddress: sdk.ValAddress("3_validator_address_").String(),
Amount: sdk.NewInt64Coin("gogogo", 99),
},
},
expErr: []string{"invalid deposit", "invalid decimal coin expression", "notcoins"},
},
{
name: "one message nil",
args: []string{argDeposit, "30nilcoin"},
msgs: []sdk.Msg{nil},
expErr: []string{"could not wrap <nil> message as Any", "Expecting non nil value to create a new Any"},
},
{
name: "two messages first nil",
args: []string{argDeposit, "32onecoin"},
msgs: []sdk.Msg{
nil,
&stakingtypes.MsgDelegate{
DelegatorAddress: fromAddr.String(),
ValidatorAddress: sdk.ValAddress("4_validator_address_").String(),
Amount: sdk.NewInt64Coin("foundcoin", 200),
},
},
expErr: []string{"could not wrap message 0 (<nil>) as Any", "Expecting non nil value to create a new Any"},
},
{
name: "two messages second nil",
args: []string{argDeposit, "31twocoin"},
msgs: []sdk.Msg{
&stakingtypes.MsgDelegate{
DelegatorAddress: fromAddr.String(),
ValidatorAddress: sdk.ValAddress("5_validator_address_").String(),
Amount: sdk.NewInt64Coin("inccoin", 123),
},
nil,
},
expErr: []string{"could not wrap message 1 (<nil>) as Any", "Expecting non nil value to create a new Any"},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Create a dummy command to get stuff from.
cmd := &cobra.Command{
Short: tc.name,
Run: func(cmd *cobra.Command, args []string) {
t.Errorf("The cmd for %q has run with the args %q, but Run shouldn't have been called.", tc.name, args)
},
}
AddGovPropFlagsToCmd(cmd)
flags.AddTxFlagsToCmd(cmd)

// Use it to parse the provided flags and get the resulting flagSet.
err := cmd.ParseFlags(tc.args)
require.NoError(t, err, "parsing test case args using cmd: %q", tc.args)
flagSet := cmd.Flags()

// Give it a context and then retrieve it.
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &client.Context{}))
clientCtx, err := client.GetClientTxContext(cmd)
require.NoError(t, err, "GetClientTxContext")
// Set the From Address so that the resulting proposal will have a proposer.
clientCtx.FromAddress = fromAddr

// Run the function being tested.
testFunc := func() error {
return GenerateOrBroadcastTxCLIAsGovProp(clientCtx, flagSet, tc.msgs...)
}
err = convertPanicToErrorWithStack(testFunc)

// Make sure the error has what's expected.
if len(tc.expErr) > 0 {
require.Error(t, err, "GenerateOrBroadcastTxCLIAsGovProp error")
for _, exp := range tc.expErr {
assert.ErrorContains(t, err, exp, "GenerateOrBroadcastTxCLIAsGovProp error")
}
} else {
require.NoError(t, err, "GenerateOrBroadcastTxCLIAsGovProp error")
}
})
}
}
Loading

0 comments on commit b1248e3

Please sign in to comment.