Merge remote-tracking branch 'origin/develop' into rigel/fee-distribution
This commit is contained in:
@@ -16,7 +16,9 @@ type TxBuilder struct {
|
||||
Codec *wire.Codec
|
||||
AccountNumber int64
|
||||
Sequence int64
|
||||
Gas int64
|
||||
Gas int64 // TODO: should this turn into uint64? requires further discussion - see #2173
|
||||
GasAdjustment float64
|
||||
SimulateGas bool
|
||||
ChainID string
|
||||
Memo string
|
||||
Fee string
|
||||
@@ -36,9 +38,11 @@ func NewTxBuilderFromCLI() TxBuilder {
|
||||
|
||||
return TxBuilder{
|
||||
ChainID: chainID,
|
||||
Gas: viper.GetInt64(client.FlagGas),
|
||||
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
|
||||
Gas: client.GasFlagVar.Gas,
|
||||
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
|
||||
Sequence: viper.GetInt64(client.FlagSequence),
|
||||
SimulateGas: client.GasFlagVar.Simulate,
|
||||
Fee: viper.GetString(client.FlagFee),
|
||||
Memo: viper.GetString(client.FlagMemo),
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func getBenchmarkMockApp() (*mock.App, error) {
|
||||
bankKeeper := NewBaseKeeper(mapp.AccountMapper)
|
||||
mapp.Router().AddRoute("bank", NewHandler(bankKeeper))
|
||||
|
||||
err := mapp.CompleteSetup([]*sdk.KVStoreKey{})
|
||||
err := mapp.CompleteSetup()
|
||||
return mapp, err
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type sendBody struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
@@ -81,31 +81,37 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
||||
return
|
||||
}
|
||||
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
Gas: m.Gas,
|
||||
ChainID: m.ChainID,
|
||||
AccountNumber: m.AccountNumber,
|
||||
Sequence: m.Sequence,
|
||||
simulateGas, gas, err := cliclient.ReadGasFlag(m.Gas)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, cliclient.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
Gas: gas,
|
||||
GasAdjustment: adjustment,
|
||||
SimulateGas: simulateGas,
|
||||
ChainID: m.ChainID,
|
||||
AccountNumber: m.AccountNumber,
|
||||
Sequence: m.Sequence,
|
||||
}
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
|
||||
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txBldr.Gas)
|
||||
utils.WriteSimulationResponse(w, newBldr.Gas)
|
||||
return
|
||||
}
|
||||
txBldr = newCtx
|
||||
txBldr = newBldr
|
||||
}
|
||||
|
||||
if utils.HasGenerateOnlyArg(r) {
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestBankWithRandomMessages(t *testing.T) {
|
||||
bankKeeper := bank.NewBaseKeeper(mapper)
|
||||
mapp.Router().AddRoute("bank", bank.NewHandler(bankKeeper))
|
||||
|
||||
err := mapp.CompleteSetup([]*sdk.KVStoreKey{})
|
||||
err := mapp.CompleteSetup()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -33,8 +33,8 @@ func TestBankWithRandomMessages(t *testing.T) {
|
||||
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.Operation{
|
||||
SimulateSingleInputMsgSend(mapper),
|
||||
[]simulation.WeightedOperation{
|
||||
{1, SimulateSingleInputMsgSend(mapper)},
|
||||
},
|
||||
[]simulation.RandSetup{},
|
||||
[]simulation.Invariant{
|
||||
|
||||
+18
-13
@@ -20,7 +20,7 @@ type baseReq struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
@@ -69,32 +69,37 @@ func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
|
||||
// TODO: Build this function out into a more generic base-request
|
||||
// (probably should live in client/lcd).
|
||||
func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
|
||||
var err error
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
AccountNumber: baseReq.AccountNumber,
|
||||
Sequence: baseReq.Sequence,
|
||||
ChainID: baseReq.ChainID,
|
||||
Gas: baseReq.Gas,
|
||||
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
Gas: gas,
|
||||
GasAdjustment: adjustment,
|
||||
SimulateGas: simulateGas,
|
||||
ChainID: baseReq.ChainID,
|
||||
AccountNumber: baseReq.AccountNumber,
|
||||
Sequence: baseReq.Sequence,
|
||||
}
|
||||
|
||||
if utils.HasDryRunArg(r) || baseReq.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, []sdk.Msg{msg})
|
||||
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
|
||||
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txBldr.Gas)
|
||||
utils.WriteSimulationResponse(w, newBldr.Gas)
|
||||
return
|
||||
}
|
||||
txBldr = newCtx
|
||||
txBldr = newBldr
|
||||
}
|
||||
|
||||
if utils.HasGenerateOnlyArg(r) {
|
||||
|
||||
+10
-4
@@ -114,8 +114,14 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
||||
resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
|
||||
resTags.AppendTag(tags.ProposalID, proposalIDBytes)
|
||||
|
||||
logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - didn't mean minimum deposit (had only %s), deleted",
|
||||
inactiveProposal.GetProposalID(), inactiveProposal.GetTitle(), inactiveProposal.GetTotalDeposit()))
|
||||
logger.Info(
|
||||
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %v steak (had only %v steak); deleted",
|
||||
inactiveProposal.GetProposalID(),
|
||||
inactiveProposal.GetTitle(),
|
||||
keeper.GetDepositProcedure(ctx).MinDeposit.AmountOf("steak"),
|
||||
inactiveProposal.GetTotalDeposit().AmountOf("steak"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Check if earliest Active Proposal ended voting period yet
|
||||
@@ -143,7 +149,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
||||
activeProposal.SetTallyResult(tallyResults)
|
||||
keeper.SetProposal(ctx, activeProposal)
|
||||
|
||||
logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - tallied, passed: %v",
|
||||
logger.Info(fmt.Sprintf("proposal %d (%s) tallied; passed: %v",
|
||||
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes))
|
||||
|
||||
for _, valAddr := range nonVotingVals {
|
||||
@@ -154,7 +160,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
||||
val.GetPower().RoundInt64(),
|
||||
keeper.GetTallyingProcedure(ctx).GovernancePenalty)
|
||||
|
||||
logger.Info(fmt.Sprintf("Validator %s failed to vote on proposal %d, slashing",
|
||||
logger.Info(fmt.Sprintf("validator %s failed to vote on proposal %d; slashing",
|
||||
val.GetOperator(), activeProposal.GetProposalID()))
|
||||
}
|
||||
|
||||
|
||||
+23
-12
@@ -8,22 +8,33 @@ import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// query endpoints supported by the governance Querier
|
||||
const (
|
||||
QueryProposals = "proposals"
|
||||
QueryProposal = "proposal"
|
||||
QueryDeposits = "deposits"
|
||||
QueryDeposit = "deposit"
|
||||
QueryVotes = "votes"
|
||||
QueryVote = "vote"
|
||||
QueryTally = "tally"
|
||||
)
|
||||
|
||||
func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) {
|
||||
switch path[0] {
|
||||
case "proposal":
|
||||
return queryProposal(ctx, path[1:], req, keeper)
|
||||
case "deposit":
|
||||
return queryDeposit(ctx, path[1:], req, keeper)
|
||||
case "vote":
|
||||
return queryVote(ctx, path[1:], req, keeper)
|
||||
case "deposits":
|
||||
return queryDeposits(ctx, path[1:], req, keeper)
|
||||
case "votes":
|
||||
return queryVotes(ctx, path[1:], req, keeper)
|
||||
case "proposals":
|
||||
case QueryProposals:
|
||||
return queryProposals(ctx, path[1:], req, keeper)
|
||||
case "tally":
|
||||
case QueryProposal:
|
||||
return queryProposal(ctx, path[1:], req, keeper)
|
||||
case QueryDeposits:
|
||||
return queryDeposits(ctx, path[1:], req, keeper)
|
||||
case QueryDeposit:
|
||||
return queryDeposit(ctx, path[1:], req, keeper)
|
||||
case QueryVotes:
|
||||
return queryVotes(ctx, path[1:], req, keeper)
|
||||
case QueryVote:
|
||||
return queryVote(ctx, path[1:], req, keeper)
|
||||
case QueryTally:
|
||||
return queryTally(ctx, path[1:], req, keeper)
|
||||
default:
|
||||
return nil, sdk.ErrUnknownRequest("unknown gov query endpoint")
|
||||
|
||||
@@ -156,13 +156,16 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||
return operationSimulateMsgVote(k, sk, nil, -1)
|
||||
}
|
||||
|
||||
|
||||
// nolint: unparam
|
||||
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
if key == nil {
|
||||
key = simulation.RandomKey(r, keys)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
|
||||
if proposalID < 0 {
|
||||
proposalID, ok = randomProposalID(r, k, ctx)
|
||||
if !ok {
|
||||
@@ -171,15 +174,18 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey,
|
||||
}
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
option := randomVotingOption(r)
|
||||
|
||||
msg := gov.NewMsgVote(addr, proposalID, option)
|
||||
if msg.ValidateBasic() != nil {
|
||||
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||
}
|
||||
|
||||
ctx, write := ctx.CacheContext()
|
||||
result := gov.NewHandler(k)(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
||||
event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK()))
|
||||
action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
|
||||
return action, nil, nil
|
||||
|
||||
@@ -26,7 +26,8 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||
mapper := mapp.AccountMapper
|
||||
bankKeeper := bank.NewBaseKeeper(mapper)
|
||||
stakeKey := sdk.NewKVStoreKey("stake")
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, bankKeeper, stake.DefaultCodespace)
|
||||
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, stake.DefaultCodespace)
|
||||
paramKey := sdk.NewKVStoreKey("params")
|
||||
paramKeeper := params.NewKeeper(mapp.Cdc, paramKey)
|
||||
govKey := sdk.NewKVStoreKey("gov")
|
||||
@@ -37,7 +38,7 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||
return abci.ResponseEndBlock{}
|
||||
})
|
||||
|
||||
err := mapp.CompleteSetup([]*sdk.KVStoreKey{stakeKey, paramKey, govKey})
|
||||
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramKey, govKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -56,10 +57,10 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||
// Test with unscheduled votes
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.Operation{
|
||||
SimulateMsgSubmitProposal(govKeeper, stakeKeeper),
|
||||
SimulateMsgDeposit(govKeeper, stakeKeeper),
|
||||
SimulateMsgVote(govKeeper, stakeKeeper),
|
||||
[]simulation.WeightedOperation{
|
||||
{2, SimulateMsgSubmitProposal(govKeeper, stakeKeeper)},
|
||||
{3, SimulateMsgDeposit(govKeeper, stakeKeeper)},
|
||||
{20, SimulateMsgVote(govKeeper, stakeKeeper)},
|
||||
}, []simulation.RandSetup{
|
||||
setup,
|
||||
}, []simulation.Invariant{
|
||||
@@ -71,9 +72,9 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||
// Test with scheduled votes
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.Operation{
|
||||
SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper),
|
||||
SimulateMsgDeposit(govKeeper, stakeKeeper),
|
||||
[]simulation.WeightedOperation{
|
||||
{10, SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper)},
|
||||
{5, SimulateMsgDeposit(govKeeper, stakeKeeper)},
|
||||
}, []simulation.RandSetup{
|
||||
setup,
|
||||
}, []simulation.Invariant{
|
||||
|
||||
@@ -28,18 +28,19 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper,
|
||||
|
||||
keyGlobalParams := sdk.NewKVStoreKey("params")
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
keyGov := sdk.NewKVStoreKey("gov")
|
||||
|
||||
pk := params.NewKeeper(mapp.Cdc, keyGlobalParams)
|
||||
ck := bank.NewBaseKeeper(mapp.AccountMapper)
|
||||
sk := stake.NewKeeper(mapp.Cdc, keyStake, ck, mapp.RegisterCodespace(stake.DefaultCodespace))
|
||||
sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, mapp.RegisterCodespace(stake.DefaultCodespace))
|
||||
keeper := NewKeeper(mapp.Cdc, keyGov, pk.Setter(), ck, sk, DefaultCodespace)
|
||||
mapp.Router().AddRoute("gov", NewHandler(keeper))
|
||||
|
||||
mapp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mapp.SetInitChainer(getInitChainer(mapp, keeper, sk))
|
||||
|
||||
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keyGov, keyGlobalParams}))
|
||||
require.NoError(t, mapp.CompleteSetup(keyStake, keyGov, keyGlobalParams, tkeyStake))
|
||||
|
||||
genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin("steak", 42)})
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ func getMockApp(t *testing.T) *mock.App {
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
|
||||
mapp.Router().AddRoute("ibc", NewHandler(ibcMapper, bankKeeper))
|
||||
|
||||
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyIBC}))
|
||||
require.NoError(t, mapp.CompleteSetup(keyIBC))
|
||||
return mapp
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ type transferBody struct {
|
||||
SrcChainID string `json:"src_chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
@@ -71,21 +71,26 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
||||
packet := ibc.NewIBCPacket(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount, m.SrcChainID, destChainID)
|
||||
msg := ibc.IBCTransferMsg{packet}
|
||||
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
ChainID: m.SrcChainID,
|
||||
AccountNumber: m.AccountNumber,
|
||||
Sequence: m.Sequence,
|
||||
Gas: m.Gas,
|
||||
simulateGas, gas, err := client.ReadGasFlag(m.Gas)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
Gas: gas,
|
||||
GasAdjustment: adjustment,
|
||||
SimulateGas: simulateGas,
|
||||
ChainID: m.SrcChainID,
|
||||
AccountNumber: m.AccountNumber,
|
||||
Sequence: m.Sequence,
|
||||
}
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
|
||||
+13
-2
@@ -1,6 +1,7 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
@@ -75,11 +76,21 @@ func NewApp() *App {
|
||||
|
||||
// CompleteSetup completes the application setup after the routes have been
|
||||
// registered.
|
||||
func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
|
||||
func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error {
|
||||
newKeys = append(newKeys, app.KeyMain)
|
||||
newKeys = append(newKeys, app.KeyAccount)
|
||||
|
||||
app.MountStoresIAVL(newKeys...)
|
||||
for _, key := range newKeys {
|
||||
switch key.(type) {
|
||||
case *sdk.KVStoreKey:
|
||||
app.MountStore(key, sdk.StoreTypeIAVL)
|
||||
case *sdk.TransientStoreKey:
|
||||
app.MountStore(key, sdk.StoreTypeTransient)
|
||||
default:
|
||||
return fmt.Errorf("unsupported StoreKey: %+v", key)
|
||||
}
|
||||
}
|
||||
|
||||
err := app.LoadLatestVersion(app.KeyMain)
|
||||
|
||||
return err
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ func getMockApp(t *testing.T) *App {
|
||||
mApp := NewApp()
|
||||
|
||||
mApp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
|
||||
require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{}))
|
||||
require.NoError(t, mApp.CompleteSetup())
|
||||
|
||||
return mApp
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -23,12 +24,13 @@ import (
|
||||
)
|
||||
|
||||
// Simulate tests application by sending random messages.
|
||||
func Simulate(
|
||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []Operation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||
) {
|
||||
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage,
|
||||
ops []WeightedOperation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool) error {
|
||||
|
||||
time := time.Now().UnixNano()
|
||||
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
||||
return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
||||
}
|
||||
|
||||
func initChain(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress, setups []RandSetup, app *baseapp.BaseApp,
|
||||
@@ -53,10 +55,13 @@ func randTimestamp(r *rand.Rand) time.Time {
|
||||
|
||||
// SimulateFromSeed tests an application by running the provided
|
||||
// operations, testing the provided invariants, but using the provided seed.
|
||||
func SimulateFromSeed(
|
||||
tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||
) {
|
||||
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage,
|
||||
seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant,
|
||||
numBlocks int, blockSize int, commit bool) (simError error) {
|
||||
|
||||
// in case we have to end early, don't os.Exit so that we can run cleanup code.
|
||||
stopEarly := false
|
||||
testingMode, t, b := getTestingMode(tb)
|
||||
fmt.Printf("Starting SimulateFromSeed with randomness created with seed %d\n", int(seed))
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
@@ -79,12 +84,12 @@ func SimulateFromSeed(
|
||||
|
||||
// Setup code to catch SIGTERM's
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
<-c
|
||||
fmt.Printf("Exiting early due to SIGTERM, on block %d, operation %d\n", header.Height, opCount)
|
||||
DisplayEvents(events)
|
||||
os.Exit(128 + int(syscall.SIGTERM))
|
||||
receivedSignal := <-c
|
||||
fmt.Printf("Exiting early due to %s, on block %d, operation %d\n", receivedSignal, header.Height, opCount)
|
||||
simError = fmt.Errorf("Exited due to %s", receivedSignal)
|
||||
stopEarly = true
|
||||
}()
|
||||
|
||||
var pastTimes []time.Time
|
||||
@@ -95,15 +100,27 @@ func SimulateFromSeed(
|
||||
operationQueue := make(map[int][]Operation)
|
||||
var blockLogBuilders []*strings.Builder
|
||||
|
||||
if !testingMode {
|
||||
b.ResetTimer()
|
||||
} else {
|
||||
if testingMode {
|
||||
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
||||
}
|
||||
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
||||
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks, displayLogs)
|
||||
if !testingMode {
|
||||
b.ResetTimer()
|
||||
} else {
|
||||
// Recover logs in case of panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Panic with err\n", r)
|
||||
stackTrace := string(debug.Stack())
|
||||
fmt.Println(stackTrace)
|
||||
displayLogs()
|
||||
simError = fmt.Errorf("Simulation halted due to panic on block %d", header.Height)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < numBlocks; i++ {
|
||||
for i := 0; i < numBlocks && !stopEarly; i++ {
|
||||
// Log the header time for future lookup
|
||||
pastTimes = append(pastTimes, header.Time)
|
||||
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
|
||||
@@ -122,10 +139,9 @@ func SimulateFromSeed(
|
||||
|
||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event)
|
||||
opCount += numQueuedOpsRan
|
||||
thisBlockSize -= numQueuedOpsRan
|
||||
operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter)
|
||||
opCount += operations
|
||||
opCount += operations + numQueuedOpsRan
|
||||
|
||||
res := app.EndBlock(abci.RequestEndBlock{})
|
||||
header.Height++
|
||||
@@ -146,19 +162,38 @@ func SimulateFromSeed(
|
||||
// Update the validator set
|
||||
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
|
||||
}
|
||||
|
||||
if stopEarly {
|
||||
DisplayEvents(events)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount)
|
||||
DisplayEvents(events)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
||||
// memory overhead
|
||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []Operation, operationQueue map[int][]Operation, totalNumBlocks int, displayLogs func()) func(
|
||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []WeightedOperation, operationQueue map[int][]Operation, totalNumBlocks int, displayLogs func()) func(
|
||||
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
|
||||
totalOpWeight := 0
|
||||
for i := 0; i < len(ops); i++ {
|
||||
totalOpWeight += ops[i].Weight
|
||||
}
|
||||
selectOp := func(r *rand.Rand) Operation {
|
||||
x := r.Intn(totalOpWeight)
|
||||
for i := 0; i < len(ops); i++ {
|
||||
if x <= ops[i].Weight {
|
||||
return ops[i].Op
|
||||
}
|
||||
x -= ops[i].Weight
|
||||
}
|
||||
// shouldn't happen
|
||||
return ops[0].Op
|
||||
}
|
||||
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
|
||||
for j := 0; j < blocksize; j++ {
|
||||
logUpdate, futureOps, err := ops[r.Intn(len(ops))](r, app, ctx, keys, event)
|
||||
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, keys, event)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err)
|
||||
@@ -324,18 +359,14 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
|
||||
// updateValidators mimicks Tendermint's update logic
|
||||
// nolint: unparam
|
||||
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
|
||||
|
||||
for _, update := range updates {
|
||||
switch {
|
||||
case update.Power == 0:
|
||||
// // TEMPORARY DEBUG CODE TO PROVE THAT THE OLD METHOD WAS BROKEN
|
||||
// // (i.e. didn't catch in the event of problem)
|
||||
// if val, ok := tb.(*testing.T); ok {
|
||||
// require.NotNil(val, current[string(update.PubKey.Data)])
|
||||
// }
|
||||
// // CORRECT CHECK
|
||||
// if _, ok := current[string(update.PubKey.Data)]; !ok {
|
||||
// tb.Fatalf("tried to delete a nonexistent validator")
|
||||
// }
|
||||
if _, ok := current[string(update.PubKey.Data)]; !ok {
|
||||
tb.Fatalf("tried to delete a nonexistent validator")
|
||||
}
|
||||
|
||||
event("endblock/validatorupdates/kicked")
|
||||
delete(current, string(update.PubKey.Data))
|
||||
default:
|
||||
@@ -350,5 +381,6 @@ func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValida
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
@@ -47,6 +47,13 @@ type (
|
||||
BlockHeight int
|
||||
Op Operation
|
||||
}
|
||||
|
||||
// WeightedOperation is an operation with associated weight.
|
||||
// This is used to bias the selection operation within the simulator.
|
||||
WeightedOperation struct {
|
||||
Weight int
|
||||
Op Operation
|
||||
}
|
||||
)
|
||||
|
||||
// PeriodicInvariant returns an Invariant function closure that asserts
|
||||
|
||||
@@ -3,9 +3,11 @@ package simulation
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
@@ -94,13 +96,34 @@ func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, invariants []Invari
|
||||
func logPrinter(testingmode bool, logs []*strings.Builder) func() {
|
||||
if testingmode {
|
||||
return func() {
|
||||
numLoggers := 0
|
||||
for i := 0; i < len(logs); i++ {
|
||||
// We're passed the last created block
|
||||
if logs[i] == nil {
|
||||
return
|
||||
numLoggers = i - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
var f *os.File
|
||||
if numLoggers > 10 {
|
||||
fileName := fmt.Sprintf("simulation_log_%s.txt", time.Now().Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf("Too many logs to display, instead writing to %s\n", fileName)
|
||||
f, _ = os.Create(fileName)
|
||||
}
|
||||
for i := 0; i < numLoggers; i++ {
|
||||
if f != nil {
|
||||
_, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i))
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
_, err = f.WriteString((*logs[i]).String())
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Begin block %d\n", i)
|
||||
fmt.Println((*logs[i]).String())
|
||||
}
|
||||
fmt.Printf("Begin block %d\n", i)
|
||||
fmt.Println((*logs[i]).String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,12 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) {
|
||||
|
||||
RegisterWire(mapp.Cdc)
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
keySlashing := sdk.NewKVStoreKey("slashing")
|
||||
keyParams := sdk.NewKVStoreKey("params")
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
|
||||
paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams)
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, bankKeeper, mapp.RegisterCodespace(stake.DefaultCodespace))
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, bankKeeper, mapp.RegisterCodespace(stake.DefaultCodespace))
|
||||
|
||||
keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, paramsKeeper.Getter(), mapp.RegisterCodespace(DefaultCodespace))
|
||||
mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
|
||||
@@ -38,7 +39,7 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) {
|
||||
|
||||
mapp.SetEndBlocker(getEndBlocker(stakeKeeper))
|
||||
mapp.SetInitChainer(getInitChainer(mapp, stakeKeeper))
|
||||
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keySlashing, keyParams}))
|
||||
require.NoError(t, mapp.CompleteSetup(keyStake, keySlashing, keyParams, tkeyStake))
|
||||
|
||||
return mapp, stakeKeeper, keeper
|
||||
}
|
||||
|
||||
@@ -70,22 +70,20 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
|
||||
return
|
||||
}
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
ChainID: m.ChainID,
|
||||
AccountNumber: m.AccountNumber,
|
||||
Sequence: m.Sequence,
|
||||
Gas: m.Gas,
|
||||
GasAdjustment: adjustment,
|
||||
}
|
||||
|
||||
msg := slashing.NewMsgUnjail(valAddr)
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
|
||||
@@ -52,11 +52,13 @@ func createTestCodec() *wire.Codec {
|
||||
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, params.Setter, Keeper) {
|
||||
keyAcc := sdk.NewKVStoreKey("acc")
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
keySlashing := sdk.NewKVStoreKey("slashing")
|
||||
keyParams := sdk.NewKVStoreKey("params")
|
||||
db := dbm.NewMemDB()
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
@@ -67,7 +69,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
|
||||
ck := bank.NewBaseKeeper(accountMapper)
|
||||
params := params.NewKeeper(cdc, keyParams)
|
||||
sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace)
|
||||
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, stake.DefaultCodespace)
|
||||
genesis := stake.DefaultGenesisState()
|
||||
|
||||
genesis.Pool.LooseTokens = sdk.NewDec(initCoins.MulRaw(int64(len(addrs))).Int64())
|
||||
|
||||
+3
-2
@@ -34,14 +34,15 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) {
|
||||
RegisterWire(mApp.Cdc)
|
||||
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
bankKeeper := bank.NewBaseKeeper(mApp.AccountMapper)
|
||||
keeper := NewKeeper(mApp.Cdc, keyStake, bankKeeper, mApp.RegisterCodespace(DefaultCodespace))
|
||||
keeper := NewKeeper(mApp.Cdc, keyStake, tkeyStake, bankKeeper, mApp.RegisterCodespace(DefaultCodespace))
|
||||
|
||||
mApp.Router().AddRoute("stake", NewHandler(keeper))
|
||||
mApp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper))
|
||||
|
||||
require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
|
||||
require.NoError(t, mApp.CompleteSetup(keyStake, tkeyStake))
|
||||
return mApp, keeper
|
||||
}
|
||||
|
||||
|
||||
+19
-15
@@ -60,7 +60,7 @@ type EditDelegationsBody struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
Delegations []msgDelegationsInput `json:"delegations"`
|
||||
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
|
||||
@@ -263,10 +263,21 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
||||
i++
|
||||
}
|
||||
|
||||
simulateGas, gas, err := client.ReadGasFlag(m.Gas)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
txBldr := authtxb.TxBuilder{
|
||||
Codec: cdc,
|
||||
ChainID: m.ChainID,
|
||||
Gas: m.Gas,
|
||||
Codec: cdc,
|
||||
Gas: gas,
|
||||
GasAdjustment: adjustment,
|
||||
SimulateGas: simulateGas,
|
||||
ChainID: m.ChainID,
|
||||
}
|
||||
|
||||
// sign messages
|
||||
@@ -275,26 +286,19 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
||||
// increment sequence for each message
|
||||
txBldr = txBldr.WithAccountNumber(m.AccountNumber)
|
||||
txBldr = txBldr.WithSequence(m.Sequence)
|
||||
|
||||
m.Sequence++
|
||||
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
|
||||
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txBldr.Gas)
|
||||
utils.WriteSimulationResponse(w, newBldr.Gas)
|
||||
return
|
||||
}
|
||||
txBldr = newCtx
|
||||
txBldr = newBldr
|
||||
}
|
||||
|
||||
if utils.HasGenerateOnlyArg(r) {
|
||||
|
||||
+1
-2
@@ -52,8 +52,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid
|
||||
k.SetIntraTxCounter(ctx, 0)
|
||||
|
||||
// calculate validator set changes
|
||||
ValidatorUpdates = k.GetTendermintUpdates(ctx)
|
||||
k.ClearTendermintUpdates(ctx)
|
||||
ValidatorUpdates = k.GetValidTendermintUpdates(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
This document provided a bit more insight as to the purpose of several related
|
||||
prefixed areas of the staking store which are accessed in `x/stake/keeper.go`.
|
||||
|
||||
# IAVL Store
|
||||
|
||||
## Validators
|
||||
- Prefix Key Space: ValidatorsKey
|
||||
@@ -36,10 +37,13 @@ prefixed areas of the staking store which are accessed in `x/stake/keeper.go`.
|
||||
through this set to determine who we've kicked out.
|
||||
retrieving validator by tendermint index
|
||||
|
||||
# Transient Store
|
||||
|
||||
The transient store persists between transations but not between blocks
|
||||
|
||||
## Tendermint Updates
|
||||
- Prefix Key Space: TendermintUpdatesKey
|
||||
- Prefix Key Space: TendermintUpdatesTKey
|
||||
- Key/Sort: Validator Operator Address
|
||||
- Value: Tendermint ABCI Validator
|
||||
- Contains: Validators are queued to affect the consensus validation set in Tendermint
|
||||
- Used For: Informing Tendermint of the validator set updates, is used only intra-block, as the
|
||||
updates are applied then cleared on endblock
|
||||
- Used For: Informing Tendermint of the validator set updates
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
// keeper of the stake store
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
storeTKey sdk.StoreKey
|
||||
cdc *wire.Codec
|
||||
bankKeeper bank.Keeper
|
||||
validatorHooks sdk.ValidatorHooks
|
||||
@@ -19,9 +20,10 @@ type Keeper struct {
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
|
||||
func NewKeeper(cdc *wire.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
|
||||
keeper := Keeper{
|
||||
storeKey: key,
|
||||
storeTKey: tkey,
|
||||
cdc: cdc,
|
||||
bankKeeper: ck,
|
||||
validatorHooks: nil,
|
||||
|
||||
+12
-10
@@ -22,14 +22,16 @@ var (
|
||||
ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power
|
||||
ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator
|
||||
ValidatorPowerCliffKey = []byte{0x07} // key for the power of the validator on the cliff
|
||||
TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated
|
||||
IntraTxCounterKey = []byte{0x09} // key for intra-block tx index
|
||||
DelegationKey = []byte{0x0A} // key for a delegation
|
||||
UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation
|
||||
UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator operator
|
||||
RedelegationKey = []byte{0x0D} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by source validator operator
|
||||
RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by destination validator operator
|
||||
IntraTxCounterKey = []byte{0x08} // key for intra-block tx index
|
||||
DelegationKey = []byte{0x09} // key for a delegation
|
||||
UnbondingDelegationKey = []byte{0x0A} // key for an unbonding-delegation
|
||||
UnbondingDelegationByValIndexKey = []byte{0x0B} // prefix for each key for an unbonding-delegation, by validator operator
|
||||
RedelegationKey = []byte{0x0C} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0D} // prefix for each key for an redelegation, by source validator operator
|
||||
RedelegationByValDstIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by destination validator operator
|
||||
|
||||
// Keys for store prefixes (transient)
|
||||
TendermintUpdatesTKey = []byte{0x00} // prefix for each key to a validator which is being updated
|
||||
)
|
||||
|
||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||
@@ -98,8 +100,8 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
||||
// get the key for the accumulated update validators
|
||||
// VALUE: abci.Validator
|
||||
// note records using these keys should never persist between blocks
|
||||
func GetTendermintUpdatesKey(operatorAddr sdk.ValAddress) []byte {
|
||||
return append(TendermintUpdatesKey, operatorAddr.Bytes()...)
|
||||
func GetTendermintUpdatesTKey(operatorAddr sdk.ValAddress) []byte {
|
||||
return append(TendermintUpdatesTKey, operatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
//______________________________________________________________________________
|
||||
|
||||
+16
-8
@@ -28,7 +28,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
|
||||
if slashFactor.LT(sdk.ZeroDec()) {
|
||||
panic(fmt.Errorf("attempted to slash with a negative slashFactor: %v", slashFactor))
|
||||
panic(fmt.Errorf("attempted to slash with a negative slash factor: %v", slashFactor))
|
||||
}
|
||||
|
||||
// Amount of slashing = slash slashFactor * power at time of infraction
|
||||
@@ -50,7 +50,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
||||
|
||||
// should not be slashing unbonded
|
||||
if validator.IsUnbonded(ctx) {
|
||||
panic(fmt.Sprintf("should not be slashing unbonded validator: %v", validator))
|
||||
panic(fmt.Sprintf("should not be slashing unbonded validator: %s", validator.GetOperator()))
|
||||
}
|
||||
|
||||
operatorAddress := validator.GetOperator()
|
||||
@@ -72,7 +72,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
||||
|
||||
// Special-case slash at current height for efficiency - we don't need to look through unbonding delegations or redelegations
|
||||
logger.Info(fmt.Sprintf(
|
||||
"Slashing at current height %d, not scanning unbonding delegations & redelegations",
|
||||
"slashing at current height %d, not scanning unbonding delegations & redelegations",
|
||||
infractionHeight))
|
||||
|
||||
case infractionHeight < ctx.BlockHeight():
|
||||
@@ -117,8 +117,8 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
||||
|
||||
// Log that a slash occurred!
|
||||
logger.Info(fmt.Sprintf(
|
||||
"Validator %s slashed by slashFactor %s, burned %v tokens",
|
||||
pubkey.Address(), slashFactor.String(), tokensToBurn))
|
||||
"validator %s slashed by slash factor of %s; burned %v tokens",
|
||||
validator.GetOperator(), slashFactor.String(), tokensToBurn))
|
||||
|
||||
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
|
||||
return
|
||||
@@ -127,8 +127,12 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
||||
// jail a validator
|
||||
func (k Keeper) Jail(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
k.setJailed(ctx, pubkey, true)
|
||||
validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String())
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
logger.Info(fmt.Sprintf("Validator %s jailed", pubkey.Address()))
|
||||
logger.Info(fmt.Sprintf("validator %s jailed", validatorAddr))
|
||||
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
|
||||
return
|
||||
}
|
||||
@@ -136,8 +140,12 @@ func (k Keeper) Jail(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
// unjail a validator
|
||||
func (k Keeper) Unjail(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
k.setJailed(ctx, pubkey, false)
|
||||
validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String())
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
logger.Info(fmt.Sprintf("Validator %s unjailed", pubkey.Address()))
|
||||
logger.Info(fmt.Sprintf("validator %s unjailed", validatorAddr))
|
||||
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
|
||||
return
|
||||
}
|
||||
@@ -146,7 +154,7 @@ func (k Keeper) Unjail(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
func (k Keeper) setJailed(ctx sdk.Context, pubkey crypto.PubKey, isJailed bool) {
|
||||
validator, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||
if !found {
|
||||
panic(fmt.Errorf("Validator with pubkey %s not found, cannot set jailed to %v", pubkey, isJailed))
|
||||
panic(fmt.Errorf("validator with pubkey %s not found, cannot set jailed to %v", pubkey, isJailed))
|
||||
}
|
||||
validator.Jailed = isJailed
|
||||
k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it
|
||||
|
||||
@@ -90,10 +90,12 @@ func ParamsNoInflation() types.Params {
|
||||
func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) {
|
||||
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
keyAcc := sdk.NewKVStoreKey("acc")
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||
err := ms.LoadLatestVersion()
|
||||
@@ -107,7 +109,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||
auth.ProtoBaseAccount, // prototype
|
||||
)
|
||||
ck := bank.NewBaseKeeper(accountMapper)
|
||||
keeper := NewKeeper(cdc, keyStake, ck, types.DefaultCodespace)
|
||||
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, types.DefaultCodespace)
|
||||
keeper.SetPool(ctx, types.InitialPool())
|
||||
keeper.SetNewParams(ctx, types.DefaultParams())
|
||||
keeper.InitIntraTxCounter(ctx)
|
||||
|
||||
+78
-71
@@ -158,9 +158,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
|
||||
}
|
||||
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
||||
}
|
||||
ensureValidatorFound(found, address)
|
||||
|
||||
validators[i] = validator
|
||||
i++
|
||||
@@ -184,9 +182,8 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
}
|
||||
address := iterator.Value()
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
||||
}
|
||||
ensureValidatorFound(found, address)
|
||||
|
||||
if validator.Status == sdk.Bonded {
|
||||
validators[i] = validator
|
||||
i++
|
||||
@@ -201,32 +198,41 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
// Accumulated updates to the active/bonded validator set for tendermint
|
||||
|
||||
// get the most recently updated validators
|
||||
func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
//
|
||||
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
||||
// at the previous block height or were removed from the validator set entirely
|
||||
// are returned to Tendermint.
|
||||
func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
|
||||
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey) //smallest to largest
|
||||
iterator := sdk.KVStorePrefixIterator(tstore, TendermintUpdatesTKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
valBytes := iterator.Value()
|
||||
var val abci.Validator
|
||||
k.cdc.MustUnmarshalBinary(valBytes, &val)
|
||||
updates = append(updates, val)
|
||||
var abciVal abci.Validator
|
||||
|
||||
abciValBytes := iterator.Value()
|
||||
k.cdc.MustUnmarshalBinary(abciValBytes, &abciVal)
|
||||
|
||||
val, found := k.GetValidator(ctx, abciVal.GetAddress())
|
||||
if found {
|
||||
// The validator is new or already exists in the store and must adhere to
|
||||
// Tendermint invariants.
|
||||
prevBonded := val.BondHeight < ctx.BlockHeight() && val.BondHeight > val.UnbondingHeight
|
||||
zeroPower := val.GetPower().Equal(sdk.ZeroDec())
|
||||
|
||||
if !zeroPower || zeroPower && prevBonded {
|
||||
updates = append(updates, abciVal)
|
||||
}
|
||||
} else {
|
||||
// Add the ABCI validator in such a case where the validator was removed
|
||||
// from the store as it must have existed before.
|
||||
updates = append(updates, abciVal)
|
||||
}
|
||||
}
|
||||
|
||||
iterator.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// remove all validator update entries after applied to Tendermint
|
||||
func (k Keeper) ClearTendermintUpdates(ctx sdk.Context) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
// delete subspace
|
||||
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
store.Delete(iterator.Key())
|
||||
}
|
||||
iterator.Close()
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
||||
// Perform all the necessary steps for when a validator changes its power. This
|
||||
@@ -237,15 +243,20 @@ func (k Keeper) ClearTendermintUpdates(ctx sdk.Context) {
|
||||
// nolint: gocyclo
|
||||
// TODO: Remove above nolint, function needs to be simplified!
|
||||
func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
pool := k.GetPool(ctx)
|
||||
oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr)
|
||||
|
||||
validator = k.updateForJailing(ctx, oldFound, oldValidator, validator)
|
||||
powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator)
|
||||
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator, validator)
|
||||
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator)
|
||||
valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool)
|
||||
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||
cliffValExists := (cliffPower != nil)
|
||||
var valPowerLTcliffPower bool
|
||||
if cliffValExists {
|
||||
valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
@@ -257,9 +268,9 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
||||
(oldFound && oldValidator.Status == sdk.Bonded):
|
||||
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(validator.OperatorAddr), bz)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
||||
|
||||
if cliffPower != nil {
|
||||
if cliffValExists {
|
||||
cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx))
|
||||
if bytes.Equal(cliffAddr, validator.OperatorAddr) {
|
||||
k.updateCliffValidator(ctx, validator)
|
||||
@@ -267,14 +278,13 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
||||
}
|
||||
|
||||
// if is a new validator and the new power is less than the cliff validator
|
||||
case cliffPower != nil && !oldFound &&
|
||||
bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower
|
||||
case cliffValExists && !oldFound && valPowerLTcliffPower:
|
||||
// skip to completion
|
||||
|
||||
// if was unbonded and the new power is less than the cliff validator
|
||||
case cliffPower != nil &&
|
||||
case cliffValExists &&
|
||||
(oldFound && oldValidator.Status == sdk.Unbonded) &&
|
||||
bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower
|
||||
valPowerLTcliffPower: //(valPower < cliffPower
|
||||
// skip to completion
|
||||
|
||||
default:
|
||||
@@ -293,7 +303,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
||||
// if decreased in power but still bonded, update Tendermint validator
|
||||
if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) {
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(validator.OperatorAddr), bz)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +325,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
||||
|
||||
oldCliffVal, found := k.GetValidator(ctx, cliffAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("cliff validator record not found for address: %v\n", cliffAddr))
|
||||
panic(fmt.Sprintf("cliff validator record not found for address: %X\n", cliffAddr))
|
||||
}
|
||||
|
||||
// Create a validator iterator ranging from smallest to largest by power
|
||||
@@ -327,12 +337,10 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
||||
if iterator.Valid() {
|
||||
ownerAddr := iterator.Value()
|
||||
currVal, found := k.GetValidator(ctx, ownerAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
||||
}
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
|
||||
if currVal.Status != sdk.Bonded || currVal.Jailed {
|
||||
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %s\n", ownerAddr))
|
||||
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr))
|
||||
}
|
||||
|
||||
newCliffVal = currVal
|
||||
@@ -345,13 +353,10 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
||||
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
||||
|
||||
if bytes.Equal(affectedVal.OperatorAddr, newCliffVal.OperatorAddr) {
|
||||
|
||||
// The affected validator remains the cliff validator, however, since
|
||||
// the store does not contain the new power, update the new power rank.
|
||||
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
||||
|
||||
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
||||
|
||||
// The affected validator no longer remains the cliff validator as it's
|
||||
// power is greater than the new cliff validator.
|
||||
k.setCliffValidator(ctx, newCliffVal, pool)
|
||||
@@ -382,18 +387,20 @@ func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
|
||||
// get the bond height and incremented intra-tx counter
|
||||
// nolint: unparam
|
||||
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
newValidator types.Validator) (height int64, intraTxCounter int16) {
|
||||
func (k Keeper) bondIncrement(
|
||||
ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) {
|
||||
|
||||
// if already a validator, copy the old block height and counter, else set them
|
||||
if oldFound && oldValidator.Status == sdk.Bonded {
|
||||
// if already a validator, copy the old block height and counter
|
||||
if found && oldValidator.Status == sdk.Bonded {
|
||||
height = oldValidator.BondHeight
|
||||
intraTxCounter = oldValidator.BondIntraTxCounter
|
||||
return
|
||||
}
|
||||
|
||||
height = ctx.BlockHeight()
|
||||
counter := k.GetIntraTxCounter(ctx)
|
||||
intraTxCounter = counter
|
||||
|
||||
k.SetIntraTxCounter(ctx, counter+1)
|
||||
return
|
||||
}
|
||||
@@ -454,29 +461,25 @@ func (k Keeper) UpdateBondedValidators(
|
||||
} else {
|
||||
var found bool
|
||||
validator, found = k.GetValidator(ctx, ownerAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
||||
}
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
}
|
||||
|
||||
// if we've reached jailed validators no further bonded validators exist
|
||||
if validator.Jailed {
|
||||
break
|
||||
}
|
||||
|
||||
// increment bondedValidatorsCount / get the validator to bond
|
||||
if validator.Status != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
if newValidatorBonded {
|
||||
panic("already decided to bond a validator, can't bond another!")
|
||||
if validator.Status == sdk.Bonded {
|
||||
panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr))
|
||||
}
|
||||
newValidatorBonded = true
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// increment the total number of bonded validators and potentially mark
|
||||
// the validator to bond
|
||||
if validator.Status != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
if newValidatorBonded {
|
||||
panic("already decided to bond a validator, can't bond another!")
|
||||
}
|
||||
newValidatorBonded = true
|
||||
}
|
||||
|
||||
@@ -502,9 +505,7 @@ func (k Keeper) UpdateBondedValidators(
|
||||
if newValidatorBonded {
|
||||
if oldCliffValidatorAddr != nil {
|
||||
oldCliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", oldCliffValidatorAddr))
|
||||
}
|
||||
ensureValidatorFound(found, oldCliffValidatorAddr)
|
||||
|
||||
if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) {
|
||||
|
||||
@@ -512,7 +513,6 @@ func (k Keeper) UpdateBondedValidators(
|
||||
// validator was newly bonded and has greater power
|
||||
k.beginUnbondingValidator(ctx, oldCliffVal)
|
||||
} else {
|
||||
|
||||
// otherwise begin unbonding the affected validator, which must
|
||||
// have been kicked out
|
||||
affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator)
|
||||
@@ -560,9 +560,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
||||
|
||||
ownerAddr := iterator.Value()
|
||||
validator, found = k.GetValidator(ctx, ownerAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
||||
}
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
|
||||
_, found = toKickOut[string(ownerAddr)]
|
||||
if found {
|
||||
@@ -605,9 +603,7 @@ func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) {
|
||||
for key := range toKickOut {
|
||||
ownerAddr := []byte(key)
|
||||
validator, found := k.GetValidator(ctx, ownerAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
||||
}
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
k.beginUnbondingValidator(ctx, validator)
|
||||
}
|
||||
}
|
||||
@@ -637,7 +633,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
||||
store.Set(GetTendermintUpdatesKey(validator.OperatorAddr), bzABCI)
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
||||
|
||||
// also remove from the Bonded types.Validators Store
|
||||
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
||||
@@ -662,6 +659,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
|
||||
panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
validator.BondHeight = ctx.BlockHeight()
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
|
||||
k.SetPool(ctx, pool)
|
||||
@@ -672,7 +671,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(validator.OperatorAddr), bzABCI)
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
||||
|
||||
// call the bond hook if present
|
||||
if k.validatorHooks != nil {
|
||||
@@ -707,7 +707,8 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
|
||||
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
||||
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
||||
store.Set(GetTendermintUpdatesKey(address), bz)
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(address), bz)
|
||||
}
|
||||
|
||||
//__________________________________________________________________________
|
||||
@@ -738,3 +739,9 @@ func (k Keeper) clearCliffValidator(ctx sdk.Context) {
|
||||
store.Delete(ValidatorPowerCliffKey)
|
||||
store.Delete(ValidatorCliffIndexKey)
|
||||
}
|
||||
|
||||
func ensureValidatorFound(found bool, ownerAddr []byte) {
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,34 @@ import (
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// for testing, remove all validator update entries after applied to Tendermint
|
||||
func clearTendermintUpdates(ctx sdk.Context, k Keeper) {
|
||||
store := ctx.TransientStore(k.storeTKey)
|
||||
|
||||
// delete subspace
|
||||
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesTKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
store.Delete(iterator.Key())
|
||||
}
|
||||
iterator.Close()
|
||||
}
|
||||
|
||||
//_______________________________________________________
|
||||
|
||||
func TestSetValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 10)
|
||||
pool := keeper.GetPool(ctx)
|
||||
|
||||
valPubKey := PKs[0]
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
// test how the validator is set from a purely unbonbed pool
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
validator := types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, sdk.Unbonded, validator.Status)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
|
||||
@@ -26,14 +42,14 @@ func TestSetValidator(t *testing.T) {
|
||||
keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// after the save the validator should be bonded
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
validator, found := keeper.GetValidator(ctx, valAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Bonded, validator.Status)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares))
|
||||
|
||||
// Check each store for being saved
|
||||
resVal, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
resVal, found := keeper.GetValidator(ctx, valAddr)
|
||||
assert.True(ValEq(t, validator, resVal))
|
||||
require.True(t, found)
|
||||
|
||||
@@ -45,7 +61,7 @@ func TestSetValidator(t *testing.T) {
|
||||
require.Equal(t, 1, len(resVals))
|
||||
assert.True(ValEq(t, validator, resVals[0]))
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validator.ABCIValidator(), updates[0])
|
||||
}
|
||||
@@ -633,67 +649,35 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
}
|
||||
|
||||
// clear the tracked changes to the gotValidator set
|
||||
func TestClearTendermintUpdates(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{100, 400, 200}
|
||||
validators := make([]types.Validator, len(amts))
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.UpdateValidator(ctx, validators[i])
|
||||
}
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
require.Equal(t, len(amts), len(updates))
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(updates))
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesAllNone(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesAllNone(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
var validators [2]types.Validator
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
|
||||
|
||||
valPubKey := PKs[i+1]
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
|
||||
// test from nothing to something
|
||||
// tendermintUpdate set: {} -> {c1, c3}
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
assert.Equal(t, 2, len(updates))
|
||||
assert.Equal(t, validators[0].ABCIValidator(), updates[0])
|
||||
assert.Equal(t, validators[1].ABCIValidator(), updates[1])
|
||||
|
||||
// test from something to nothing
|
||||
// tendermintUpdate set: {} -> {c1, c2, c3, c4}
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
|
||||
keeper.RemoveValidator(ctx, validators[0].OperatorAddr)
|
||||
keeper.RemoveValidator(ctx, validators[1].OperatorAddr)
|
||||
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
assert.Equal(t, 2, len(updates))
|
||||
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].ConsPubKey), updates[0].PubKey)
|
||||
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[1].ConsPubKey), updates[1].PubKey)
|
||||
assert.Equal(t, int64(0), updates[0].Power)
|
||||
assert.Equal(t, int64(0), updates[1].Power)
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesIdentical(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesIdentical(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@@ -706,17 +690,17 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// test identical,
|
||||
// tendermintUpdate set: {} -> {}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@@ -729,8 +713,8 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// test single value change
|
||||
// tendermintUpdate set: {} -> {c1'}
|
||||
@@ -738,13 +722,13 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
validators[0].Tokens = sdk.NewDec(600)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidator(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@@ -757,8 +741,8 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// test multiple value change
|
||||
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
|
||||
@@ -769,13 +753,13 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidator(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[1])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesInserted(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesInserted(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20, 5, 15, 25}
|
||||
@@ -788,34 +772,34 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// test validtor added at the beginning
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[2].ABCIValidator(), updates[0])
|
||||
|
||||
// test validtor added at the beginning
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
validators[3] = keeper.UpdateValidator(ctx, validators[3])
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
updates = keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[3].ABCIValidator(), updates[0])
|
||||
|
||||
// test validtor added at the end
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
validators[4] = keeper.UpdateValidator(ctx, validators[4])
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
updates = keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[4].ABCIValidator(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesWithCliffValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := types.DefaultParams()
|
||||
params.MaxValidators = 2
|
||||
@@ -831,32 +815,32 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// test validator added at the end but not inserted in the valset
|
||||
// tendermintUpdate set: {} -> {}
|
||||
keeper.UpdateValidator(ctx, validators[2])
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(updates))
|
||||
|
||||
// test validator change its power and become a gotValidator (pushing out an existing)
|
||||
// tendermintUpdate set: {} -> {c0, c4}
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
updates = keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates), "%v", updates)
|
||||
require.Equal(t, validators[0].ABCIValidatorZero(), updates[0])
|
||||
require.Equal(t, validators[2].ABCIValidator(), updates[1])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
func TestGetValidTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{100, 100}
|
||||
@@ -869,8 +853,8 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.ClearTendermintUpdates(ctx)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// check initial power
|
||||
require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64())
|
||||
@@ -890,8 +874,158 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64())
|
||||
|
||||
// Tendermint updates should reflect power change
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidator(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[1])
|
||||
}
|
||||
|
||||
func TestGetValidTendermintUpdatesNewValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := keeper.GetParams(ctx)
|
||||
params.MaxValidators = uint16(3)
|
||||
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
amts := []int64{100, 100}
|
||||
var validators [2]types.Validator
|
||||
|
||||
// initialize some validators into the state
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
valPubKey := PKs[i+1]
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
}
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, len(validators), len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidator(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[1])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// update initial validator set
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
}
|
||||
|
||||
// add a new validator that goes from zero power, to non-zero power, back to
|
||||
// zero power
|
||||
pool := keeper.GetPool(ctx)
|
||||
valPubKey := PKs[len(validators)+1]
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
amt := sdk.NewInt(100)
|
||||
|
||||
validator := types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, amt)
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
validator, pool, _ = validator.RemoveDelShares(pool, sdk.NewDecFromInt(amt))
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// add a new validator that increases in power
|
||||
valPubKey = PKs[len(validators)+2]
|
||||
valAddr = sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
validator = types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(500))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates = keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, len(validators)+1, len(updates))
|
||||
require.Equal(t, validator.ABCIValidator(), updates[0])
|
||||
require.Equal(t, validators[0].ABCIValidator(), updates[1])
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[2])
|
||||
}
|
||||
|
||||
func TestGetValidTendermintUpdatesBondTransition(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := keeper.GetParams(ctx)
|
||||
params.MaxValidators = uint16(2)
|
||||
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
amts := []int64{100, 200, 300}
|
||||
var validators [3]types.Validator
|
||||
|
||||
// initialize some validators into the state
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
moniker := fmt.Sprintf("%d", i)
|
||||
valPubKey := PKs[i+1]
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
}
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates := keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
require.Equal(t, validators[2].ABCIValidator(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[1])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// delegate to validator with lowest power but not enough to bond
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
require.True(t, found)
|
||||
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
|
||||
// create a series of events that will bond and unbond the validator with
|
||||
// lowest power in a single block context (height)
|
||||
ctx = ctx.WithBlockHeight(2)
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
require.True(t, found)
|
||||
|
||||
validator, pool, _ = validator.RemoveDelShares(pool, validator.DelegatorShares)
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[1] = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates = keeper.GetValidTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[1].ABCIValidator(), updates[0])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||
mapper := mapp.AccountMapper
|
||||
bankKeeper := bank.NewBaseKeeper(mapper)
|
||||
stakeKey := sdk.NewKVStoreKey("stake")
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, bankKeeper, stake.DefaultCodespace)
|
||||
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
|
||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, stake.DefaultCodespace)
|
||||
mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
|
||||
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
validatorUpdates := stake.EndBlocker(ctx, stakeKeeper)
|
||||
@@ -32,7 +33,7 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
err := mapp.CompleteSetup([]*sdk.KVStoreKey{stakeKey})
|
||||
err := mapp.CompleteSetup(stakeKey, stakeTKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -44,14 +45,14 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.Operation{
|
||||
SimulateMsgCreateValidator(mapper, stakeKeeper),
|
||||
SimulateMsgEditValidator(stakeKeeper),
|
||||
SimulateMsgDelegate(mapper, stakeKeeper),
|
||||
SimulateMsgBeginUnbonding(mapper, stakeKeeper),
|
||||
SimulateMsgCompleteUnbonding(stakeKeeper),
|
||||
SimulateMsgBeginRedelegate(mapper, stakeKeeper),
|
||||
SimulateMsgCompleteRedelegate(stakeKeeper),
|
||||
[]simulation.WeightedOperation{
|
||||
{10, SimulateMsgCreateValidator(mapper, stakeKeeper)},
|
||||
{5, SimulateMsgEditValidator(stakeKeeper)},
|
||||
{15, SimulateMsgDelegate(mapper, stakeKeeper)},
|
||||
{10, SimulateMsgBeginUnbonding(mapper, stakeKeeper)},
|
||||
{3, SimulateMsgCompleteUnbonding(stakeKeeper)},
|
||||
{10, SimulateMsgBeginRedelegate(mapper, stakeKeeper)},
|
||||
{3, SimulateMsgCompleteRedelegate(stakeKeeper)},
|
||||
}, []simulation.RandSetup{
|
||||
Setup(mapp, stakeKeeper),
|
||||
}, []simulation.Invariant{
|
||||
|
||||
+2
-2
@@ -33,7 +33,7 @@ var (
|
||||
GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey
|
||||
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
|
||||
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
|
||||
GetTendermintUpdatesKey = keeper.GetTendermintUpdatesKey
|
||||
GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey
|
||||
GetDelegationKey = keeper.GetDelegationKey
|
||||
GetDelegationsKey = keeper.GetDelegationsKey
|
||||
ParamKey = keeper.ParamKey
|
||||
@@ -44,7 +44,7 @@ var (
|
||||
ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey
|
||||
ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey
|
||||
ValidatorPowerCliffKey = keeper.ValidatorPowerCliffKey
|
||||
TendermintUpdatesKey = keeper.TendermintUpdatesKey
|
||||
TendermintUpdatesTKey = keeper.TendermintUpdatesTKey
|
||||
DelegationKey = keeper.DelegationKey
|
||||
IntraTxCounterKey = keeper.IntraTxCounterKey
|
||||
GetUBDKey = keeper.GetUBDKey
|
||||
|
||||
Reference in New Issue
Block a user