From aa525418e152c55cb63a8e8af6d3ada484739af3 Mon Sep 17 00:00:00 2001 From: Joon Date: Wed, 18 Jul 2018 23:39:40 -0700 Subject: [PATCH] Merge PR #1373: Initialization of POS chain --- PENDING.md | 1 + baseapp/baseapp.go | 2 +- client/lcd/lcd_test.go | 21 +++++-------- cmd/gaia/app/app.go | 6 ++-- cmd/gaia/cmd/gaiadebug/hack.go | 6 ++-- server/init.go | 17 +++++----- x/gov/test_common.go | 6 ++-- x/slashing/app_test.go | 7 +++-- x/slashing/test_common.go | 2 +- x/stake/app_test.go | 6 ++-- x/stake/genesis.go | 19 +++++++++--- x/stake/genesis_test.go | 57 ++++++++++++++++++++++++++++++++-- x/stake/keeper/test_common.go | 4 +-- 13 files changed, 109 insertions(+), 45 deletions(-) diff --git a/PENDING.md b/PENDING.md index f297e6a4af6a..16ca3adc9326 100644 --- a/PENDING.md +++ b/PENDING.md @@ -6,6 +6,7 @@ BREAKING CHANGES FEATURES * [lcd] Can now query governance proposals by ProposalStatus +* [baseapp] Initialize validator set on ResponseInitChain * Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd * This allows SDK users to init a new project repository with a single command. diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index da75591a2c09..ca5e8fd97b8e 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -290,7 +290,7 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC if app.initChainer == nil { return } - app.initChainer(app.deliverState.ctx, req) // no error + res = app.initChainer(app.deliverState.ctx, req) // NOTE: we don't commit, but BeginBlock for block 1 // starts from this deliverState diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index f5b2d263ee18..2de92575a510 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -358,25 +358,20 @@ func TestTxs(t *testing.T) { } func TestValidatorsQuery(t *testing.T) { - cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.AccAddress{}) + cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}) defer cleanup() - require.Equal(t, 2, len(pks)) + require.Equal(t, 1, len(pks)) validators := getValidators(t, port) - require.Equal(t, len(validators), 2) + require.Equal(t, len(validators), 1) // make sure all the validators were found (order unknown because sorted by owner addr) - foundVal1, foundVal2 := false, false - pk1Bech := sdk.MustBech32ifyValPub(pks[0]) - pk2Bech := sdk.MustBech32ifyValPub(pks[1]) - if validators[0].PubKey == pk1Bech || validators[1].PubKey == pk1Bech { - foundVal1 = true + foundVal := false + pkBech := sdk.MustBech32ifyValPub(pks[0]) + if validators[0].PubKey == pkBech { + foundVal = true } - if validators[0].PubKey == pk2Bech || validators[1].PubKey == pk2Bech { - foundVal2 = true - } - require.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner) - require.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner) + require.True(t, foundVal, "pkBech %v, owner %v", pkBech, validators[0].Owner) } func TestBonding(t *testing.T) { diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 7b0f85e306c4..ab8a27e6c5d9 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -173,7 +173,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci } // load the initial stake information - err = stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) + validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) if err != nil { panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") @@ -181,7 +181,9 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci gov.InitGenesis(ctx, app.govKeeper, gov.DefaultGenesisState()) - return abci.ResponseInitChain{} + return abci.ResponseInitChain{ + Validators: validators, + } } // export the state of gaia for a genesis file diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 11d2dfa73004..aa3bc939eb7d 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -249,10 +249,12 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci } // load the initial stake information - err = stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) + validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) if err != nil { panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") } - return abci.ResponseInitChain{} + return abci.ResponseInitChain{ + Validators: validators, + } } diff --git a/server/init.go b/server/init.go index 39f3d0b7f89a..a644c0c1ae62 100644 --- a/server/init.go +++ b/server/init.go @@ -48,10 +48,9 @@ var ( // genesis piece structure for creating combined genesis type GenesisTx struct { - NodeID string `json:"node_id"` - IP string `json:"ip"` - Validator tmtypes.GenesisValidator `json:"validator"` - AppGenTx json.RawMessage `json:"app_gen_tx"` + NodeID string `json:"node_id"` + IP string `json:"ip"` + AppGenTx json.RawMessage `json:"app_gen_tx"` } // Storage for init command input parameters @@ -121,16 +120,15 @@ func gentxWithConfig(cdc *wire.Codec, appInit AppInit, config *cfg.Config, genTx nodeID := string(nodeKey.ID()) pubKey := readOrCreatePrivValidator(config) - appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) + appGenTx, cliPrint, _, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) if err != nil { return } tx := GenesisTx{ - NodeID: nodeID, - IP: genTxConfig.IP, - Validator: validator, - AppGenTx: appGenTx, + NodeID: nodeID, + IP: genTxConfig.IP, + AppGenTx: appGenTx, } bz, err := wire.MarshalJSONIndent(cdc, tx) if err != nil { @@ -312,7 +310,6 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec) ( genTx := genTxs[nodeID] // combine some stuff - validators = append(validators, genTx.Validator) appGenTxs = append(appGenTxs, genTx.AppGenTx) // Add a persistent peer diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 5567e4697a7f..7ea85fc72db6 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -61,12 +61,14 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk stakeGenesis := stake.DefaultGenesisState() stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) - err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) + validators, err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis) if err != nil { panic(err) } InitGenesis(ctx, keeper, DefaultGenesisState()) - return abci.ResponseInitChain{} + return abci.ResponseInitChain{ + Validators: validators, + } } } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index f5f8c98f8c88..8151c69daf5c 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -59,11 +59,14 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakeGenesis := stake.DefaultGenesisState() stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) - err := stake.InitGenesis(ctx, keeper, stakeGenesis) + validators, err := stake.InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) } - return abci.ResponseInitChain{} + + return abci.ResponseInitChain{ + Validators: validators, + } } } diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 19093299500a..142093c76826 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -70,7 +70,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para genesis.Pool.LooseTokens = sdk.NewRat(initCoins.MulRaw(int64(len(addrs))).Int64()) - err = stake.InitGenesis(ctx, sk, genesis) + _, err = stake.InitGenesis(ctx, sk, genesis) require.Nil(t, err) for _, addr := range addrs { diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 606369cd65bb..b1490edefb19 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -65,12 +65,14 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { stakeGenesis := DefaultGenesisState() stakeGenesis.Pool.LooseTokens = sdk.NewRat(100000) - err := InitGenesis(ctx, keeper, stakeGenesis) + validators, err := InitGenesis(ctx, keeper, stakeGenesis) if err != nil { panic(err) } - return abci.ResponseInitChain{} + return abci.ResponseInitChain{ + Validators: validators, + } } } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index b4ed80e51482..ad3ac0af5ab2 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -1,10 +1,12 @@ package stake import ( + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/pkg/errors" - tmtypes "github.com/tendermint/tendermint/types" ) // InitGenesis sets the pool and parameters for the provided keeper and @@ -12,7 +14,8 @@ import ( // validator in the keeper along with manually setting the indexes. In // addition, it also sets any delegations found in data. Finally, it updates // the bonded validators. -func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error { +// Returns final validator set after applying all declaration and delegations +func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.Validator, err error) { keeper.SetPool(ctx, data.Pool) keeper.SetNewParams(ctx, data.Params) keeper.InitIntraTxCounter(ctx) @@ -21,10 +24,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error keeper.SetValidator(ctx, validator) if validator.Tokens.IsZero() { - return errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator) + return res, errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator) } if validator.DelegatorShares.IsZero() { - return errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator) + return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator) } // Manually set indexes for the first time @@ -43,7 +46,13 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error } keeper.UpdateBondedValidatorsFull(ctx) - return nil + + vals := keeper.GetValidatorsBonded(ctx) + res = make([]abci.Validator, len(vals)) + for i, val := range vals { + res[i] = sdk.ABCIValidator(val) + } + return } // WriteGenesis returns a GenesisState for a given context and keeper. The diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index e27c7fed2c2c..ec061ea3c368 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -1,10 +1,13 @@ package stake import ( + "fmt" "testing" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" keep "github.com/cosmos/cosmos-sdk/x/stake/keeper" "github.com/cosmos/cosmos-sdk/x/stake/types" @@ -14,7 +17,7 @@ func TestInitGenesis(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewRat(2) + pool.BondedTokens = sdk.NewRat(2) params := keeper.GetParams(ctx) var delegations []Delegation @@ -24,17 +27,19 @@ func TestInitGenesis(t *testing.T) { NewValidator(keep.Addrs[1], keep.PKs[1], Description{Moniker: "bloop"}), } genesisState := types.NewGenesisState(pool, params, validators, delegations) - err := InitGenesis(ctx, keeper, genesisState) + _, err := InitGenesis(ctx, keeper, genesisState) require.Error(t, err) // initialize the validators + validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.OneRat() validators[0].DelegatorShares = sdk.OneRat() + validators[1].Status = sdk.Bonded validators[1].Tokens = sdk.OneRat() validators[1].DelegatorShares = sdk.OneRat() genesisState = types.NewGenesisState(pool, params, validators, delegations) - err = InitGenesis(ctx, keeper, genesisState) + vals, err := InitGenesis(ctx, keeper, genesisState) require.NoError(t, err) // now make sure the validators are bonded @@ -45,4 +50,50 @@ func TestInitGenesis(t *testing.T) { resVal, found = keeper.GetValidator(ctx, keep.Addrs[1]) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) + + abcivals := make([]abci.Validator, len(vals)) + for i, val := range validators { + abcivals[i] = sdk.ABCIValidator(val) + } + + require.Equal(t, abcivals, vals) +} + +func TestInitGenesisLargeValidatorSet(t *testing.T) { + size := 200 + require.True(t, size > 100) + + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + + // Assigning 2 to the first 100 vals, 1 to the rest + pool := keeper.GetPool(ctx) + pool.BondedTokens = sdk.NewRat(int64(200 + (size - 100))) + + params := keeper.GetParams(ctx) + delegations := []Delegation{} + validators := make([]Validator, size) + + for i := range validators { + validators[i] = NewValidator(keep.Addrs[i], keep.PKs[i], Description{Moniker: fmt.Sprintf("#%d", i)}) + + validators[i].Status = sdk.Bonded + if i < 100 { + validators[i].Tokens = sdk.NewRat(2) + validators[i].DelegatorShares = sdk.NewRat(2) + } else { + validators[i].Tokens = sdk.OneRat() + validators[i].DelegatorShares = sdk.OneRat() + } + } + + genesisState := types.NewGenesisState(pool, params, validators, delegations) + vals, err := InitGenesis(ctx, keeper, genesisState) + require.NoError(t, err) + + abcivals := make([]abci.Validator, 100) + for i, val := range validators[:100] { + abcivals[i] = sdk.ABCIValidator(val) + } + + require.Equal(t, abcivals, vals) } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index db7e382d5485..19cf4d27cc6c 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -23,8 +23,8 @@ import ( // dummy addresses used for testing var ( - Addrs = createTestAddrs(100) - PKs = createTestPubKeys(100) + Addrs = createTestAddrs(500) + PKs = createTestPubKeys(500) emptyAddr sdk.AccAddress emptyPubkey crypto.PubKey