-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/v1.17.x' into dwedul/bp-wasmvm-1.17
- Loading branch information
Showing
4 changed files
with
278 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package app | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/spf13/cast" | ||
|
||
"github.com/tendermint/tendermint/libs/log" | ||
dbm "github.com/tendermint/tm-db" | ||
|
||
"github.com/cosmos/cosmos-sdk/baseapp" | ||
"github.com/cosmos/cosmos-sdk/server" | ||
servertypes "github.com/cosmos/cosmos-sdk/server/types" | ||
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 | ||
|
||
// WrapStoreLoader creates a new StoreLoader by wrapping an existing one. | ||
func WrapStoreLoader(wrapper StoreLoaderWrapper, storeLoader baseapp.StoreLoader) baseapp.StoreLoader { | ||
return func(ms sdk.CommitMultiStore) error { | ||
if storeLoader == nil { | ||
storeLoader = baseapp.DefaultStoreLoader | ||
} | ||
|
||
if wrapper == nil { | ||
return errors.New("wrapper must not be nil") | ||
} | ||
|
||
return wrapper(ms, 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 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)) | ||
} | ||
|
||
if indexer != "" { | ||
errs = append(errs, fmt.Sprintf("indexer \"%s\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%s\"", indexer, "")) | ||
} | ||
|
||
if fastNode { | ||
errs = append(errs, fmt.Sprintf("iavl-disable-fastnode \"%v\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%v\"", 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) | ||
} | ||
|
||
return sl(ms) | ||
}, storeLoader) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package app | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/cosmos/cosmos-sdk/baseapp" | ||
"github.com/cosmos/cosmos-sdk/store/rootmulti" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/tendermint/tendermint/libs/log" | ||
dbm "github.com/tendermint/tm-db" | ||
) | ||
|
||
func TestWrapStoreLoader(t *testing.T) { | ||
var flag bool | ||
tests := []struct { | ||
name string | ||
storeLoader baseapp.StoreLoader | ||
wrapper StoreLoaderWrapper | ||
err string | ||
}{ | ||
{ | ||
name: "nil store loader is set with valid value", | ||
storeLoader: nil, | ||
wrapper: createMockStoreWrapper(&flag), | ||
}, | ||
{ | ||
name: "nil wrapper is handled", | ||
storeLoader: createMockStoreLoader(), | ||
wrapper: nil, | ||
err: "wrapper must not be nil", | ||
}, | ||
{ | ||
name: "contents of wrapper are called", | ||
storeLoader: createMockStoreLoader(), | ||
wrapper: createMockFlipWrapper(&flag), | ||
}, | ||
} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.name, func(t *testing.T) { | ||
storeLoader := WrapStoreLoader(tc.wrapper, tc.storeLoader) | ||
db := dbm.MemDB{} | ||
ms := rootmulti.NewStore(&db, nil) | ||
assert.NotNil(t, ms, "should create a new multistore for testing") | ||
flag = false | ||
|
||
err := storeLoader(ms) | ||
if len(tc.err) > 0 { | ||
assert.EqualError(t, err, tc.err, "should have correct error") | ||
assert.False(t, flag, "wrapper should not be executed") | ||
} else { | ||
assert.NoError(t, err, "should not return an error on success") | ||
assert.True(t, flag, "wrapper should execute and have correct logic") | ||
} | ||
|
||
}) | ||
} | ||
} | ||
|
||
func TestValidateWrapper(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
appOpts MockAppOptions | ||
delta uint64 | ||
}{ | ||
{ | ||
name: "recommended pruning, indexer, db, and fastnode should not wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "13", | ||
db: "goleveldb", | ||
fastNode: "false", | ||
indexer: "", | ||
}, | ||
delta: 0, | ||
}, | ||
{ | ||
name: "non-recommended pruning should wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "1000", | ||
db: "goleveldb", | ||
fastNode: "false", | ||
indexer: "", | ||
}, | ||
delta: 30, | ||
}, | ||
{ | ||
name: "non-recommended indexer should wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "13", | ||
db: "goleveldb", | ||
fastNode: "false", | ||
indexer: "kv", | ||
}, | ||
delta: 30, | ||
}, | ||
{ | ||
name: "non-recommended db should wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "13", | ||
db: "cleveldb", | ||
fastNode: "false", | ||
indexer: "", | ||
}, | ||
delta: 30, | ||
}, | ||
{ | ||
name: "non-recommended fastnode should wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "13", | ||
db: "goleveldb", | ||
fastNode: "true", | ||
indexer: "", | ||
}, | ||
delta: 30, | ||
}, | ||
{ | ||
name: "multiple non-recommended should wait", | ||
appOpts: MockAppOptions{ | ||
pruning: "1000", | ||
db: "cleveldb", | ||
fastNode: "true", | ||
indexer: "kv", | ||
}, | ||
delta: 30, | ||
}, | ||
} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.name, func(t *testing.T) { | ||
logger := log.NewNopLogger() | ||
storeLoader := ValidateWrapper(logger, tc.appOpts, createMockStoreLoader()) | ||
db := dbm.MemDB{} | ||
ms := rootmulti.NewStore(&db, nil) | ||
assert.NotNil(t, ms, "should create a new multistore for testing") | ||
|
||
start := time.Now() | ||
err := storeLoader(ms) | ||
delta := uint64(time.Now().Sub(start).Seconds()) | ||
assert.NoError(t, err, "should not throw error") | ||
assert.GreaterOrEqual(t, delta, tc.delta, "should wait correct amount of time") | ||
}) | ||
} | ||
} | ||
|
||
// createMockStoreLoader creates an empty StoreLoader. | ||
func createMockStoreLoader() baseapp.StoreLoader { | ||
return func(ms sdk.CommitMultiStore) error { | ||
return nil | ||
} | ||
} | ||
|
||
// createMockFlipWrapper creates a wrapper that has logic to flip a bit. | ||
func createMockFlipWrapper(flag *bool) StoreLoaderWrapper { | ||
return func(cms sdk.CommitMultiStore, sl baseapp.StoreLoader) error { | ||
*flag = !(*flag) | ||
return nil | ||
} | ||
} | ||
|
||
// createMockStoreWrapper creates a wrapper that checks if the StoreLoader is nil and sets the flag accordingly. | ||
func createMockStoreWrapper(flag *bool) StoreLoaderWrapper { | ||
return func(cms sdk.CommitMultiStore, sl baseapp.StoreLoader) error { | ||
*flag = sl != nil | ||
return nil | ||
} | ||
} | ||
|
||
// MockAppOptions is a mocked version of AppOpts that allows the developer to provide the pruning attribute. | ||
type MockAppOptions struct { | ||
pruning string | ||
indexer string | ||
db string | ||
fastNode string | ||
} | ||
|
||
// Get returns the value for the provided option. | ||
func (m MockAppOptions) Get(opt string) interface{} { | ||
switch opt { | ||
case "pruning-interval": | ||
return m.pruning | ||
case "tx_index": | ||
return map[string]interface{}{ | ||
"indexer": m.indexer, | ||
} | ||
case "app-db-backend": | ||
return m.db | ||
case "db-backend": | ||
return m.db | ||
case "iavl-disable-fastnode": | ||
return m.fastNode | ||
} | ||
|
||
return nil | ||
} |