Merge branch 'develop' into joon/2490-copy-godocs

This commit is contained in:
Joon 2018-10-16 04:14:40 +09:00 committed by GitHub
commit 047c3d1456
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 278 additions and 110 deletions

View File

@ -69,7 +69,8 @@ BREAKING CHANGES
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index * [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
* [x/staking] \#2236 more distribution hooks for distribution * [x/staking] \#2236 more distribution hooks for distribution
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock * [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
* [x/stake] Global Paramstore refactored * [x/stake] \#2412 Added an unbonding validator queue to EndBlock to automatically update validator.Status when finished Unbonding
* [x/params] Global Paramstore refactored
* Tendermint * Tendermint
* Update tendermint version from v0.23.0 to v0.25.0, notable changes * Update tendermint version from v0.23.0 to v0.25.0, notable changes
@ -92,6 +93,7 @@ FEATURES
* [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`. * [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint. * [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}` * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`
* [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint
* Gaia CLI (`gaiacli`) * Gaia CLI (`gaiacli`)
* [cli] Cmds to query staking pool and params * [cli] Cmds to query staking pool and params

View File

@ -10,19 +10,19 @@ import (
"testing" "testing"
"time" "time"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/client/tx"
p2p "github.com/tendermint/tendermint/p2p"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys" cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
p2p "github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
client "github.com/cosmos/cosmos-sdk/client" client "github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys" keys "github.com/cosmos/cosmos-sdk/client/keys"
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
tests "github.com/cosmos/cosmos-sdk/tests" tests "github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -613,7 +613,7 @@ func TestSubmitProposal(t *testing.T) {
defer cleanup() defer cleanup()
// create SubmitProposal TX // create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name, password, addr) resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed // check if tx was committed
@ -635,7 +635,7 @@ func TestDeposit(t *testing.T) {
defer cleanup() defer cleanup()
// create SubmitProposal TX // create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name, password, addr) resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed // check if tx was committed
@ -650,7 +650,7 @@ func TestDeposit(t *testing.T) {
require.Equal(t, "Test", proposal.GetTitle()) require.Equal(t, "Test", proposal.GetTitle())
// create SubmitProposal TX // create SubmitProposal TX
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID) resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// query proposal // query proposal
@ -669,7 +669,7 @@ func TestVote(t *testing.T) {
defer cleanup() defer cleanup()
// create SubmitProposal TX // create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name, password, addr) resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed // check if tx was committed
@ -684,7 +684,7 @@ func TestVote(t *testing.T) {
require.Equal(t, "Test", proposal.GetTitle()) require.Equal(t, "Test", proposal.GetTitle())
// create SubmitProposal TX // create SubmitProposal TX
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID) resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// query proposal // query proposal
@ -725,27 +725,52 @@ func TestProposalsQuery(t *testing.T) {
defer cleanup() defer cleanup()
// Addr1 proposes (and deposits) proposals #1 and #2 // Addr1 proposes (and deposits) proposals #1 and #2
resultTx := doSubmitProposal(t, port, seed, name, password1, addr) resultTx := doSubmitProposal(t, port, seed, name, password1, addr, 5)
var proposalID1 int64 var proposalID1 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1) cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doSubmitProposal(t, port, seed, name, password1, addr) resultTx = doSubmitProposal(t, port, seed, name, password1, addr, 5)
var proposalID2 int64 var proposalID2 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2) cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 proposes (and deposits) proposals #3 // Addr2 proposes (and deposits) proposals #3
resultTx = doSubmitProposal(t, port, seed2, name2, password2, addr2) resultTx = doSubmitProposal(t, port, seed2, name2, password2, addr2, 5)
var proposalID3 int64 var proposalID3 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3) cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 deposits on proposals #2 & #3 // Addr2 deposits on proposals #2 & #3
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID2) resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID2, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID3) resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID3, 5)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// check deposits match proposal and individual deposits
deposits := getDeposits(t, port, proposalID1)
require.Len(t, deposits, 1)
deposit := getDeposit(t, port, proposalID1, addr)
require.Equal(t, deposit, deposits[0])
deposits = getDeposits(t, port, proposalID2)
require.Len(t, deposits, 2)
deposit = getDeposit(t, port, proposalID2, addr)
require.Equal(t, deposit, deposits[0])
deposit = getDeposit(t, port, proposalID2, addr2)
require.Equal(t, deposit, deposits[1])
deposits = getDeposits(t, port, proposalID3)
require.Len(t, deposits, 1)
deposit = getDeposit(t, port, proposalID3, addr2)
require.Equal(t, deposit, deposits[0])
// increasing the amount of the deposit should update the existing one
resultTx = doDeposit(t, port, seed, name, password1, addr, proposalID1, 1)
tests.WaitForHeight(resultTx.Height+1, port)
deposits = getDeposits(t, port, proposalID1)
require.Len(t, deposits, 1)
// Only proposals #1 should be in Deposit Period // Only proposals #1 should be in Deposit Period
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod) proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
require.Len(t, proposals, 1) require.Len(t, proposals, 1)
@ -1168,6 +1193,15 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
return proposal return proposal
} }
func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var deposits []gov.Deposit
err := cdc.UnmarshalJSON([]byte(body), &deposits)
require.Nil(t, err)
return deposits
}
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit { func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -1245,7 +1279,7 @@ func getProposalsFilterStatus(t *testing.T, port string, status gov.ProposalStat
return proposals return proposals
} }
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr) acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber() accnum := acc.GetAccountNumber()
@ -1259,7 +1293,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
"description": "test", "description": "test",
"proposal_type": "Text", "proposal_type": "Text",
"proposer": "%s", "proposer": "%s",
"initial_deposit": [{ "denom": "steak", "amount": "5" }], "initial_deposit": [{ "denom": "steak", "amount": "%d" }],
"base_req": { "base_req": {
"name": "%s", "name": "%s",
"password": "%s", "password": "%s",
@ -1267,7 +1301,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
"account_number":"%d", "account_number":"%d",
"sequence":"%d" "sequence":"%d"
} }
}`, proposerAddr, name, password, chainID, accnum, sequence)) }`, proposerAddr, amount, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", "/gov/proposals", jsonStr) res, body := Request(t, port, "POST", "/gov/proposals", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -1278,7 +1312,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
return results return results
} }
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) { func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr) acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber() accnum := acc.GetAccountNumber()
@ -1289,7 +1323,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
// deposit on proposal // deposit on proposal
jsonStr := []byte(fmt.Sprintf(`{ jsonStr := []byte(fmt.Sprintf(`{
"depositer": "%s", "depositer": "%s",
"amount": [{ "denom": "steak", "amount": "5" }], "amount": [{ "denom": "steak", "amount": "%d" }],
"base_req": { "base_req": {
"name": "%s", "name": "%s",
"password": "%s", "password": "%s",
@ -1297,7 +1331,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
"account_number":"%d", "account_number":"%d",
"sequence": "%d" "sequence": "%d"
} }
}`, proposerAddr, name, password, chainID, accnum, sequence)) }`, proposerAddr, amount, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr) res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)

View File

@ -1,5 +1,20 @@
# End-Block # End-Block
## Unbonding Validator Queue
For all unbonding validators that have finished their unbonding period, this switches their validator.Status
from sdk.Unbonding to sdk.Unbonded
```golang
validatorQueue(currTime time.Time):
// unbonding validators are in ordered queue from oldest to newest
for all unbondingValidators whose CompleteTime < currTime:
validator = GetValidator(unbondingValidator.ValidatorAddr)
validator.Status = sdk.Bonded
SetValidator(unbondingValidator)
return
```
## Validator Set Changes ## Validator Set Changes
The Tendermint validator set may be updated by state transitions that run at The Tendermint validator set may be updated by state transitions that run at

View File

@ -188,7 +188,9 @@ func (c Context) WithBlockTime(newTime time.Time) Context {
} }
func (c Context) WithBlockHeight(height int64) Context { func (c Context) WithBlockHeight(height int64) Context {
return c.withValue(contextKeyBlockHeight, height) newHeader := c.BlockHeader()
newHeader.Height = height
return c.withValue(contextKeyBlockHeight, height).withValue(contextKeyBlockHeader, newHeader)
} }
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context { func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {

View File

@ -164,15 +164,16 @@ func TestContextWithCustom(t *testing.T) {
meter := types.NewGasMeter(10000) meter := types.NewGasMeter(10000)
minFees := types.Coins{types.NewInt64Coin("feeCoin", 1)} minFees := types.Coins{types.NewInt64Coin("feeCoin", 1)}
ctx = types.NewContext(nil, header, ischeck, logger). ctx = types.NewContext(nil, header, ischeck, logger)
require.Equal(t, header, ctx.BlockHeader())
ctx = ctx.
WithBlockHeight(height). WithBlockHeight(height).
WithChainID(chainid). WithChainID(chainid).
WithTxBytes(txbytes). WithTxBytes(txbytes).
WithVoteInfos(voteinfos). WithVoteInfos(voteinfos).
WithGasMeter(meter). WithGasMeter(meter).
WithMinimumFees(minFees) WithMinimumFees(minFees)
require.Equal(t, header, ctx.BlockHeader())
require.Equal(t, height, ctx.BlockHeight()) require.Equal(t, height, ctx.BlockHeight())
require.Equal(t, chainid, ctx.ChainID()) require.Equal(t, chainid, ctx.ChainID())
require.Equal(t, ischeck, ctx.IsCheckTx()) require.Equal(t, ischeck, ctx.IsCheckTx())

View File

@ -31,13 +31,12 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec)
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc)).Methods("GET") r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc)).Methods("GET") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), queryDepositsHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc)).Methods("GET") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc)).Methods("GET")
} }
type postProposalReq struct { type postProposalReq struct {
@ -164,7 +163,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
} }
} }
func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc { func queryProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
@ -180,8 +179,6 @@ func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
params := gov.QueryProposalParams{ params := gov.QueryProposalParams{
ProposalID: proposalID, ProposalID: proposalID,
} }
@ -198,11 +195,41 @@ func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc { func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
strProposalID := vars[RestProposalID]
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
params := gov.QueryDepositsParams{
ProposalID: proposalID,
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/deposits", bz)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
@ -232,8 +259,6 @@ func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
params := gov.QueryDepositParams{ params := gov.QueryDepositParams{
ProposalID: proposalID, ProposalID: proposalID,
Depositer: depositerAddr, Depositer: depositerAddr,
@ -265,11 +290,11 @@ func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc { func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
@ -299,8 +324,6 @@ func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
params := gov.QueryVoteParams{ params := gov.QueryVoteParams{
Voter: voterAddr, Voter: voterAddr,
ProposalID: proposalID, ProposalID: proposalID,
@ -335,12 +358,12 @@ func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
// todo: Split this functionality into helper functions to remove the above // todo: Split this functionality into helper functions to remove the above
func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc { func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
@ -356,8 +379,6 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
params := gov.QueryVotesParams{ params := gov.QueryVotesParams{
ProposalID: proposalID, ProposalID: proposalID,
} }
@ -373,12 +394,12 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
// todo: Split this functionality into helper functions to remove the above // todo: Split this functionality into helper functions to remove the above
func queryProposalsWithParameterFn(cdc *codec.Codec) http.HandlerFunc { func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
bechVoterAddr := r.URL.Query().Get(RestVoter) bechVoterAddr := r.URL.Query().Get(RestVoter)
bechDepositerAddr := r.URL.Query().Get(RestDepositer) bechDepositerAddr := r.URL.Query().Get(RestDepositer)
@ -430,20 +451,18 @@ func queryProposalsWithParameterFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz) res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
if err != nil { if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
// todo: Split this functionality into helper functions to remove the above // todo: Split this functionality into helper functions to remove the above
func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc { func queryTallyOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
@ -461,8 +480,6 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
cliCtx := context.NewCLIContext().WithCodec(cdc)
params := gov.QueryTallyParams{ params := gov.QueryTallyParams{
ProposalID: proposalID, ProposalID: proposalID,
} }
@ -480,6 +497,6 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return return
} }
w.Write(res) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }

View File

@ -118,7 +118,7 @@ type QueryDepositsParams struct {
// nolint: unparam // nolint: unparam
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
var params QueryDepositParams var params QueryDepositsParams
err2 := keeper.cdc.UnmarshalJSON(req.Data, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
if err2 != nil { if err2 != nil {
return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error()))

View File

@ -35,6 +35,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) { func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
endBlockerTags := sdk.EmptyTags() endBlockerTags := sdk.EmptyTags()
k.UnbondAllMatureValidatorQueue(ctx)
matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time) matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time)
for _, dvPair := range matureUnbonds { for _, dvPair := range matureUnbonds {
err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr) err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr)

View File

@ -629,6 +629,56 @@ func TestJailValidator(t *testing.T) {
require.True(t, got.IsOK(), "expected ok, got %v", got) require.True(t, got.IsOK(), "expected ok, got %v", got)
} }
func TestValidatorQueue(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
// set the unbonding time
params := keeper.GetParams(ctx)
params.UnbondingTime = 7 * time.Second
keeper.SetParams(ctx, params)
// create the validator
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
// bond a delegator
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
got = handleMsgDelegate(ctx, msgDelegate, keeper)
require.True(t, got.IsOK(), "expected ok, got %v", got)
EndBlocker(ctx, keeper)
// unbond the all self-delegation to put validator in unbonding state
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
require.True(t, got.IsOK(), "expected no error: %v", got)
var finishTime time.Time
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
ctx = ctx.WithBlockTime(finishTime)
EndBlocker(ctx, keeper)
origHeader := ctx.BlockHeader()
validator, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonding, "%v", validator)
// should still be unbonding at time 6 seconds later
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6))
EndBlocker(ctx, keeper)
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonding, "%v", validator)
// should be in unbonded state at time 7 seconds later
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7))
EndBlocker(ctx, keeper)
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonded, "%v", validator)
}
func TestUnbondingPeriod(t *testing.T) { func TestUnbondingPeriod(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000) ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr := sdk.ValAddress(keep.Addrs[0]) validatorAddr := sdk.ValAddress(keep.Addrs[0])

View File

@ -447,10 +447,10 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) (
// the longest wait - just unbonding period from now // the longest wait - just unbonding period from now
minTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) minTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx))
height = ctx.BlockHeader().Height height = ctx.BlockHeight()
return minTime, height, false return minTime, height, false
case validator.IsUnbonded(ctx): case validator.Status == sdk.Unbonded:
return minTime, height, true return minTime, height, true
case validator.Status == sdk.Unbonding: case validator.Status == sdk.Unbonding:

View File

@ -374,12 +374,8 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
} }
keeper.SetDelegation(ctx, delegation) keeper.SetDelegation(ctx, delegation)
header := ctx.BlockHeader() ctx = ctx.WithBlockHeight(10)
blockHeight := int64(10) ctx = ctx.WithBlockTime(time.Unix(333, 0))
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
// unbond the all self-delegation to put validator in unbonding state // unbond the all self-delegation to put validator in unbonding state
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) _, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
@ -391,17 +387,12 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
validator, found := keeper.GetValidator(ctx, addrVals[0]) validator, found := keeper.GetValidator(ctx, addrVals[0])
require.True(t, found) require.True(t, found)
require.Equal(t, blockHeight, validator.UnbondingHeight) require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime)) require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
// change the context to one which makes the validator considered unbonded // unbond the validator
header = ctx.BlockHeader() keeper.unbondingToUnbonded(ctx, validator)
blockHeight2 := int64(20)
header.Height = blockHeight2
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
header.Time = blockTime2
ctx = ctx.WithBlockHeader(header)
// unbond some of the other delegation's shares // unbond some of the other delegation's shares
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6)) _, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
@ -696,12 +687,8 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
validator2 = testingUpdateValidator(keeper, ctx, validator2) validator2 = testingUpdateValidator(keeper, ctx, validator2)
require.Equal(t, sdk.Bonded, validator2.Status) require.Equal(t, sdk.Bonded, validator2.Status)
header := ctx.BlockHeader() ctx = ctx.WithBlockHeight(10)
blockHeight := int64(10) ctx = ctx.WithBlockTime(time.Unix(333, 0))
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
// unbond the all self-delegation to put validator in unbonding state // unbond the all self-delegation to put validator in unbonding state
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) _, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
@ -713,23 +700,18 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
validator, found := keeper.GetValidator(ctx, addrVals[0]) validator, found := keeper.GetValidator(ctx, addrVals[0])
require.True(t, found) require.True(t, found)
require.Equal(t, blockHeight, validator.UnbondingHeight) require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime)) require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
// change the context to one which makes the validator considered unbonded // unbond the validator
header = ctx.BlockHeader() keeper.unbondingToUnbonded(ctx, validator)
blockHeight2 := int64(20)
header.Height = blockHeight2
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
header.Time = blockTime2
ctx = ctx.WithBlockHeader(header)
// unbond some of the other delegation's shares // redelegate some of the delegation's shares
_, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6)) _, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
require.NoError(t, err) require.NoError(t, err)
// no ubd should have been found, coins should have been returned direcly to account // no red should have been found
ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.False(t, found, "%v", ubd) require.False(t, found, "%v", red)
} }

View File

@ -29,6 +29,7 @@ var (
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations queue RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations queue
ValidatorQueueKey = []byte{0x0F} // prefix for the timestamps in validator queue
) )
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
@ -86,6 +87,12 @@ func getValidatorPowerRank(validator types.Validator) []byte {
return key return key
} }
// gets the prefix for all unbonding delegations from a delegator
func GetValidatorQueueTimeKey(timestamp time.Time) []byte {
bz := types.MsgCdc.MustMarshalBinary(timestamp)
return append(ValidatorQueueKey, bz...)
}
//______________________________________________________________________________ //______________________________________________________________________________
// gets the key for delegator bond with validator // gets the key for delegator bond with validator

View File

@ -46,7 +46,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
} }
// should not be slashing unbonded // should not be slashing unbonded
if validator.IsUnbonded(ctx) { if validator.Status == sdk.Unbonded {
panic(fmt.Sprintf("should not be slashing unbonded validator: %s", validator.GetOperator())) panic(fmt.Sprintf("should not be slashing unbonded validator: %s", validator.GetOperator()))
} }

View File

@ -131,8 +131,9 @@ func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) typ
return k.bondValidator(ctx, validator) return k.bondValidator(ctx, validator)
} }
// switches a validator from unbonding state to unbonded state
func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator { func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator {
if validator.Status != sdk.Unbonded { if validator.Status != sdk.Unbonding {
panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
} }
return k.completeUnbondingValidator(ctx, validator) return k.completeUnbondingValidator(ctx, validator)
@ -213,6 +214,9 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
k.SetValidatorByPowerIndex(ctx, validator, pool) k.SetValidatorByPowerIndex(ctx, validator, pool)
// Adds to unbonding validator queue
k.InsertValidatorQueue(ctx, validator)
// call the unbond hook if present // call the unbond hook if present
if k.hooks != nil { if k.hooks != nil {
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())

View File

@ -3,6 +3,7 @@ package keeper
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/cosmos/cosmos-sdk/x/stake/types"
@ -281,3 +282,69 @@ func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
} }
return validators[:i] // trim return validators[:i] // trim
} }
// gets a specific validator queue timeslice. A timeslice is a slice of ValAddresses corresponding to unbonding validators
// that expire at a certain time.
func (k Keeper) GetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (valAddrs []sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(GetValidatorQueueTimeKey(timestamp))
if bz == nil {
return []sdk.ValAddress{}
}
k.cdc.MustUnmarshalBinary(bz, &valAddrs)
return valAddrs
}
// Sets a specific validator queue timeslice.
func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(keys)
store.Set(GetValidatorQueueTimeKey(timestamp), bz)
}
// Insert an validator address to the appropriate timeslice in the validator queue
func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) {
timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
if len(timeSlice) == 0 {
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, []sdk.ValAddress{val.OperatorAddr})
} else {
timeSlice = append(timeSlice, val.OperatorAddr)
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, timeSlice)
}
}
// Returns all the validator queue timeslices from time 0 until endTime
func (k Keeper) ValidatorQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
return store.Iterator(ValidatorQueueKey, sdk.InclusiveEndBytes(GetValidatorQueueTimeKey(endTime)))
}
// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue
func (k Keeper) GetAllMatureValidatorQueue(ctx sdk.Context, currTime time.Time) (matureValsAddrs []sdk.ValAddress) {
// gets an iterator for all timeslices from time 0 until the current Blockheader time
validatorTimesliceIterator := k.ValidatorQueueIterator(ctx, ctx.BlockHeader().Time)
for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() {
timeslice := []sdk.ValAddress{}
k.cdc.MustUnmarshalBinary(validatorTimesliceIterator.Value(), &timeslice)
matureValsAddrs = append(matureValsAddrs, timeslice...)
}
return matureValsAddrs
}
// Unbonds all the unbonding validators that have finished their unbonding period
func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
validatorTimesliceIterator := k.ValidatorQueueIterator(ctx, ctx.BlockHeader().Time)
for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() {
timeslice := []sdk.ValAddress{}
k.cdc.MustUnmarshalBinary(validatorTimesliceIterator.Value(), &timeslice)
for _, valAddr := range timeslice {
val, found := k.GetValidator(ctx, valAddr)
if !found || val.GetStatus() != sdk.Unbonding {
continue
}
k.unbondingToUnbonded(ctx, val)
}
store.Delete(validatorTimesliceIterator.Key())
}
}

View File

@ -435,21 +435,6 @@ func (v Validator) BondedTokens() sdk.Dec {
return sdk.ZeroDec() return sdk.ZeroDec()
} }
// TODO remove this once the validator queue logic is implemented
// Returns if the validator should be considered unbonded
func (v Validator) IsUnbonded(ctx sdk.Context) bool {
switch v.Status {
case sdk.Unbonded:
return true
case sdk.Unbonding:
ctxTime := ctx.BlockHeader().Time
if ctxTime.After(v.UnbondingMinTime) {
return true
}
}
return false
}
//______________________________________________________________________ //______________________________________________________________________
// ensure fulfills the sdk validator types // ensure fulfills the sdk validator types