Skip to content

Commit

Permalink
Merge pull request #8444 from cosmos/release/v0.40.x
Browse files Browse the repository at this point in the history
Release v0.41.0
  • Loading branch information
Alessio Treglia committed Jan 26, 2021
2 parents 7cb7a3a + c54025d commit f8a6987
Show file tree
Hide file tree
Showing 17 changed files with 608 additions and 119 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

## [v0.41.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.0) - 2021-01-26

### State Machine Breaking

* (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON for IBC messages in order to support Ledger text signing.
* (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks.

### Bug Fixes

* (simapp) [\#8418](https://github.com/cosmos/cosmos-sdk/pull/8418) Add balance coin to supply when adding a new genesis account
* (x/bank) [\#8417](https://github.com/cosmos/cosmos-sdk/pull/8417) Validate balances and coin denom metadata on genesis

## [v0.40.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.1) - 2021-01-19

### Improvements
Expand Down
45 changes: 15 additions & 30 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,30 @@
# Cosmos SDK v0.40.1 "Stargate" Release Notes
# Cosmos SDK v0.41.0 "Stargate" Release Notes

This is a bug fix release to the *Cosmos SDK 0.40* "Stargate" release series. No breaking changes are introduced, thus no migration should be needed.
Among the various bugfixes, this release introduces important security patches.
This release includes two breaking changes, and a few minor bugfixes.

See the [Cosmos SDK v0.40.1 milestone](https://github.com/cosmos/cosmos-sdk/milestone/36?closed=1) on our issue tracker for details.
See the [Cosmos SDK v0.41.0 milestone](https://github.com/cosmos/cosmos-sdk/milestone/37?closed=1) on our issue tracker for details.

### Gogo protobuf security release
### Support Amino JSON for IBC MsgTransfer

[Gogoprotobuf](https://github.com/gogo/protobuf) released a bugfix addressing [CVE-2021-3121](https://nvd.nist.gov/vuln/detail/CVE-2021-3121). Cosmos SDK respective dependency has been updated and protobuf generated files were regenerated.
This change **breaks state backward compatibility**.

### Tendermint security patches
At the moment hardware wallets are [unable to sign messages using `SIGN_MODE_DIRECT` because the cosmos ledger app does not support proto encoding and`SIGN_MODE_TEXTUAL` is not available yet](https://https://github.com/cosmos/cosmos-sdk/issues/8266).

This release comes with a newer release of Tendermint that, other than fixing various bugs it also addresses a high-severity security vulnerability.
For the comprehensive list of changes introduced by Tendermint since Cosmos SDK v0.40.0, please refer to [Tendermint's v0.34.3 release notes](https://github.com/tendermint/tendermint/blob/v0.34.3/CHANGELOG.md#v0.34.3).
In order to enable hardware wallets users to interact with IBC, amino JSON support was added to `MsgTransfer` only.

### Fix zero time checks
### Counterparty.ChannelID not available in OnChanOpenAck callback implementation.

In Cosmos SDK applications, it is recommended to use `Time.Unix() <= 0` instead of `Time.IsZero()`, which may lead to unexpected results.
See [\#8085](https://github.com/cosmos/cosmos-sdk/pull/8058) for more information.
This change **breaks state backward compatibility**.

### Querying upgrade plans panics when no plan exists
In a previous version the `Counterparty.ChannelID` was available for an `OnChanOpenAck` callback implementation (read via `channelKeeper.GetChannel()`. Due to a regression, the channelID is currently empty.

The `x/upgrade` module command and REST endpoints for querying upgrade plans would panic when no plan existed. This is now resolved.
The issue has been fixed by reordering IBC `ChanOpenAck` and `ChanOpenConfirm` to execute the core handlers logic first, followed by application callbacks.

### Fix account sequence
It breaks state backward compatibility because the current change consumes more gas, which means that in an updated node a TX might fail because it ran out of gas whilst in older versions it would be successful.

In Cosmos SDK v0.40.0 a new structure (`SignatureV2`) for handling message signatures was introduced.
Although the `tx sign --signature-only` command was still capable of generating correct signatures, it was not returning the account's correct sequence number.
### Bug Fixes

### Reproducible builds
Now `x/bank` correctly verifies balances and metadata at init genesis stage.

Our automatic builds were not working correctly due to small gaps in file paths. Fixed in [\8300](https://github.com/cosmos/cosmos-sdk/pull/8300) and [\8301](https://github.com/cosmos/cosmos-sdk/pull/8301).
`simapp` correctly adds the coins of genesis accounts to supply.

### Wrapper errors were not reflective

Cosmos SDK errors typically support the `Is()` method. The `Go` `errors.Is()` function compares an error to a value and should always return `true` when the receiver is passed as an argument to its own method, e.g. `err.Is(err)`. This was not a case for the error types provided by the `types/errors` package.

### Fix latest consensus state

Errors occur when using the client to send IBC transactions without flag `--absolute-timeouts`, e.g:

gaiad tx ibc-transfer transfer

The issue was caused by incorrect interface decoding and unpacking of `Any` values and is now fixed.
1 change: 1 addition & 0 deletions simapp/simd/cmd/genaccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
bankGenState := banktypes.GetGenesisStateFromAppState(depCdc, appState)
bankGenState.Balances = append(bankGenState.Balances, balances)
bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances)
bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...)

bankGenStateBz, err := cdc.MarshalJSON(bankGenState)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions x/auth/client/rest/rest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ func (s *IntegrationTestSuite) TestBroadcastIBCTxRequest() {
res, err := rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", []byte(req))
s.Require().NoError(err)

// Make sure the error message is correct.
s.Require().Contains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints")
s.Require().NotContains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints", string(res))
}

// Helper function to test querying txs. We will use it to query StdTx and service `Msg`s.
Expand Down
2 changes: 1 addition & 1 deletion x/bank/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, _ client.TxEncodi
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}

return types.ValidateGenesis(data)
return data.Validate()
}

// RegisterRESTRoutes registers the REST routes for the bank module.
Expand Down
93 changes: 93 additions & 0 deletions x/bank/types/balance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package types

import (
"bytes"
"encoding/json"
fmt "fmt"
"sort"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/exported"
)

var _ exported.GenesisBalance = (*Balance)(nil)

// GetAddress returns the account address of the Balance object.
func (b Balance) GetAddress() sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(b.Address)
return addr
}

// GetCoins returns the account coins of the Balance object.
func (b Balance) GetCoins() sdk.Coins {
return b.Coins
}

// Validate checks for address and coins correctness.
func (b Balance) Validate() error {
_, err := sdk.AccAddressFromBech32(b.Address)
if err != nil {
return err
}

if len(b.Coins) == 0 {
return fmt.Errorf("empty or nil coins for address %s", b.Address)
}

seenDenoms := make(map[string]bool)

// NOTE: we perform a custom validation since the coins.Validate function
// errors on zero balance coins
for _, coin := range b.Coins {
if seenDenoms[coin.Denom] {
return fmt.Errorf("duplicate denomination %s", coin.Denom)
}

if err := sdk.ValidateDenom(coin.Denom); err != nil {
return err
}

if coin.IsNegative() {
return fmt.Errorf("coin %s amount is cannot be negative", coin.Denom)
}

seenDenoms[coin.Denom] = true
}

// sort the coins post validation
b.Coins = b.Coins.Sort()

return nil
}

// SanitizeGenesisBalances sorts addresses and coin sets.
func SanitizeGenesisBalances(balances []Balance) []Balance {
sort.Slice(balances, func(i, j int) bool {
addr1, _ := sdk.AccAddressFromBech32(balances[i].Address)
addr2, _ := sdk.AccAddressFromBech32(balances[j].Address)
return bytes.Compare(addr1.Bytes(), addr2.Bytes()) < 0
})

for _, balance := range balances {
balance.Coins = balance.Coins.Sort()
}

return balances
}

// GenesisBalancesIterator implements genesis account iteration.
type GenesisBalancesIterator struct{}

// IterateGenesisBalances iterates over all the genesis balances found in
// appGenesis and invokes a callback on each genesis account. If any call
// returns true, iteration stops.
func (GenesisBalancesIterator) IterateGenesisBalances(
cdc codec.JSONMarshaler, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool),
) {
for _, balance := range GetGenesisStateFromAppState(cdc, appState).Balances {
if cb(balance) {
break
}
}
}
80 changes: 80 additions & 0 deletions x/bank/types/balance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package types

import (
"testing"

"github.com/stretchr/testify/require"

sdk "github.com/cosmos/cosmos-sdk/types"
)

func TestBalanceValidate(t *testing.T) {

testCases := []struct {
name string
balance Balance
expErr bool
}{
{
"valid balance",
Balance{
Address: "cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t",
Coins: sdk.Coins{sdk.NewInt64Coin("uatom", 1)},
},
false,
},
{"empty balance", Balance{}, true},
{
"nil balance coins",
Balance{
Address: "cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t",
},
true,
},
{
"dup coins",
Balance{
Address: "cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t",
Coins: sdk.Coins{
sdk.NewInt64Coin("uatom", 1),
sdk.NewInt64Coin("uatom", 1),
},
},
true,
},
{
"invalid coin denom",
Balance{
Address: "cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t",
Coins: sdk.Coins{
sdk.Coin{Denom: "", Amount: sdk.OneInt()},
},
},
true,
},
{
"negative coin",
Balance{
Address: "cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t",
Coins: sdk.Coins{
sdk.Coin{Denom: "uatom", Amount: sdk.NewInt(-1)},
},
},
true,
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {

err := tc.balance.Validate()

if tc.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
74 changes: 28 additions & 46 deletions x/bank/types/genesis.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,49 @@
package types

import (
"bytes"
"encoding/json"
"sort"
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/exported"
)

var _ exported.GenesisBalance = (*Balance)(nil)
// Validate performs basic validation of supply genesis data returning an
// error for any failed validation criteria.
func (gs GenesisState) Validate() error {
if err := gs.Params.Validate(); err != nil {
return err
}

// GetAddress returns the account address of the Balance object.
func (b Balance) GetAddress() sdk.AccAddress {
addr1, _ := sdk.AccAddressFromBech32(b.Address)
return addr1
}
seenBalances := make(map[string]bool)
seenMetadatas := make(map[string]bool)

// GetAddress returns the account coins of the Balance object.
func (b Balance) GetCoins() sdk.Coins {
return b.Coins
}
for _, balance := range gs.Balances {
if seenBalances[balance.Address] {
return fmt.Errorf("duplicate balance for address %s", balance.Address)
}

// SanitizeGenesisAccounts sorts addresses and coin sets.
func SanitizeGenesisBalances(balances []Balance) []Balance {
sort.Slice(balances, func(i, j int) bool {
addr1, _ := sdk.AccAddressFromBech32(balances[i].Address)
addr2, _ := sdk.AccAddressFromBech32(balances[j].Address)
return bytes.Compare(addr1.Bytes(), addr2.Bytes()) < 0
})
if err := balance.Validate(); err != nil {
return err
}

for _, balance := range balances {
balance.Coins = balance.Coins.Sort()
seenBalances[balance.Address] = true
}

return balances
}
for _, metadata := range gs.DenomMetadata {
if seenMetadatas[metadata.Base] {
return fmt.Errorf("duplicate client metadata for denom %s", metadata.Base)
}

// ValidateGenesis performs basic validation of supply genesis data returning an
// error for any failed validation criteria.
func ValidateGenesis(data GenesisState) error {
if err := data.Params.Validate(); err != nil {
return err
if err := metadata.Validate(); err != nil {
return err
}

seenMetadatas[metadata.Base] = true
}

return NewSupply(data.Supply).ValidateBasic()
// NOTE: this errors if supply for any given coin is zero
return NewSupply(gs.Supply).ValidateBasic()
}

// NewGenesisState creates a new genesis state.
Expand Down Expand Up @@ -74,19 +72,3 @@ func GetGenesisStateFromAppState(cdc codec.JSONMarshaler, appState map[string]js

return &genesisState
}

// GenesisAccountIterator implements genesis account iteration.
type GenesisBalancesIterator struct{}

// IterateGenesisAccounts iterates over all the genesis accounts found in
// appGenesis and invokes a callback on each genesis account. If any call
// returns true, iteration stops.
func (GenesisBalancesIterator) IterateGenesisBalances(
cdc codec.JSONMarshaler, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool),
) {
for _, balance := range GetGenesisStateFromAppState(cdc, appState).Balances {
if cb(balance) {
break
}
}
}
Loading

0 comments on commit f8a6987

Please sign in to comment.