diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 4958240b5..65aff3af9 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -36,6 +36,7 @@ var ( addr4 = priv4.PubKey().Address() coins = sdk.Coins{{"foocoin", 10}} halfCoins = sdk.Coins{{"foocoin", 5}} + manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} fee = sdk.StdFee{ sdk.Coins{{"foocoin", 0}}, 0, @@ -73,6 +74,15 @@ var ( bank.NewOutput(addr1, coins), }, } + + sendMsg5 = bank.SendMsg{ + Inputs: []bank.Input{ + bank.NewInput(addr1, manyCoins), + }, + Outputs: []bank.Output{ + bank.NewOutput(addr2, manyCoins), + }, + } ) func loggerAndDBs() (log.Logger, map[string]dbm.DB) { @@ -131,6 +141,48 @@ func TestMsgs(t *testing.T) { } } +func TestSortGenesis(t *testing.T) { + logger, dbs := loggerAndDBs() + bapp := NewBasecoinApp(logger, dbs) + + // Note the order: the coins are unsorted! + coinDenom1, coinDenom2 := "foocoin", "barcoin" + + genState := fmt.Sprintf(`{ + "accounts": [{ + "address": "%s", + "coins": [ + { + "denom": "%s", + "amount": 10 + }, + { + "denom": "%s", + "amount": 20 + } + ] + }] + }`, addr1.String(), coinDenom1, coinDenom2) + + // Initialize the chain + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)}) + bapp.Commit() + + // Unsorted coins means invalid + err := sendMsg5.ValidateBasic() + require.Equal(t, sdk.CodeInvalidCoins, err.ABCICode(), err.ABCILog()) + + // Sort coins, should be valid + sendMsg5.Inputs[0].Coins.Sort() + sendMsg5.Outputs[0].Coins.Sort() + err = sendMsg5.ValidateBasic() + require.Nil(t, err) + + // Ensure we can send + SignCheckDeliver(t, bapp, sendMsg5, []int64{0}, true, priv1) +} + func TestGenesis(t *testing.T) { logger, dbs := loggerAndDBs() bapp := NewBasecoinApp(logger, dbs) diff --git a/examples/basecoin/types/account.go b/examples/basecoin/types/account.go index f34113fc6..35b37c7b2 100644 --- a/examples/basecoin/types/account.go +++ b/examples/basecoin/types/account.go @@ -55,7 +55,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount { return &GenesisAccount{ Name: aa.Name, Address: aa.Address, - Coins: aa.Coins, + Coins: aa.Coins.Sort(), } } @@ -63,7 +63,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount { func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) { baseAcc := auth.BaseAccount{ Address: ga.Address, - Coins: ga.Coins, + Coins: ga.Coins.Sort(), } return &AppAccount{ BaseAccount: baseAcc, diff --git a/examples/democoin/types/account.go b/examples/democoin/types/account.go index f34113fc6..35b37c7b2 100644 --- a/examples/democoin/types/account.go +++ b/examples/democoin/types/account.go @@ -55,7 +55,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount { return &GenesisAccount{ Name: aa.Name, Address: aa.Address, - Coins: aa.Coins, + Coins: aa.Coins.Sort(), } } @@ -63,7 +63,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount { func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) { baseAcc := auth.BaseAccount{ Address: ga.Address, - Coins: ga.Coins, + Coins: ga.Coins.Sort(), } return &AppAccount{ BaseAccount: baseAcc, diff --git a/types/coin.go b/types/coin.go index d19d4d854..ab7d863c1 100644 --- a/types/coin.go +++ b/types/coin.go @@ -257,7 +257,10 @@ func (coins Coins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i] var _ sort.Interface = Coins{} // Sort is a helper function to sort the set of coins inplace -func (coins Coins) Sort() { sort.Sort(coins) } +func (coins Coins) Sort() Coins { + sort.Sort(coins) + return coins +} //---------------------------------------- // Parsing