Skip to content

Commit

Permalink
Merge PR #5500: Regen network/multistore upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
anilcse committed Feb 28, 2020
1 parent de0f1a9 commit 0b74491
Show file tree
Hide file tree
Showing 19 changed files with 351 additions and 130 deletions.
60 changes: 0 additions & 60 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package baseapp

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"reflect"
"runtime/debug"
"strings"
Expand All @@ -17,7 +14,6 @@ import (
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
Expand Down Expand Up @@ -226,62 +222,6 @@ func DefaultStoreLoader(ms sdk.CommitMultiStore) error {
return ms.LoadLatestVersion()
}

// StoreLoaderWithUpgrade is used to prepare baseapp with a fixed StoreLoader
// pattern. This is useful in test cases, or with custom upgrade loading logic.
func StoreLoaderWithUpgrade(upgrades *storetypes.StoreUpgrades) StoreLoader {
return func(ms sdk.CommitMultiStore) error {
return ms.LoadLatestVersionAndUpgrade(upgrades)
}
}

// UpgradeableStoreLoader can be configured by SetStoreLoader() to check for the
// existence of a given upgrade file - json encoded StoreUpgrades data.
//
// If not file is present, it will peform the default load (no upgrades to store).
//
// If the file is present, it will parse the file and execute those upgrades
// (rename or delete stores), while loading the data. It will also delete the
// upgrade file upon successful load, so that the upgrade is only applied once,
// and not re-applied on next restart
//
// This is useful for in place migrations when a store key is renamed between
// two versions of the software. (TODO: this code will move to x/upgrades
// when PR #4233 is merged, here mainly to help test the design)
func UpgradeableStoreLoader(upgradeInfoPath string) StoreLoader {
return func(ms sdk.CommitMultiStore) error {
_, err := os.Stat(upgradeInfoPath)
if os.IsNotExist(err) {
return DefaultStoreLoader(ms)
} else if err != nil {
return err
}

// there is a migration file, let's execute
data, err := ioutil.ReadFile(upgradeInfoPath)
if err != nil {
return fmt.Errorf("cannot read upgrade file %s: %v", upgradeInfoPath, err)
}

var upgrades storetypes.StoreUpgrades
err = json.Unmarshal(data, &upgrades)
if err != nil {
return fmt.Errorf("cannot parse upgrade file: %v", err)
}

err = ms.LoadLatestVersionAndUpgrade(&upgrades)
if err != nil {
return fmt.Errorf("load and upgrade database: %v", err)
}

// if we have a successful load, we delete the file
err = os.Remove(upgradeInfoPath)
if err != nil {
return fmt.Errorf("deleting upgrade file %s: %v", upgradeInfoPath, err)
}
return nil
}
}

// LoadVersion loads the BaseApp application version. It will panic if called
// more than once on a running baseapp.
func (app *BaseApp) LoadVersion(version int64, baseKey *sdk.KVStoreKey) error {
Expand Down
50 changes: 0 additions & 50 deletions baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"sync"
"testing"
Expand Down Expand Up @@ -137,18 +136,6 @@ func useDefaultLoader(app *BaseApp) {
app.SetStoreLoader(DefaultStoreLoader)
}

func useUpgradeLoader(upgrades *store.StoreUpgrades) func(*BaseApp) {
return func(app *BaseApp) {
app.SetStoreLoader(StoreLoaderWithUpgrade(upgrades))
}
}

func useFileUpgradeLoader(upgradeInfoPath string) func(*BaseApp) {
return func(app *BaseApp) {
app.SetStoreLoader(UpgradeableStoreLoader(upgradeInfoPath))
}
}

func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) {
rs := rootmulti.NewStore(db)
rs.SetPruning(store.PruneNothing)
Expand Down Expand Up @@ -184,19 +171,6 @@ func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte
// Test that we can make commits and then reload old versions.
// Test that LoadLatestVersion actually does.
func TestSetLoader(t *testing.T) {
// write a renamer to a file
f, err := ioutil.TempFile("", "upgrade-*.json")
require.NoError(t, err)
data := []byte(`{"renamed":[{"old_key": "bnk", "new_key": "banker"}]}`)
_, err = f.Write(data)
require.NoError(t, err)
configName := f.Name()
require.NoError(t, f.Close())

// make sure it exists before running everything
_, err = os.Stat(configName)
require.NoError(t, err)

cases := map[string]struct {
setLoader func(*BaseApp)
origStoreKey string
Expand All @@ -211,26 +185,6 @@ func TestSetLoader(t *testing.T) {
origStoreKey: "foo",
loadStoreKey: "foo",
},
"rename with inline opts": {
setLoader: useUpgradeLoader(&store.StoreUpgrades{
Renamed: []store.StoreRename{{
OldKey: "foo",
NewKey: "bar",
}},
}),
origStoreKey: "foo",
loadStoreKey: "bar",
},
"file loader with missing file": {
setLoader: useFileUpgradeLoader(configName + "randomchars"),
origStoreKey: "bnk",
loadStoreKey: "bnk",
},
"file loader with existing file": {
setLoader: useFileUpgradeLoader(configName),
origStoreKey: "bnk",
loadStoreKey: "banker",
},
}

k := []byte("key")
Expand Down Expand Up @@ -265,10 +219,6 @@ func TestSetLoader(t *testing.T) {
checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil)
})
}

