Skip to content

Commit

Permalink
Allow bypassing the new warning wait period through PIO_ACKWARN env v…
Browse files Browse the repository at this point in the history
…ar. (#1810)

* Tweak the store loader config warning stuff a bit to make the tests not actually do the sleeps. Also allow bypassing the sleep via env var. Standardize some of the buffered logger stuff too.

* Add changelog entry.

* Fix imports in app/store_loader_test.go.

* Move the buffered logger to internal because the rosetta stuff needed it (was included in the non-unit-test-only app/test_helpers.go file) but couldn't get it because it wasn't part of accessible stuff.
  • Loading branch information
SpicyLemon authored Jan 12, 2024
1 parent aa179d2 commit ec697ce
Show file tree
Hide file tree
Showing 9 changed files with 430 additions and 217 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* Add upgrade handler for 1.18 [#1756](https://github.com/provenance-io/provenance/pull/1756).
* Remove the rust upgrade handlers [PR 1774](https://github.com/provenance-io/provenance/pull/1774).
* Allow bypassing the config warning wait using an environment variable [PR 1810](https://github.com/provenance-io/provenance/pull/1810).

### Bug Fixes

Expand Down
3 changes: 1 addition & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ func New(
}

// Currently in an upgrade hold for this block.
var storeLoader baseapp.StoreLoader
storeLoader := baseapp.DefaultStoreLoader
if upgradeInfo.Name != "" && upgradeInfo.Height == app.LastBlockHeight()+1 {
if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
app.Logger().Info("Skipping upgrade based on height",
Expand All @@ -1075,7 +1075,6 @@ func New(
storeLoader = GetUpgradeStoreLoader(app, upgradeInfo)
}
}
// --

// Verify configuration settings
storeLoader = ValidateWrapper(app.Logger(), appOpts, storeLoader)
Expand Down
111 changes: 66 additions & 45 deletions app/store_loader.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package app

import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"

"github.com/spf13/cast"
Expand All @@ -16,60 +18,79 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// StoreLoaderWrapper is a wrapper function that is called before the StoreLoader.
type StoreLoaderWrapper func(sdk.CommitMultiStore, baseapp.StoreLoader) error
// ValidateWrapperSleeper is the sleeper that the ValidateWrapper will use.
// It primarily exists so it can be changed for unit tests on ValidateWrapper so they don't take so long.
var ValidateWrapperSleeper Sleeper = &DefaultSleeper{}

// WrapStoreLoader creates a new StoreLoader by wrapping an existing one.
func WrapStoreLoader(wrapper StoreLoaderWrapper, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
// ValidateWrapper creates a new StoreLoader that first checks the config settings before calling the provided StoreLoader.
func ValidateWrapper(logger log.Logger, appOpts servertypes.AppOptions, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
return func(ms sdk.CommitMultiStore) error {
if storeLoader == nil {
storeLoader = baseapp.DefaultStoreLoader
}
IssueConfigWarnings(logger, appOpts, ValidateWrapperSleeper)
return storeLoader(ms)
}
}

if wrapper == nil {
return errors.New("wrapper must not be nil")
}
// Sleeper is an interface for something with a Sleep function.
type Sleeper interface {
Sleep(d time.Duration)
}

return wrapper(ms, storeLoader)
}
// DefaultSleeper uses the time.Sleep function for sleeping.
type DefaultSleeper struct{}

// Sleep is a wrapper for time.Sleep(d).
func (s DefaultSleeper) Sleep(d time.Duration) {
time.Sleep(d)
}

// ValidateWrapper creates a new StoreLoader that first checks the config settings before calling the provided StoreLoader.
func ValidateWrapper(logger log.Logger, appOpts servertypes.AppOptions, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
return WrapStoreLoader(func(ms sdk.CommitMultiStore, sl baseapp.StoreLoader) error {
const MaxPruningInterval = 999
const SleepSeconds = 30
backend := server.GetAppDBBackend(appOpts)
interval := cast.ToUint64(appOpts.Get("pruning-interval"))
txIndexer := cast.ToStringMap(appOpts.Get("tx_index"))
indexer := cast.ToString(txIndexer["indexer"])
fastNode := cast.ToBool(appOpts.Get("iavl-disable-fastnode"))
var errs []string

if interval > MaxPruningInterval {
errs = append(errs, fmt.Sprintf("pruning-interval %d EXCEEDS %d AND IS NOT RECOMMENDED, AS IT CAN LEAD TO MISSED BLOCKS ON VALIDATORS", interval, MaxPruningInterval))
}
// IssueConfigWarnings checks a few values in the configs and issues warnings and sleeps if appropriate.
func IssueConfigWarnings(logger log.Logger, appOpts servertypes.AppOptions, sleeper Sleeper) {
const MaxPruningInterval = 999
const SleepSeconds = 30
interval := cast.ToUint64(appOpts.Get("pruning-interval"))
txIndexer := cast.ToStringMap(appOpts.Get("tx_index"))
indexer := cast.ToString(txIndexer["indexer"])
fastNode := cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))
backend := server.GetAppDBBackend(appOpts)
var errs []string

if indexer != "" && indexer != "null" {
errs = append(errs, fmt.Sprintf("indexer \"%s\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%s\"", indexer, "null"))
}
if interval > MaxPruningInterval {
errs = append(errs, fmt.Sprintf("pruning-interval %d EXCEEDS %d AND IS NOT RECOMMENDED, AS IT CAN LEAD TO MISSED BLOCKS ON VALIDATORS.", interval, MaxPruningInterval))
}

if fastNode {
errs = append(errs, fmt.Sprintf("iavl-disable-fastnode \"%v\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%v\"", fastNode, !fastNode))
}
if indexer != "" && indexer != "null" {
errs = append(errs, fmt.Sprintf("indexer \"%s\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%s\".", indexer, "null"))
}

if backend != dbm.GoLevelDBBackend {
errs = append(errs, fmt.Sprintf("%s IS NO LONGER SUPPORTED. MIGRATE TO %s", backend, dbm.GoLevelDBBackend))
}
if fastNode {
errs = append(errs, fmt.Sprintf("%s \"%v\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%v\".", server.FlagDisableIAVLFastNode, fastNode, !fastNode))
}

if backend != dbm.GoLevelDBBackend {
errs = append(errs, fmt.Sprintf("%s IS NO LONGER SUPPORTED. MIGRATE TO %s.", backend, dbm.GoLevelDBBackend))
}

if len(errs) > 0 {
logger.Error(fmt.Sprintf("NODE WILL CONTINUE AFTER %d SECONDS", SleepSeconds))
for _, err := range errs {
logger.Error(err)
}
time.Sleep(SleepSeconds * time.Second)
if len(errs) > 0 {
for _, err := range errs {
logger.Error(err)
}
if !HaveAckWarn() {
logger.Error(fmt.Sprintf("NODE WILL CONTINUE AFTER %d SECONDS.", SleepSeconds))
logger.Error("This wait can be bypassed by fixing the above warnings or setting the PIO_ACKWARN environment variable to \"1\".")
sleeper.Sleep(SleepSeconds * time.Second)
}
}
}

// HaveAckWarn returns true if the PIO_ACKWARN env var is set and isn't a false value (e.g. "0", "f" or "false").
func HaveAckWarn() bool {
ackWarn := strings.TrimSpace(os.Getenv("PIO_ACKWARN"))
if len(ackWarn) == 0 {
return false
}

return sl(ms)
}, storeLoader)
rv, err := strconv.ParseBool(ackWarn)
// We return false only if it parsed successfully to a false value.
// If parsing failed or it parsed to a true value, we return true.
return err != nil || rv
}
Loading

0 comments on commit ec697ce

Please sign in to comment.