Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport: Allow bypassing the new warning wait period through PIO_ACKWARN env var: #1810 #1811

Merged
merged 1 commit into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

*nothing
### Improvements

* Allow bypassing the config warning wait using an environment variable [PR 1810](https://github.com/provenance-io/provenance/pull/1810).

---

Expand Down
3 changes: 1 addition & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,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 @@ -1057,7 +1057,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
Loading