// ensure config file was deleted
_, err = os.Stat(configName)
require.True(t, os.IsNotExist(err))
}

func TestAppVersionSetterGetter(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ type SimApp struct {
// NewSimApp returns a reference to an initialized SimApp.
func NewSimApp(
logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool,
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp),
homePath string, invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp),
) *SimApp {

// TODO: Remove cdc in favor of appCodec once all modules are migrated.
Expand Down Expand Up @@ -189,7 +189,7 @@ func NewSimApp(
app.CrisisKeeper = crisis.NewKeeper(
app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName,
)
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec)
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], appCodec, homePath)

// create evidence keeper with router
evidenceKeeper := evidence.NewKeeper(
Expand Down
6 changes: 3 additions & 3 deletions simapp/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

func TestSimAppExport(t *testing.T) {
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0)

genesisState := NewDefaultGenesisState()
stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState)
Expand All @@ -31,15 +31,15 @@ func TestSimAppExport(t *testing.T) {
app.Commit()

// Making a new app object with the db, so that initchain hasn't been called
app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0)
_, _, err = app2.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

// ensure that black listed addresses are properly set in bank keeper
func TestBlackListedAddrs(t *testing.T) {
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0)

for acc := range maccPerms {
require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc)))
Expand Down
4 changes: 2 additions & 2 deletions simapp/sim_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func BenchmarkFullAppSimulation(b *testing.B) {
}
}()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt())

// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
Expand Down Expand Up @@ -65,7 +65,7 @@ func BenchmarkInvariants(b *testing.B) {
}
}()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt())

// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
Expand Down
12 changes: 6 additions & 6 deletions simapp/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestFullAppSimulation(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())

// run randomized simulation
Expand Down Expand Up @@ -95,7 +95,7 @@ func TestAppImportExport(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())

// Run randomized simulation
Expand Down Expand Up @@ -129,7 +129,7 @@ func TestAppImportExport(t *testing.T) {
require.NoError(t, os.RemoveAll(newDir))
}()

newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "SimApp", newApp.Name())

var genesisState GenesisState
Expand Down Expand Up @@ -181,7 +181,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())

// Run randomized simulation
Expand Down Expand Up @@ -220,7 +220,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
require.NoError(t, os.RemoveAll(newDir))
}()

newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "SimApp", newApp.Name())

newApp.InitChain(abci.RequestInitChain{
Expand Down Expand Up @@ -266,7 +266,7 @@ func TestAppStateDeterminism(t *testing.T) {

db := dbm.NewMemDB()

app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, interBlockCacheOpt())

fmt.Printf(
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
Expand Down
4 changes: 2 additions & 2 deletions simapp/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
// Setup initializes a new SimApp. A Nop logger is set in SimApp.
func Setup(isCheckTx bool) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0)
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0)
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
genesisState := NewDefaultGenesisState()
Expand All @@ -48,7 +48,7 @@ func Setup(isCheckTx bool) *SimApp {
// accounts and possible balances.
func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances ...bank.Balance) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0)
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0)

// initialize the chain with the passed in genesis accounts
genesisState := NewDefaultGenesisState()
Expand Down
7 changes: 7 additions & 0 deletions store/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ type StoreUpgrades struct {
Deleted []string `json:"deleted"`
}

// UpgradeInfo defines height and name of the upgrade
// to ensure multistore upgrades happen only at matching height.
type UpgradeInfo struct {
Name string `json:"name"`
Height int64 `json:"height"`
}

// StoreRename defines a name change of a sub-store.
// All data previously under a PrefixStore with OldKey will be copied
// to a PrefixStore with NewKey, then deleted from OldKey store.
Expand Down
2 changes: 1 addition & 1 deletion x/crisis/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var (

func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) {
db := dbm.NewMemDB()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 1)
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1)
ctx := app.NewContext(true, abci.Header{})

constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)
Expand Down
2 changes: 1 addition & 1 deletion x/crisis/internal/keeper/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func createTestApp() *simapp.SimApp {
db := dbm.NewMemDB()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 5)
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5)
// init chain must be called to stop deliverState from being nil
genesisState := simapp.NewDefaultGenesisState()
stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState)
Expand Down
2 changes: 1 addition & 1 deletion x/gov/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestImportExportQueues(t *testing.T) {
}

db := dbm.NewMemDB()
app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0)
app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0)

app2.InitChain(
abci.RequestInitChain{
Expand Down
8 changes: 8 additions & 0 deletions x/upgrade/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ func BeginBlocker(k Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) {
upgradeMsg := fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info)
// We don't have an upgrade handler for this upgrade name, meaning this software is out of date so shutdown
ctx.Logger().Error(upgradeMsg)

// Write the upgrade info to disk. The UpgradeStoreLoader uses this info to perform or skip
// store migrations.
err := k.DumpUpgradeInfoToDisk(ctx.BlockHeight(), plan.Name)
if err != nil {
panic(fmt.Errorf("unable to write upgrade info to filesystem: %s", err.Error()))
}

panic(upgradeMsg)
}
// We have an upgrade handler for this upgrade name, so apply the upgrade
Expand Down
Loading

0 comments on commit 0b74491

Please sign in to comment.