refactor auths broadcast cmd in alignment with #6216 (#6713)

* refactor auths broadcast cmd in alignment with #6216

* add TxResponse proto definition, and related refactoring

* re-run make proto-gen, updating staking.pb.go

* cleanup TxResponse tests to handle nil return values

* properly handle nil Tx value in TxResponse's implementation of UnpackInterfaces

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
Cory 2020-07-17 10:17:21 -07:00 committed by GitHub
parent 5c86ecd1f8
commit 32de79d0aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2168 additions and 720 deletions

View File

@ -16,7 +16,7 @@ import (
// based on the context parameters. The result of the broadcast is parsed into
// an intermediate structure which is logged if the context has a logger
// defined.
func (ctx Context) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
func (ctx Context) BroadcastTx(txBytes []byte) (res *sdk.TxResponse, err error) {
switch ctx.BroadcastMode {
case flags.BroadcastSync:
res, err = ctx.BroadcastTxSync(txBytes)
@ -28,7 +28,7 @@ func (ctx Context) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
res, err = ctx.BroadcastTxCommit(txBytes)
default:
return sdk.TxResponse{}, fmt.Errorf("unsupported return type %s; supported types: sync, async, block", ctx.BroadcastMode)
return nil, fmt.Errorf("unsupported return type %s; supported types: sync, async, block", ctx.BroadcastMode)
}
return res, err
@ -84,16 +84,16 @@ func CheckTendermintError(err error, txBytes []byte) *sdk.TxResponse {
// NOTE: This should ideally not be used as the request may timeout but the tx
// may still be included in a block. Use BroadcastTxAsync or BroadcastTxSync
// instead.
func (ctx Context) BroadcastTxCommit(txBytes []byte) (sdk.TxResponse, error) {
func (ctx Context) BroadcastTxCommit(txBytes []byte) (*sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
res, err := node.BroadcastTxCommit(txBytes)
if err != nil {
if errRes := CheckTendermintError(err, txBytes); errRes != nil {
return *errRes, nil
return errRes, nil
}
return sdk.NewResponseFormatBroadcastTxCommit(res), err
@ -112,15 +112,15 @@ func (ctx Context) BroadcastTxCommit(txBytes []byte) (sdk.TxResponse, error) {
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node
// synchronously (i.e. returns after CheckTx execution).
func (ctx Context) BroadcastTxSync(txBytes []byte) (sdk.TxResponse, error) {
func (ctx Context) BroadcastTxSync(txBytes []byte) (*sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
res, err := node.BroadcastTxSync(txBytes)
if errRes := CheckTendermintError(err, txBytes); errRes != nil {
return *errRes, nil
return errRes, nil
}
return sdk.NewResponseFormatBroadcastTx(res), err
@ -128,15 +128,15 @@ func (ctx Context) BroadcastTxSync(txBytes []byte) (sdk.TxResponse, error) {
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
// asynchronously (i.e. returns immediately).
func (ctx Context) BroadcastTxAsync(txBytes []byte) (sdk.TxResponse, error) {
func (ctx Context) BroadcastTxAsync(txBytes []byte) (*sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
res, err := node.BroadcastTxAsync(txBytes)
if errRes := CheckTendermintError(err, txBytes); errRes != nil {
return *errRes, nil
return errRes, nil
}
return sdk.NewResponseFormatBroadcastTx(res), err

View File

@ -83,6 +83,21 @@ func (any *Any) Pack(x proto.Message) error {
return nil
}
// UnsafePackAny packs the value x in the Any and instead of returning the error
// in the case of a packing failure, keeps the cached value. This should only
// be used in situations where compatibility is needed with amino. Amino-only
// values can safely be packed using this method when they will only be
// marshaled with amino and not protobuf
func UnsafePackAny(x interface{}) *Any {
if msg, ok := x.(proto.Message); ok {
any, err := NewAnyWithValue(msg)
if err != nil {
return any
}
}
return &Any{cachedValue: x}
}
// GetCachedValue returns the cached value from the Any if present
func (any *Any) GetCachedValue() interface{} {
return any.cachedValue

View File

@ -3,6 +3,7 @@ package cosmos;
import "gogoproto/gogo.proto";
import "tendermint/abci/types/types.proto";
import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types";
option (gogoproto.goproto_stringer_all) = false;
@ -94,3 +95,50 @@ message TxData {
repeated MsgData data = 1;
}
// TxResponse defines a structure containing relevant tx data and metadata. The
// tags are stringified and the log is JSON decoded.
message TxResponse {
option (gogoproto.goproto_getters) = false;
int64 height = 1;
string txhash = 2 [(gogoproto.customname) = "TxHash"];
string codespace = 3;
uint32 code = 4;
string data = 5;
string raw_log = 6;
repeated ABCIMessageLog logs = 7 [(gogoproto.castrepeated) = "ABCIMessageLogs", (gogoproto.nullable) = false];
string info = 8;
int64 gas_wanted = 9;
int64 gas_used = 10;
google.protobuf.Any tx = 11;
string timestamp = 12;
}
// ABCIMessageLog defines a structure containing an indexed tx ABCI message log.
message ABCIMessageLog {
option (gogoproto.stringer) = true;
uint32 msg_index = 1;
string log = 2;
// Events contains a slice of Event objects that were emitted during some
// execution.
repeated StringEvent events = 3 [(gogoproto.castrepeated) = "StringEvents", (gogoproto.nullable) = false];
}
// StringAttribute defines en Event object wrapper where all the attributes
// contain key/value pairs that are strings instead of raw bytes.
message StringEvent {
option (gogoproto.stringer) = true;
string type = 1;
repeated Attribute attributes = 2 [(gogoproto.nullable) = false];
}
// Attribute defines an attribute wrapper where the key and value are
// strings instead of raw bytes.
message Attribute {
string key = 1;
string value = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
yaml "gopkg.in/yaml.v2"
"github.com/cosmos/cosmos-sdk/codec"
)
// create a decimal from a decimal string (ex. "1234.5678")
@ -271,8 +269,6 @@ func TestTruncate(t *testing.T) {
}
}
var cdc = codec.New()
func TestDecMarshalJSON(t *testing.T) {
decimal := func(i int64) Dec {
d := NewDec(0)

View File

@ -48,13 +48,6 @@ type (
// Event is a type alias for an ABCI Event
Event abci.Event
// Attribute defines an attribute wrapper where the key and value are
// strings instead of raw bytes.
Attribute struct {
Key string `json:"key"`
Value string `json:"value,omitempty"`
}
// Events defines a slice of Event objects
Events []Event
)
@ -141,13 +134,6 @@ var (
)
type (
// StringAttribute defines en Event object wrapper where all the attributes
// contain key/value pairs that are strings instead of raw bytes.
StringEvent struct {
Type string `json:"type,omitempty"`
Attributes []Attribute `json:"attributes,omitempty"`
}
// StringAttributes defines a slice of StringEvents objects.
StringEvents []StringEvent
)

View File

@ -11,10 +11,12 @@ import (
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
)
var cdc = codec.New()
func (gi GasInfo) String() string {
bz, _ := yaml.Marshal(gi)
return string(bz)
@ -37,19 +39,9 @@ func (r Result) GetEvents() Events {
// ABCIMessageLogs represents a slice of ABCIMessageLog.
type ABCIMessageLogs []ABCIMessageLog
// ABCIMessageLog defines a structure containing an indexed tx ABCI message log.
type ABCIMessageLog struct {
MsgIndex uint16 `json:"msg_index"`
Log string `json:"log"`
// Events contains a slice of Event objects that were emitted during some
// execution.
Events StringEvents `json:"events"`
}
func NewABCIMessageLog(i uint16, log string, events Events) ABCIMessageLog {
return ABCIMessageLog{
MsgIndex: i,
MsgIndex: uint32(i),
Log: log,
Events: StringifyEvents(events.ToABCIEvents()),
}
@ -58,7 +50,7 @@ func NewABCIMessageLog(i uint16, log string, events Events) ABCIMessageLog {
// String implements the fmt.Stringer interface for the ABCIMessageLogs type.
func (logs ABCIMessageLogs) String() (str string) {
if logs != nil {
raw, err := legacy.Cdc.MarshalJSON(logs)
raw, err := cdc.MarshalJSON(logs)
if err == nil {
str = string(raw)
}
@ -67,32 +59,15 @@ func (logs ABCIMessageLogs) String() (str string) {
return str
}
// TxResponse defines a structure containing relevant tx data and metadata. The
// tags are stringified and the log is JSON decoded.
type TxResponse struct {
Height int64 `json:"height"`
TxHash string `json:"txhash"`
Codespace string `json:"codespace,omitempty"`
Code uint32 `json:"code,omitempty"`
Data string `json:"data,omitempty"`
RawLog string `json:"raw_log,omitempty"`
Logs ABCIMessageLogs `json:"logs,omitempty"`
Info string `json:"info,omitempty"`
GasWanted int64 `json:"gas_wanted,omitempty"`
GasUsed int64 `json:"gas_used,omitempty"`
Tx Tx `json:"tx,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
}
// NewResponseResultTx returns a TxResponse given a ResultTx from tendermint
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxResponse {
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) *TxResponse {
if res == nil {
return TxResponse{}
return nil
}
parsedLogs, _ := ParseABCILogs(res.TxResult.Log)
return TxResponse{
return &TxResponse{
TxHash: res.Hash.String(),
Height: res.Height,
Codespace: res.TxResult.Codespace,
@ -103,16 +78,16 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxRespon
Info: res.TxResult.Info,
GasWanted: res.TxResult.GasWanted,
GasUsed: res.TxResult.GasUsed,
Tx: tx,
Tx: types.UnsafePackAny(tx),
Timestamp: timestamp,
}
}
// NewResponseFormatBroadcastTxCommit returns a TxResponse given a
// ResultBroadcastTxCommit from tendermint.
func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxResponse {
func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) *TxResponse {
if res == nil {
return TxResponse{}
return nil
}
if !res.CheckTx.IsOK() {
@ -122,9 +97,9 @@ func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxR
return newTxResponseDeliverTx(res)
}
func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) *TxResponse {
if res == nil {
return TxResponse{}
return nil
}
var txHash string
@ -134,7 +109,7 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
parsedLogs, _ := ParseABCILogs(res.CheckTx.Log)
return TxResponse{
return &TxResponse{
Height: res.Height,
TxHash: txHash,
Codespace: res.CheckTx.Codespace,
@ -148,9 +123,9 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
}
}
func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) *TxResponse {
if res == nil {
return TxResponse{}
return nil
}
var txHash string
@ -160,7 +135,7 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
parsedLogs, _ := ParseABCILogs(res.DeliverTx.Log)
return TxResponse{
return &TxResponse{
Height: res.Height,
TxHash: txHash,
Codespace: res.DeliverTx.Codespace,
@ -175,14 +150,14 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse {
}
// NewResponseFormatBroadcastTx returns a TxResponse given a ResultBroadcastTx from tendermint
func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse {
func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) *TxResponse {
if res == nil {
return TxResponse{}
return nil
}
parsedLogs, _ := ParseABCILogs(res.Log)
return TxResponse{
return &TxResponse{
Code: res.Code,
Codespace: res.Codespace,
Data: res.Data.String(),
@ -240,15 +215,15 @@ func (r TxResponse) Empty() bool {
// SearchTxsResult defines a structure for querying txs pageable
type SearchTxsResult struct {
TotalCount int `json:"total_count"` // Count of all txs
Count int `json:"count"` // Count of txs in current page
PageNumber int `json:"page_number"` // Index of current page, start from 1
PageTotal int `json:"page_total"` // Count of total pages
Limit int `json:"limit"` // Max count txs per page
Txs []TxResponse `json:"txs"` // List of txs in current page
TotalCount int `json:"total_count"` // Count of all txs
Count int `json:"count"` // Count of txs in current page
PageNumber int `json:"page_number"` // Index of current page, start from 1
PageTotal int `json:"page_total"` // Count of total pages
Limit int `json:"limit"` // Max count txs per page
Txs []*TxResponse `json:"txs"` // List of txs in current page
}
func NewSearchTxsResult(totalCount, count, page, limit int, txs []TxResponse) SearchTxsResult {
func NewSearchTxsResult(totalCount, count, page, limit int, txs []*TxResponse) SearchTxsResult {
return SearchTxsResult{
TotalCount: totalCount,
Count: count,
@ -284,5 +259,17 @@ func (s SearchTxsResult) UnpackInterfaces(unpacker types.AnyUnpacker) error {
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (r TxResponse) UnpackInterfaces(unpacker types.AnyUnpacker) error {
return types.UnpackInterfaces(r.Tx, unpacker)
if r.Tx != nil {
var tx Tx
return unpacker.UnpackAny(r.Tx, &tx)
}
return nil
}
// GetTx unpacks the Tx from within a TxResponse and returns it
func (r TxResponse) GetTx() Tx {
if tx, ok := r.Tx.GetCachedValue().(Tx); ok {
return tx
}
return nil
}

View File

@ -10,7 +10,8 @@ import (
"github.com/tendermint/tendermint/libs/bytes"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -22,30 +23,31 @@ func TestParseABCILog(t *testing.T) {
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, res[0].Log, "")
require.Equal(t, res[0].MsgIndex, uint16(1))
require.Equal(t, res[0].MsgIndex, uint32(1))
}
func TestABCIMessageLog(t *testing.T) {
t.Parallel()
cdc := codec.New()
events := sdk.Events{sdk.NewEvent("transfer", sdk.NewAttribute("sender", "foo"))}
msgLog := sdk.NewABCIMessageLog(0, "", events)
msgLogs := sdk.ABCIMessageLogs{msgLog}
bz, err := legacy.Cdc.MarshalJSON(msgLogs)
bz, err := cdc.MarshalJSON(msgLogs)
require.NoError(t, err)
require.Equal(t, string(bz), msgLogs.String())
}
func TestNewSearchTxsResult(t *testing.T) {
t.Parallel()
got := sdk.NewSearchTxsResult(150, 20, 2, 20, []sdk.TxResponse{})
got := sdk.NewSearchTxsResult(150, 20, 2, 20, []*sdk.TxResponse{})
require.Equal(t, sdk.SearchTxsResult{
TotalCount: 150,
Count: 20,
PageNumber: 2,
PageTotal: 8,
Limit: 20,
Txs: []sdk.TxResponse{},
Txs: []*sdk.TxResponse{},
}, got)
}
@ -80,7 +82,7 @@ func TestResponseResultTx(t *testing.T) {
}
logs, err := sdk.ParseABCILogs(`[]`)
require.NoError(t, err)
want := sdk.TxResponse{
want := &sdk.TxResponse{
TxHash: "74657374",
Height: 10,
Codespace: "codespace",
@ -91,12 +93,12 @@ func TestResponseResultTx(t *testing.T) {
Info: "info",
GasWanted: 100,
GasUsed: 90,
Tx: sdk.Tx(nil),
Tx: &types.Any{},
Timestamp: "timestamp",
}
require.Equal(t, want, sdk.NewResponseResultTx(resultTx, sdk.Tx(nil), "timestamp"))
require.Equal(t, sdk.TxResponse{}, sdk.NewResponseResultTx(nil, sdk.Tx(nil), "timestamp"))
require.Equal(t, (*sdk.TxResponse)(nil), sdk.NewResponseResultTx(nil, sdk.Tx(nil), "timestamp"))
require.Equal(t, `Response:
Height: 10
TxHash: 74657374
@ -119,7 +121,7 @@ func TestResponseResultTx(t *testing.T) {
Log: `[]`,
Hash: bytes.HexBytes([]byte("test")),
}
require.Equal(t, sdk.TxResponse{
require.Equal(t, &sdk.TxResponse{
Code: 1,
Codespace: "codespace",
Data: "64617461",
@ -127,12 +129,13 @@ func TestResponseResultTx(t *testing.T) {
Logs: logs,
TxHash: "74657374",
}, sdk.NewResponseFormatBroadcastTx(resultBroadcastTx))
require.Equal(t, sdk.TxResponse{}, sdk.NewResponseFormatBroadcastTx(nil))
require.Equal(t, (*sdk.TxResponse)(nil), sdk.NewResponseFormatBroadcastTx(nil))
}
func TestResponseFormatBroadcastTxCommit(t *testing.T) {
// test nil
require.Equal(t, sdk.TxResponse{}, sdk.NewResponseFormatBroadcastTxCommit(nil))
require.Equal(t, (*sdk.TxResponse)(nil), sdk.NewResponseFormatBroadcastTxCommit(nil))
logs, err := sdk.ParseABCILogs(`[]`)
require.NoError(t, err)
@ -165,7 +168,7 @@ func TestResponseFormatBroadcastTxCommit(t *testing.T) {
},
}
want := sdk.TxResponse{
want := &sdk.TxResponse{
Height: 10,
TxHash: "74657374",
Codespace: "codespace",

View File

@ -74,31 +74,31 @@ func QueryTxsByEvents(clientCtx client.Context, events []string, page, limit int
// QueryTx queries for a single transaction by a hash string in hex format. An
// error is returned if the transaction does not exist or cannot be queried.
func QueryTx(clientCtx client.Context, hashHexStr string) (sdk.TxResponse, error) {
func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, error) {
hash, err := hex.DecodeString(hashHexStr)
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
node, err := clientCtx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
resTx, err := node.Tx(hash, !clientCtx.TrustNode)
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
if !clientCtx.TrustNode {
if err = ValidateTxResult(clientCtx, resTx); err != nil {
return sdk.TxResponse{}, err
return nil, err
}
}
resBlocks, err := getBlocksForTxResults(clientCtx, []*ctypes.ResultTx{resTx})
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
out, err := formatTxResult(clientCtx.Codec, resTx, resBlocks[resTx.Height])
@ -110,9 +110,9 @@ func QueryTx(clientCtx client.Context, hashHexStr string) (sdk.TxResponse, error
}
// formatTxResults parses the indexed txs into a slice of TxResponse objects.
func formatTxResults(cdc *codec.Codec, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]sdk.TxResponse, error) {
func formatTxResults(cdc *codec.Codec, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]*sdk.TxResponse, error) {
var err error
out := make([]sdk.TxResponse, len(resTxs))
out := make([]*sdk.TxResponse, len(resTxs))
for i := range resTxs {
out[i], err = formatTxResult(cdc, resTxs[i], resBlocks[resTxs[i].Height])
if err != nil {
@ -160,10 +160,10 @@ func getBlocksForTxResults(clientCtx client.Context, resTxs []*ctypes.ResultTx)
return resBlocks, nil
}
func formatTxResult(cdc *codec.Codec, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (sdk.TxResponse, error) {
func formatTxResult(cdc *codec.Codec, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (*sdk.TxResponse, error) {
tx, err := parseTx(cdc, resTx.Tx)
if err != nil {
return sdk.TxResponse{}, err
return nil, err
}
return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil

View File

@ -52,7 +52,7 @@ func QueryDepositsByTxQuery(clientCtx client.Context, params types.QueryProposal
var deposits []types.Deposit
for _, info := range searchResult.Txs {
for _, msg := range info.Tx.GetMsgs() {
for _, msg := range info.GetTx().GetMsgs() {
if msg.Type() == types.TypeMsgDeposit {
depMsg := msg.(*types.MsgDeposit)
@ -94,7 +94,7 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot
}
nextTxPage++
for _, info := range searchResult.Txs {
for _, msg := range info.Tx.GetMsgs() {
for _, msg := range info.GetTx().GetMsgs() {
if msg.Type() == types.TypeMsgVote {
voteMsg := msg.(*types.MsgVote)
@ -140,7 +140,7 @@ func QueryVoteByTxQuery(clientCtx client.Context, params types.QueryVoteParams)
return nil, err
}
for _, info := range searchResult.Txs {
for _, msg := range info.Tx.GetMsgs() {
for _, msg := range info.GetTx().GetMsgs() {
// there should only be a single vote under the given conditions
if msg.Type() == types.TypeMsgVote {
voteMsg := msg.(*types.MsgVote)
@ -181,7 +181,7 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa
}
for _, info := range searchResult.Txs {
for _, msg := range info.Tx.GetMsgs() {
for _, msg := range info.GetTx().GetMsgs() {
// there should only be a single deposit under the given conditions
if msg.Type() == types.TypeMsgDeposit {
depMsg := msg.(*types.MsgDeposit)
@ -221,7 +221,7 @@ func QueryProposerByTxQuery(clientCtx client.Context, proposalID uint64) (Propos
}
for _, info := range searchResult.Txs {
for _, msg := range info.Tx.GetMsgs() {
for _, msg := range info.GetTx().GetMsgs() {
// there should only be a single proposal under the given conditions
if msg.Type() == types.TypeMsgSubmitProposal {
subMsg := msg.(*types.MsgSubmitProposal)

File diff suppressed because it is too large Load Diff