Skip to content

Commit

Permalink
Merge branch 'main' into alex/sims_runner
Browse files Browse the repository at this point in the history
* main:
  fix(x/staking): stop validators from rotating to the same key on the same block (#20649)
  perf: add cache to address codec (#20122)
  build(deps): Bump google.golang.org/protobuf from 1.34.1 to 1.34.2 (#20632)
  fix: remove recipient amount from map (#20625)
  fix(proto): remove conditional preventing proper generated file placement (#20650)
  (serverv2/cometbft) Read config from commands & handle `FlagNode` (#20621)
  fix(x/consensus): fix .proto file placement (#20646)
  fix(store): avoid nil error on not exhausted payload stream (#20644)
  fix (x/accounts): Fix genesis condition check (#20645)
  feat(accounts): add genesis account initialization (#20642)
  fix(x/gov): limit execution in gov (#20348)
  • Loading branch information
alpe committed Jun 13, 2024
2 parents e79d9cf + 43991b9 commit faccd45
Show file tree
Hide file tree
Showing 123 changed files with 1,424 additions and 550 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i

### Improvements

* (codec) [#20122](https://github.com/cosmos/cosmos-sdk/pull/20122) Added a cache to address codec.
* (bank) [#20354](https://github.com/cosmos/cosmos-sdk/pull/20354) Reduce the number of `ValidateDenom` calls in `bank.SendCoins`.
* (types) [#19869](https://github.com/cosmos/cosmos-sdk/pull/19869) Removed `Any` type from `codec/types` and replaced it with an alias for `cosmos/gogoproto/types/any`.
* (server) [#19854](https://github.com/cosmos/cosmos-sdk/pull/19854) Add customizability to start command.
Expand Down
235 changes: 166 additions & 69 deletions api/cosmos/accounts/v1/genesis.pulsar.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/cosmos/circuit/v1/tx_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

211 changes: 137 additions & 74 deletions api/cosmos/gov/v1/gov.pulsar.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/cosmos/gogoproto v1.5.0
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.34.1
google.golang.org/protobuf v1.34.2
)

require (
Expand Down
3 changes: 2 additions & 1 deletion api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
2 changes: 1 addition & 1 deletion client/v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.34.1
google.golang.org/protobuf v1.34.2
gotest.tools/v3 v3.5.1
sigs.k8s.io/yaml v1.4.0
)
Expand Down
3 changes: 2 additions & 1 deletion client/v2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
104 changes: 101 additions & 3 deletions codec/address/bech32_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,78 @@ package address

import (
"errors"
"fmt"
"strings"
"sync"

"github.com/hashicorp/golang-lru/simplelru"

"cosmossdk.io/core/address"
errorsmod "cosmossdk.io/errors"

"github.com/cosmos/cosmos-sdk/internal/conv"
sdkAddress "github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/bech32"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

var errEmptyAddress = errors.New("empty address string is not allowed")

var (
_ address.Codec = &Bech32Codec{}
_ address.Codec = &cachedBech32Codec{}
)

type Bech32Codec struct {
Bech32Prefix string
}

var _ address.Codec = &Bech32Codec{}
type cachedBech32Codec struct {
codec Bech32Codec
mu *sync.Mutex
cache *simplelru.LRU
}

type CachedCodecOptions struct {
Mu *sync.Mutex
Lru *simplelru.LRU
}

func NewBech32Codec(prefix string) address.Codec {
return Bech32Codec{prefix}
return &Bech32Codec{Bech32Prefix: prefix}
}

func NewCachedBech32Codec(prefix string, opts CachedCodecOptions) (address.Codec, error) {
var err error
ac := Bech32Codec{prefix}
if opts.Mu == nil && opts.Lru == nil {
opts.Mu = new(sync.Mutex)
opts.Lru, err = simplelru.NewLRU(256, nil)
if err != nil {
return nil, fmt.Errorf("failed to create LRU cache: %w", err)
}
} else if opts.Mu == nil && opts.Lru != nil {
// The LRU cache uses a map internally. Without a mutex, concurrent access to this map can lead to race conditions.
// Therefore, a mutex is required to ensure thread-safe operations on the LRU cache.
return nil, errors.New("mutex must be provided alongside the LRU cache")
} else if opts.Mu != nil && opts.Lru == nil {
opts.Lru, err = simplelru.NewLRU(256, nil)
if err != nil {
return nil, fmt.Errorf("failed to create LRU cache: %w", err)
}
}

return cachedBech32Codec{
codec: ac,
cache: opts.Lru,
mu: opts.Mu,
}, nil
}

// StringToBytes encodes text to bytes
func (bc Bech32Codec) StringToBytes(text string) ([]byte, error) {
if len(strings.TrimSpace(text)) == 0 {
return []byte{}, errors.New("empty address string is not allowed")
return []byte{}, errEmptyAddress
}

hrp, bz, err := bech32.DecodeAndConvert(text)
Expand Down Expand Up @@ -61,3 +109,53 @@ func (bc Bech32Codec) BytesToString(bz []byte) (string, error) {

return text, nil
}

func (cbc cachedBech32Codec) BytesToString(bz []byte) (string, error) {
if len(bz) == 0 {
return "", nil
}

key := conv.UnsafeBytesToStr(bz)
cbc.mu.Lock()
defer cbc.mu.Unlock()

addrs, ok := cbc.cache.Get(key)
if !ok {
addrs = make(map[string]string)
cbc.cache.Add(key, addrs)
}

addrMap, ok := addrs.(map[string]string)
if !ok {
return "", fmt.Errorf("cache contains non-map[string]string value for key %s", key)
}

addr, ok := addrMap[cbc.codec.Bech32Prefix]
if !ok {
var err error
addr, err = cbc.codec.BytesToString(bz)
if err != nil {
return "", err
}
addrMap[cbc.codec.Bech32Prefix] = addr
}

return addr, nil
}

func (cbc cachedBech32Codec) StringToBytes(text string) ([]byte, error) {
cbc.mu.Lock()
defer cbc.mu.Unlock()

if addr, ok := cbc.cache.Get(text); ok {
return addr.([]byte), nil
}

addr, err := cbc.codec.StringToBytes(text)
if err != nil {
return nil, err
}
cbc.cache.Add(text, addr)

return addr, nil
}
209 changes: 209 additions & 0 deletions codec/address/bech32_codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package address

import (
"crypto/rand"
"sync"
"sync/atomic"
"testing"

"github.com/hashicorp/golang-lru/simplelru"
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/internal/conv"
)

var (
lru, _ = simplelru.NewLRU(500, nil)
cacheOptions = CachedCodecOptions{
Mu: &sync.Mutex{},
Lru: lru,
}
)

func generateAddresses(totalAddresses int) ([][]byte, error) {
keys := make([][]byte, totalAddresses)
addr := make([]byte, 32)
for i := 0; i < totalAddresses; i++ {
_, err := rand.Read(addr)
if err != nil {
return nil, err
}
keys[i] = addr
}

return keys, nil
}

func TestNewBech32Codec(t *testing.T) {
tests := []struct {
name string
mu *sync.Mutex
lru func(t *testing.T) *simplelru.LRU
error bool
}{
{
name: "lru and mutex provided",
mu: &sync.Mutex{},
lru: func(t *testing.T) *simplelru.LRU {
t.Helper()
newLru, err := simplelru.NewLRU(500, nil)
require.NoError(t, err)
return newLru
},
},
{
name: "both empty",
mu: nil,
lru: func(t *testing.T) *simplelru.LRU {
t.Helper()
return nil
},
},
{
name: "only lru provided",
mu: nil,
lru: func(t *testing.T) *simplelru.LRU {
t.Helper()
newLru, err := simplelru.NewLRU(500, nil)
require.NoError(t, err)
return newLru
},
error: true,
},
{
name: "only mutex provided",
mu: &sync.Mutex{},
lru: func(t *testing.T) *simplelru.LRU {
t.Helper()
return nil
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
newLru := tt.lru(t)
got, err := NewCachedBech32Codec("cosmos", CachedCodecOptions{
Mu: tt.mu,
Lru: newLru,
})
if tt.error {
require.Error(t, err)
} else {
require.NoError(t, err)
require.NotNil(t, got)
}
})
}
}

func TestBech32Codec(t *testing.T) {
tests := []struct {
name string
prefix string
lru *simplelru.LRU
address string
}{
{
name: "create accounts cached bech32 codec",
prefix: "cosmos",
lru: lru,
address: "cosmos1p8s0p6gqc6c9gt77lgr2qqujz49huhu6a80smx",
},
{
name: "create validator cached bech32 codec",
prefix: "cosmosvaloper",
lru: lru,
address: "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0",
},
{
name: "create consensus cached bech32 codec",
prefix: "cosmosvalcons",
lru: lru,
address: "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac, err := NewCachedBech32Codec(tt.prefix, cacheOptions)
require.NoError(t, err)

cached, ok := ac.(cachedBech32Codec)
require.True(t, ok)
require.Equal(t, cached.cache, tt.lru)

addr, err := ac.StringToBytes(tt.address)
require.NoError(t, err)

cachedAddr, ok := tt.lru.Get(tt.address)
require.True(t, ok)
require.Equal(t, addr, cachedAddr)

accAddr, err := ac.BytesToString(addr)
require.NoError(t, err)

cachedStrAddr, ok := tt.lru.Get(conv.UnsafeBytesToStr(addr))
require.True(t, ok)
cachedStrAddrMap, ok := cachedStrAddr.(map[string]string)
require.True(t, ok)
require.Equal(t, accAddr, cachedStrAddrMap[tt.prefix])
})
}
}

func TestMultipleBech32Codec(t *testing.T) {
cAc, err := NewCachedBech32Codec("cosmos", cacheOptions)
require.NoError(t, err)
cosmosAc, ok := cAc.(cachedBech32Codec)
require.True(t, ok)
sAc, err := NewCachedBech32Codec("stake", cacheOptions)
require.NoError(t, err)
stakeAc, ok := sAc.(cachedBech32Codec)
require.True(t, ok)
require.Equal(t, cosmosAc.cache, stakeAc.cache)

addr := make([]byte, 32)
_, err = rand.Read(addr)
require.NoError(t, err)

cosmosAddr, err := cosmosAc.BytesToString(addr)
require.NoError(t, err)
stakeAddr, err := stakeAc.BytesToString(addr)
require.NoError(t, err)
require.True(t, cosmosAddr != stakeAddr)

cachedCosmosAddr, err := cosmosAc.BytesToString(addr)
require.NoError(t, err)
require.Equal(t, cosmosAddr, cachedCosmosAddr)

cachedStakeAddr, err := stakeAc.BytesToString(addr)
require.NoError(t, err)
require.Equal(t, stakeAddr, cachedStakeAddr)
}

func TestBech32CodecRace(t *testing.T) {
ac, err := NewCachedBech32Codec("cosmos", cacheOptions)
require.NoError(t, err)
myAddrBz := []byte{0x1, 0x2, 0x3, 0x4, 0x5}

var (
wgStart, wgDone sync.WaitGroup
errCount atomic.Uint32
)
const n = 3
wgStart.Add(n)
wgDone.Add(n)
for i := 0; i < n; i++ {
go func() {
wgStart.Done()
wgStart.Wait() // wait for all routines started

got, err := ac.BytesToString(myAddrBz)
if err != nil || got != "cosmos1qypqxpq9dc9msf" {
errCount.Add(1)
}
wgDone.Done()
}()
}
wgDone.Wait() // wait for all routines completed
require.Equal(t, errCount.Load(), uint32(0))
}
Loading

0 comments on commit faccd45

Please sign in to comment.