Skip to content

Commit

Permalink
Merge branch 'main' into alex/sims2_main
Browse files Browse the repository at this point in the history
* main:
  docs(client/debug): correct `debug raw-bytes` command example (#21671)
  build: don't reinstall golangci-lint if already installed (#21662)
  refactor(server/v2): kill viper from server components (#21663)
  chore: sync changelog with latest releases (#21658)
  refactor: remove viper as a direct dependency (#21635)
  ci: centralized job for rocksdb libaries cache (#21657)
  fix: remove stray fmt.Println (#21661)
  • Loading branch information
alpe committed Sep 12, 2024
2 parents 4c367e4 + 0fc06f1 commit 972661e
Show file tree
Hide file tree
Showing 52 changed files with 294 additions and 282 deletions.
4 changes: 4 additions & 0 deletions .github/scripts/install-rocksdb-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -Eeuo pipefail

sudo apt update && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev build-essential
3 changes: 0 additions & 3 deletions .github/scripts/install-rocksdb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ if [ -z "$ROCKSDB_VERSION" ]; then
exit 1
fi

# Update and install dependencies
sudo apt update && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev build-essential

# Clone RocksDB repository
git clone https://github.com/facebook/rocksdb.git /home/runner/rocksdb
cd /home/runner/rocksdb || exit 1
Expand Down
12 changes: 3 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,12 @@ jobs:
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-${{ matrix.go-arch }}
- name: Install rocksdb deps
if: matrix.go-arch == 'amd64'
run: ./.github/scripts/install-rocksdb-deps.sh
- name: Install rocksdb
if: matrix.go-arch == 'amd64' && steps.cache-rocksdb.outputs.cache-hit != 'true'
id: install_rocksdb
run: ./.github/scripts/install-rocksdb.sh
- name: Saves rocksdb libraries cache
if: matrix.go-arch == 'amd64' && steps.install_rocksdb.outcome == 'success'
uses: actions/cache/save@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-${{ matrix.go-arch }}
###################
#### Build App ####
###################
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/cache-rocksdb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Cache rocksdb libraries
on:
push:
paths:
- build.mk
schedule:
- cron: "*/15 * * * *" # Every 15 minutes
workflow_dispatch:

permissions:
contents: read

jobs:

check-cache-rocksdb:
name: Check existing cache
runs-on: ubuntu-latest
outputs:
cache-hit: ${{ steps.cache-rocksdb.outputs.cache-hit }}

steps:
- uses: actions/checkout@v4

- name: Get rocksdb version
run: ./.github/scripts/get-rocksdb-version.sh

- name: Fix permissions for cache
run: sudo chown $(whoami) /usr/local/lib /usr/local/include

- name: Restore rocksdb libraries cache
id: cache-rocksdb
uses: actions/cache/restore@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64


save-cache-rocksdb:
name: Build rocksdb libraries and save cache
runs-on: ubuntu-latest
needs: check-cache-rocksdb
if: needs.check-cache-rocksdb.outputs.cache-hit != 'true'
steps:
- uses: actions/checkout@v4

- name: Get rocksdb version
run: ./.github/scripts/get-rocksdb-version.sh

- name: Install rocksdb deps
run: ./.github/scripts/install-rocksdb-deps.sh
- name: Install rocksdb
run: ./.github/scripts/install-rocksdb.sh

- name: Saves rocksdb libraries cache
uses: actions/cache/save@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
13 changes: 3 additions & 10 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,11 @@ jobs:
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: Install rocksdb deps
run: ./.github/scripts/install-rocksdb-deps.sh
- name: Install rocksdb
if: env.GIT_DIFF && steps.cache-rocksdb.outputs.cache-hit != 'true'
id: install_rocksdb
if: steps.cache-rocksdb.outputs.cache-hit != 'true'
run: ./.github/scripts/install-rocksdb.sh
- name: Saves rocksdb libraries cache
if: steps.install_rocksdb.outcome == 'success'
uses: actions/cache/save@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: run linting (long)
if: env.GIT_DIFF
id: lint_long
Expand Down
26 changes: 3 additions & 23 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -801,20 +801,10 @@ jobs:
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: Install rocksdb deps
run: |
sudo apt-get update && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
run: ./.github/scripts/install-rocksdb-deps.sh
- name: Install rocksdb
if: steps.cache-rocksdb.outputs.cache-hit != 'true'
id: install_rocksdb
run: ./.github/scripts/install-rocksdb.sh
- name: Saves rocksdb libraries cache
if: steps.install_rocksdb.outcome == 'success'
uses: actions/cache/save@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: tests
if: env.GIT_DIFF
run: |
Expand Down Expand Up @@ -861,20 +851,10 @@ jobs:
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: Install rocksdb deps
run: |
sudo apt-get update && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
run: ./.github/scripts/install-rocksdb-deps.sh
- name: Install rocksdb
if: env.GIT_DIFF && steps.cache-rocksdb.outputs.cache-hit != 'true'
id: install_rocksdb
if: steps.cache-rocksdb.outputs.cache-hit != 'true'
run: ./.github/scripts/install-rocksdb.sh
- name: Saves rocksdb libraries cache
if: steps.install_rocksdb.outcome == 'success'
uses: actions/cache/save@v4
with:
path: |
/usr/local/lib/librocksdb.*
/usr/local/include/rocksdb
key: ${{ runner.os }}-rocksdb-${{ env.ROCKSDB_VERSION }}-amd64
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
Expand Down
22 changes: 9 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,18 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
### Features

* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simulate nested messages.
* (cli) [#21372](https://github.com/cosmos/cosmos-sdk/pull/21372) Add a `bulk-add-genesis-account` genesis command to add many genesis accounts at once.

### Improvements

* (client) [#21436](https://github.com/cosmos/cosmos-sdk/pull/21436) Use `address.Codec` from client.Context in `tx.Sign`.
* (internal) [#21412](https://github.com/cosmos/cosmos-sdk/pull/21412) Using unsafe.String and unsafe.SliceData.
* (x/genutil) [#21249](https://github.com/cosmos/cosmos-sdk/pull/21249) Incremental JSON parsing for AppGenesis where possible.

### Bug Fixes

* (baseapp) [#21256](https://github.com/cosmos/cosmos-sdk/pull/21256) Halt height will not commit the block indicated, meaning that if halt-height is set to 10, only blocks until 9 (included) will be committed. This is to go back to the original behavior before a change was introduced in v0.50.0.
* (baseapp) [#21413](https://github.com/cosmos/cosmos-sdk/pull/21413) Fix data race in sdk mempool.

### API Breaking Changes

* (baseapp) [#21413](https://github.com/cosmos/cosmos-sdk/pull/21413) Add `SelectBy` method to `Mempool` interface, which is thread-safe to use.
* (sims)[#21613](https://github.com/cosmos/cosmos-sdk/pull/21613) Add sims2 framework and factory methods for simpler message factories in modules

### Deprecated

* (types) [#21435](https://github.com/cosmos/cosmos-sdk/pull/21435) The `String()` method on `AccAddress`, `ValAddress` and `ConsAddress` have been deprecated. This is done because those are still using the deprecated global `sdk.Config`. Use an `address.Codec` instead.

## [v0.52.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.52.0) - 2024-XX-XX

Every module contains its own CHANGELOG.md. Please refer to the module you are interested in.
Expand Down Expand Up @@ -135,6 +125,9 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* (baseapp) [#20380](https://github.com/cosmos/cosmos-sdk/pull/20380) Enhanced OfferSnapshot documentation.
* (client) [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Remove `ReadDefaultValuesFromDefaultClientConfig` from `client` package. (It was introduced in `v0.50.6` as a quick fix).
* (grpcserver) [#20945](https://github.com/cosmos/cosmos-sdk/pull/20945) Adds error handling for out-of-gas panics in grpc query handlers.
* (internal) [#21412](https://github.com/cosmos/cosmos-sdk/pull/21412) Using unsafe.String and unsafe.SliceData.
* (client) [#21436](https://github.com/cosmos/cosmos-sdk/pull/21436) Use `address.Codec` from client.Context in `tx.Sign`.
* (x/genutil) [#21249](https://github.com/cosmos/cosmos-sdk/pull/21249) Incremental JSON parsing for AppGenesis where possible.

### Bug Fixes

Expand All @@ -155,7 +148,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* (client) [#17215](https://github.com/cosmos/cosmos-sdk/pull/17215) `server.StartCmd`,`server.ExportCmd`,`server.NewRollbackCmd`,`pruning.Cmd`,`genutilcli.InitCmd`,`genutilcli.GenTxCmd`,`genutilcli.CollectGenTxsCmd`,`genutilcli.AddGenesisAccountCmd`, do not take a home directory anymore. It is inferred from the root command.
* (client) [#17259](https://github.com/cosmos/cosmos-sdk/pull/17259) Remove deprecated `clientCtx.PrintObjectLegacy`. Use `clientCtx.PrintProto` or `clientCtx.PrintRaw` instead.
* (types) [#17348](https://github.com/cosmos/cosmos-sdk/pull/17348) Remove the `WrapServiceResult` function.
* The `*sdk.Result` returned by the msg server router will not contain the `.Data` field.
* The `*sdk.Result` returned by the msg server router will not contain the `.Data` field.
* (types) [#17426](https://github.com/cosmos/cosmos-sdk/pull/17426) `NewContext` does not take a `cmtproto.Header{}` any longer.
* `WithChainID` / `WithBlockHeight` / `WithBlockHeader` must be used to set values on the context
* (client/keys) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) `clientkeys.NewKeyOutput`, `MkConsKeyOutput`, `MkValKeyOutput`, `MkAccKeyOutput`, `MkAccKeysOutput` now take their corresponding address codec instead of using the global SDK config.
Expand Down Expand Up @@ -209,7 +202,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* (x/crisis) [#20043](https://github.com/cosmos/cosmos-sdk/pull/20043) Changed `NewMsgVerifyInvariant` to accept a string as argument instead of an `AccAddress`.
* (x/simulation)[#20056](https://github.com/cosmos/cosmos-sdk/pull/20056) `SimulateFromSeed` now takes an address codec as argument.
* (server) [#20140](https://github.com/cosmos/cosmos-sdk/pull/20140) Remove embedded grpc-web proxy in favor of standalone grpc-web proxy. [Envoy Proxy](https://www.envoyproxy.io/docs/envoy/latest/start/start)
* (client) [#20255](https://github.com/cosmos/cosmos-sdk/pull/20255) Use comet proofOp proto type instead of sdk version to avoid needing to translate to later be proven in the merkle proof runtime.
* (client) [#20255](https://github.com/cosmos/cosmos-sdk/pull/20255) Use comet proofOp proto type instead of sdk version to avoid needing to translate to later be proven in the merkle proof runtime.
* (types)[#20369](https://github.com/cosmos/cosmos-sdk/pull/20369) The signature of `HasAminoCodec` has changed to accept a `core/legacy.Amino` interface instead of `codec.LegacyAmino`.
* (server) [#20422](https://github.com/cosmos/cosmos-sdk/pull/20422) Deprecated `ServerContext`. To get `cmtcfg.Config` from cmd, use `client.GetCometConfigFromCmd(cmd)` instead of `server.GetServerContextFromCmd(cmd).Config`
* (x/genutil) [#20740](https://github.com/cosmos/cosmos-sdk/pull/20740) Update `genutilcli.Commands` and `genutilcli.CommandsWithCustomMigrationMap` to take the genesis module and abstract the module manager.
Expand All @@ -218,10 +211,12 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* Remove parameter `txConfig` from `genutilcli.Commands`,`genutilcli.CommandsWithCustomMigrationMap`,`genutilcli.GenTxCmd`.
* Remove parameter `addressCodec` from `genutilcli.GenTxCmd`,`genutilcli.AddGenesisAccountCmd`,`stakingcli.BuildCreateValidatorMsg`.
* (sims) [#21039](https://github.com/cosmos/cosmos-sdk/pull/21039): Remove Baseapp from sims by a new interface `simtypes.AppEntrypoint`.
* (x/genutil) [#21372](https://github.com/cosmos/cosmos-sdk/pull/21372) Remove `AddGenesisAccount` for `AddGenesisAccounts`.
* (baseapp) [#21413](https://github.com/cosmos/cosmos-sdk/pull/21413) Add `SelectBy` method to `Mempool` interface, which is thread-safe to use.

### Client Breaking Changes

* (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query.
* (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query.

### CLI Breaking Changes

Expand All @@ -233,6 +228,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i

* (simapp) [#19146](https://github.com/cosmos/cosmos-sdk/pull/19146) Replace `--v` CLI option with `--validator-count`/`-n`.
* (module) [#19370](https://github.com/cosmos/cosmos-sdk/pull/19370) Deprecate `module.Configurator`, use `appmodule.HasMigrations` and `appmodule.HasServices` instead from Core API.
* (types) [#21435](https://github.com/cosmos/cosmos-sdk/pull/21435) The `String()` method on `AccAddress`, `ValAddress` and `ConsAddress` have been deprecated. This is done because those are still using the deprecated global `sdk.Config`. Use an `address.Codec` instead.

## [v0.50.9](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.9) - 2024-08-07

Expand Down
2 changes: 1 addition & 1 deletion client/debug/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func RawBytesCmd() *cobra.Command {
Use: "raw-bytes <raw-bytes>",
Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex",
Long: "Convert raw-bytes to hex.",
Example: fmt.Sprintf("%s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]", version.AppName),
Example: fmt.Sprintf("%s debug raw-bytes '[72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]'", version.AppName),
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
stringBytes := args[0]
Expand Down
8 changes: 8 additions & 0 deletions core/server/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package server

// DynamicConfig defines an interface for configuration that can be dynamically
// fetched at runtime by an arbitrary key.
type DynamicConfig interface {
Get(string) any
GetString(string) string
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ require (
replace (
cosmossdk.io/api => ./api
cosmossdk.io/collections => ./collections
cosmossdk.io/core => ./core
cosmossdk.io/core/testing => ./core/testing
cosmossdk.io/store => ./store
cosmossdk.io/x/bank => ./x/bank
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88e
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k=
cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90=
cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050=
cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
Expand Down
47 changes: 20 additions & 27 deletions runtime/v2/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import (
"io"
"path/filepath"

"github.com/spf13/viper"

"cosmossdk.io/core/appmodule"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/server/v2/appmanager"
Expand All @@ -25,8 +24,8 @@ import (
// the existing app.go initialization conventions.
type AppBuilder[T transaction.Tx] struct {
app *App[T]
storeOptions *rootstore.FactoryOptions
viper *viper.Viper
config server.DynamicConfig
storeOptions rootstore.Options

// the following fields are used to overwrite the default
branch func(state store.ReaderMap) store.WriterMap
Expand Down Expand Up @@ -73,9 +72,6 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule
// To be used in combination of RegisterModules.
func (a *AppBuilder[T]) RegisterStores(keys ...string) {
a.app.storeKeys = append(a.app.storeKeys, keys...)
if a.storeOptions != nil {
a.storeOptions.StoreKeys = append(a.storeOptions.StoreKeys, keys...)
}
}

// Build builds an *App instance.
Expand Down Expand Up @@ -124,29 +120,26 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
}
a.app.stf = stf

storeOpts := rootstore.DefaultStoreOptions()
if s := a.viper.Sub("store.options"); s != nil {
if err := s.Unmarshal(&storeOpts); err != nil {
return nil, fmt.Errorf("failed to unmarshal store options: %w", err)
}
}

home := a.viper.GetString(FlagHome)
scRawDb, err := db.NewDB(db.DBType(a.viper.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil)
home := a.config.GetString(FlagHome)
scRawDb, err := db.NewDB(
db.DBType(a.config.GetString("store.app-db-backend")),
"application",
filepath.Join(home, "data"),
nil,
)
if err != nil {
panic(err)
}

storeOptions := &rootstore.FactoryOptions{
factoryOptions := &rootstore.FactoryOptions{
Logger: a.app.logger,
RootDir: home,
Options: storeOpts,
Options: a.storeOptions,
StoreKeys: append(a.app.storeKeys, "stf"),
SCRawDB: scRawDb,
}
a.storeOptions = storeOptions

rs, err := rootstore.CreateRootStore(a.storeOptions)
rs, err := rootstore.CreateRootStore(factoryOptions)
if err != nil {
return nil, fmt.Errorf("failed to create root store: %w", err)
}
Expand Down Expand Up @@ -217,14 +210,14 @@ func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.C

// AppBuilderWithPostTxExec sets logic that will be executed after each transaction.
// When not provided, a no-op function will be used.
func AppBuilderWithPostTxExec[T transaction.Tx](
postTxExec func(
ctx context.Context,
tx T,
success bool,
) error,
) AppBuilderOption[T] {
func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] {
return func(a *AppBuilder[T]) {
a.postTxExec = postTxExec
}
}

func AppBuilderWithStoreOptions[T transaction.Tx](opts rootstore.Options) AppBuilderOption[T] {
return func(a *AppBuilder[T]) {
a.storeOptions = opts
}
}
Loading

0 comments on commit 972661e

Please sign in to comment.