Merge branch 'master' into cwgoes/a-random-walk-down-proof-of-stake
This commit is contained in:
commit
50d384aa90
|
@ -7,10 +7,16 @@
|
|||
BREAKING CHANGES
|
||||
* [x/stake] Specify DelegatorAddress in MsgCreateValidator
|
||||
* [x/auth] NewAccountMapper takes a constructor instead of a prototype
|
||||
* [keys] Keybase.Update function now takes in a function to get the newpass, rather than the password itself
|
||||
|
||||
FEATURES
|
||||
* [baseapp] NewBaseApp now takes option functions as parameters
|
||||
|
||||
|
||||
BUG FIXES
|
||||
* [keys] \#1629 - updating password no longer asks for a new password when the first entered password was incorrect
|
||||
* [lcd] importing an account would create a random account
|
||||
|
||||
## 0.20.0
|
||||
|
||||
*July 10th, 2018*
|
||||
|
@ -58,6 +64,8 @@ BREAKING CHANGES
|
|||
* [lcd] Switch key creation output to return bech32
|
||||
* [lcd] Removed shorthand CLI flags (`a`, `c`, `n`, `o`)
|
||||
* [gaiad] genesis transactions now use bech32 addresses / pubkeys
|
||||
* [gov] VoteStatus renamed to ProposalStatus
|
||||
* [gov] VoteOption, ProposalType, and ProposalStatus all marshal to string form in JSON
|
||||
|
||||
DEPRECATED
|
||||
* [cli] Deprecated `--name` flag in commands that send txs, in favor of `--from`
|
||||
|
@ -110,6 +118,7 @@ IMPROVEMENTS
|
|||
* [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency)
|
||||
* [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value)
|
||||
* [stake] offload more generic functionality from the handler into the keeper
|
||||
* [stake] clearer staking logic
|
||||
* [types] added common tag constants
|
||||
* [keys] improve error message when deleting non-existent key
|
||||
* [gaiacli] improve error messages on `send` and `account` commands
|
||||
|
|
|
@ -161,6 +161,7 @@ func printCreate(info keys.Info, seed string) {
|
|||
type NewKeyBody struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
Seed string `json:"seed"`
|
||||
}
|
||||
|
||||
// add new key REST handler
|
||||
|
@ -205,7 +206,11 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// create account
|
||||
info, mnemonic, err := kb.CreateMnemonic(m.Name, keys.English, m.Password, keys.Secp256k1)
|
||||
seed := m.Seed
|
||||
if seed == "" {
|
||||
seed = getSeed(keys.Secp256k1)
|
||||
}
|
||||
info, err := kb.CreateKey(m.Name, seed, m.Password)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -219,7 +224,7 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
keyOutput.Seed = mnemonic
|
||||
keyOutput.Seed = seed
|
||||
|
||||
bz, err := json.Marshal(keyOutput)
|
||||
if err != nil {
|
||||
|
|
|
@ -26,23 +26,23 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error {
|
|||
name := args[0]
|
||||
|
||||
buf := client.BufferStdin()
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldpass, err := client.GetPassword(
|
||||
"Enter the current passphrase:", buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newpass, err := client.GetCheckPassword(
|
||||
"Enter the new passphrase:",
|
||||
"Repeat the new passphrase:", buf)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
getNewpass := func() (string, error) {
|
||||
return client.GetCheckPassword(
|
||||
"Enter the new passphrase:",
|
||||
"Repeat the new passphrase:", buf)
|
||||
}
|
||||
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = kb.Update(name, oldpass, newpass)
|
||||
err = kb.Update(name, oldpass, getNewpass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -81,8 +81,10 @@ func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
getNewpass := func() (string, error) { return m.NewPassword, nil }
|
||||
|
||||
// TODO check if account exists and if password is correct
|
||||
err = kb.Update(name, m.OldPassword, m.NewPassword)
|
||||
err = kb.Update(name, m.OldPassword, getNewpass)
|
||||
if err != nil {
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -52,7 +53,7 @@ func TestKeys(t *testing.T) {
|
|||
newPassword := "0987654321"
|
||||
|
||||
// add key
|
||||
jsonStr := []byte(fmt.Sprintf(`{"name":"%s", "password":"%s"}`, newName, newPassword))
|
||||
jsonStr := []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed":"%s"}`, newName, newPassword, seed))
|
||||
res, body = Request(t, port, "POST", "/keys", jsonStr)
|
||||
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -64,6 +65,11 @@ func TestKeys(t *testing.T) {
|
|||
_, err = sdk.AccAddressFromBech32(addr2Bech32)
|
||||
require.NoError(t, err, "Failed to return a correct bech32 address")
|
||||
|
||||
// test if created account is the correct account
|
||||
expectedInfo, _ := GetKB(t).CreateKey(newName, seed, newPassword)
|
||||
expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes())
|
||||
assert.Equal(t, expectedAccount.String(), addr2Bech32)
|
||||
|
||||
// existing keys
|
||||
res, body = Request(t, port, "GET", "/keys", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -443,7 +449,7 @@ func TestSubmitProposal(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
require.Equal(t, "Test", proposal.Title)
|
||||
require.Equal(t, "Test", proposal.GetTitle())
|
||||
}
|
||||
|
||||
func TestDeposit(t *testing.T) {
|
||||
|
@ -465,7 +471,7 @@ func TestDeposit(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
require.Equal(t, "Test", proposal.Title)
|
||||
require.Equal(t, "Test", proposal.GetTitle())
|
||||
|
||||
// create SubmitProposal TX
|
||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID)
|
||||
|
@ -473,7 +479,7 @@ func TestDeposit(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal = getProposal(t, port, proposalID)
|
||||
require.True(t, proposal.TotalDeposit.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)}))
|
||||
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)}))
|
||||
|
||||
// query deposit
|
||||
deposit := getDeposit(t, port, proposalID, addr)
|
||||
|
@ -499,7 +505,7 @@ func TestVote(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
require.Equal(t, "Test", proposal.Title)
|
||||
require.Equal(t, "Test", proposal.GetTitle())
|
||||
|
||||
// create SubmitProposal TX
|
||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID)
|
||||
|
@ -507,7 +513,7 @@ func TestVote(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal = getProposal(t, port, proposalID)
|
||||
require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal.Status)
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
|
||||
|
||||
// create SubmitProposal TX
|
||||
resultTx = doVote(t, port, seed, name, password, addr, proposalID)
|
||||
|
@ -515,7 +521,7 @@ func TestVote(t *testing.T) {
|
|||
|
||||
vote := getVote(t, port, proposalID, addr)
|
||||
require.Equal(t, proposalID, vote.ProposalID)
|
||||
require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option)
|
||||
require.Equal(t, gov.OptionYes, vote.Option)
|
||||
}
|
||||
|
||||
func TestUnrevoke(t *testing.T) {
|
||||
|
@ -576,31 +582,31 @@ func TestProposalsQuery(t *testing.T) {
|
|||
|
||||
// Test query all proposals
|
||||
proposals := getProposalsAll(t, port)
|
||||
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID2, (proposals[1]).ProposalID)
|
||||
require.Equal(t, proposalID3, (proposals[2]).ProposalID)
|
||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
||||
require.Equal(t, proposalID2, (proposals[1]).GetProposalID())
|
||||
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
|
||||
|
||||
// Test query deposited by addr1
|
||||
proposals = getProposalsFilterDepositer(t, port, addr)
|
||||
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
||||
|
||||
// Test query deposited by addr2
|
||||
proposals = getProposalsFilterDepositer(t, port, addr2)
|
||||
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
|
||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
||||
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
||||
|
||||
// Test query voted by addr1
|
||||
proposals = getProposalsFilterVoter(t, port, addr)
|
||||
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
|
||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
||||
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
||||
|
||||
// Test query voted by addr2
|
||||
proposals = getProposalsFilterVoter(t, port, addr2)
|
||||
require.Equal(t, proposalID3, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID3, (proposals[0]).GetProposalID())
|
||||
|
||||
// Test query voted and deposited by addr1
|
||||
proposals = getProposalsFilterVoterDepositer(t, port, addr, addr)
|
||||
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
|
@ -838,68 +844,68 @@ func getValidators(t *testing.T, port string) []stakerest.StakeValidatorOutput {
|
|||
return validators
|
||||
}
|
||||
|
||||
func getProposal(t *testing.T, port string, proposalID int64) gov.ProposalRest {
|
||||
func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d", proposalID), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var proposal gov.ProposalRest
|
||||
var proposal gov.Proposal
|
||||
err := cdc.UnmarshalJSON([]byte(body), &proposal)
|
||||
require.Nil(t, err)
|
||||
return proposal
|
||||
}
|
||||
|
||||
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.DepositRest {
|
||||
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)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var deposit gov.DepositRest
|
||||
var deposit gov.Deposit
|
||||
err := cdc.UnmarshalJSON([]byte(body), &deposit)
|
||||
require.Nil(t, err)
|
||||
return deposit
|
||||
}
|
||||
|
||||
func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddress) gov.VoteRest {
|
||||
func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddress) gov.Vote {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes/%s", proposalID, voterAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var vote gov.VoteRest
|
||||
var vote gov.Vote
|
||||
err := cdc.UnmarshalJSON([]byte(body), &vote)
|
||||
require.Nil(t, err)
|
||||
return vote
|
||||
}
|
||||
|
||||
func getProposalsAll(t *testing.T, port string) []gov.ProposalRest {
|
||||
func getProposalsAll(t *testing.T, port string) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", "/gov/proposals", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var proposals []gov.ProposalRest
|
||||
var proposals []gov.Proposal
|
||||
err := cdc.UnmarshalJSON([]byte(body), &proposals)
|
||||
require.Nil(t, err)
|
||||
return proposals
|
||||
}
|
||||
|
||||
func getProposalsFilterDepositer(t *testing.T, port string, depositerAddr sdk.AccAddress) []gov.ProposalRest {
|
||||
func getProposalsFilterDepositer(t *testing.T, port string, depositerAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s", depositerAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var proposals []gov.ProposalRest
|
||||
var proposals []gov.Proposal
|
||||
err := cdc.UnmarshalJSON([]byte(body), &proposals)
|
||||
require.Nil(t, err)
|
||||
return proposals
|
||||
}
|
||||
|
||||
func getProposalsFilterVoter(t *testing.T, port string, voterAddr sdk.AccAddress) []gov.ProposalRest {
|
||||
func getProposalsFilterVoter(t *testing.T, port string, voterAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?voter=%s", voterAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var proposals []gov.ProposalRest
|
||||
var proposals []gov.Proposal
|
||||
err := cdc.UnmarshalJSON([]byte(body), &proposals)
|
||||
require.Nil(t, err)
|
||||
return proposals
|
||||
}
|
||||
|
||||
func getProposalsFilterVoterDepositer(t *testing.T, port string, voterAddr, depositerAddr sdk.AccAddress) []gov.ProposalRest {
|
||||
func getProposalsFilterVoterDepositer(t *testing.T, port string, voterAddr, depositerAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s&voter=%s", depositerAddr, voterAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var proposals []gov.ProposalRest
|
||||
var proposals []gov.Proposal
|
||||
err := cdc.UnmarshalJSON([]byte(body), &proposals)
|
||||
require.Nil(t, err)
|
||||
return proposals
|
||||
|
|
|
@ -183,8 +183,8 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags))
|
||||
require.Equal(t, int64(1), proposal1.ProposalID)
|
||||
require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status)
|
||||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%s --deposit=10steak --proposalID=1 --from=foo", flags, fooAddr), pass)
|
||||
tests.WaitForNextHeightTM(port)
|
||||
|
@ -192,15 +192,15 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags))
|
||||
require.Equal(t, int64(1), proposal1.ProposalID)
|
||||
require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status)
|
||||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%s --option=Yes --from=foo", flags, fooAddr), pass)
|
||||
tests.WaitForNextHeightTM(port)
|
||||
|
||||
vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%s --output=json %v", fooAddr, flags))
|
||||
require.Equal(t, int64(1), vote.ProposalID)
|
||||
require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option)
|
||||
require.Equal(t, gov.OptionYes, vote.Option)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
@ -288,18 +288,18 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
|||
return validator
|
||||
}
|
||||
|
||||
func executeGetProposal(t *testing.T, cmdStr string) gov.ProposalRest {
|
||||
func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
var proposal gov.ProposalRest
|
||||
var proposal gov.Proposal
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &proposal)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return proposal
|
||||
}
|
||||
|
||||
func executeGetVote(t *testing.T, cmdStr string) gov.VoteRest {
|
||||
func executeGetVote(t *testing.T, cmdStr string) gov.Vote {
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
var vote gov.VoteRest
|
||||
var vote gov.Vote
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &vote)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
|
|
|
@ -330,8 +330,9 @@ func (kb dbKeybase) Delete(name, passphrase string) error {
|
|||
// encrypted.
|
||||
//
|
||||
// oldpass must be the current passphrase used for encryption,
|
||||
// newpass will be the only valid passphrase from this time forward.
|
||||
func (kb dbKeybase) Update(name, oldpass, newpass string) error {
|
||||
// getNewpass is a function to get the passphrase to permanently replace
|
||||
// the current passphrase
|
||||
func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -343,6 +344,10 @@ func (kb dbKeybase) Update(name, oldpass, newpass string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newpass, err := getNewpass()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kb.writeLocalKey(key, name, newpass)
|
||||
return nil
|
||||
default:
|
||||
|
|
|
@ -167,9 +167,10 @@ func TestSignVerify(t *testing.T) {
|
|||
}
|
||||
|
||||
func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) {
|
||||
err := cstore.Update(name, badpass, pass)
|
||||
getNewpass := func() (string, error) { return pass, nil }
|
||||
err := cstore.Update(name, badpass, getNewpass)
|
||||
require.NotNil(t, err)
|
||||
err = cstore.Update(name, pass, pass)
|
||||
err = cstore.Update(name, pass, getNewpass)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
}
|
||||
|
||||
|
@ -265,12 +266,13 @@ func TestAdvancedKeyManagement(t *testing.T) {
|
|||
assertPassword(t, cstore, n1, p1, p2)
|
||||
|
||||
// update password requires the existing password
|
||||
err = cstore.Update(n1, "jkkgkg", p2)
|
||||
getNewpass := func() (string, error) { return p2, nil }
|
||||
err = cstore.Update(n1, "jkkgkg", getNewpass)
|
||||
require.NotNil(t, err)
|
||||
assertPassword(t, cstore, n1, p1, p2)
|
||||
|
||||
// then it changes the password when correct
|
||||
err = cstore.Update(n1, p1, p2)
|
||||
err = cstore.Update(n1, p1, getNewpass)
|
||||
require.NoError(t, err)
|
||||
// p2 is now the proper one!
|
||||
assertPassword(t, cstore, n1, p2, p1)
|
||||
|
|
|
@ -34,7 +34,7 @@ type Keybase interface {
|
|||
CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error)
|
||||
|
||||
// The following operations will *only* work on locally-stored keys
|
||||
Update(name, oldpass, newpass string) error
|
||||
Update(name, oldpass string, getNewpass func() (string, error)) error
|
||||
Import(name string, armor string) (err error)
|
||||
ImportPubKey(name string, armor string) (err error)
|
||||
Export(name string) (armor string, err error)
|
||||
|
|
|
@ -48,7 +48,7 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
proposalType, err := gov.StringToProposalType(strProposalType)
|
||||
proposalType, err := gov.ProposalTypeFromString(strProposalType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
option := viper.GetString(flagOption)
|
||||
|
||||
byteVoteOption, err := gov.StringToVoteOption(option)
|
||||
byteVoteOption, err := gov.VoteOptionFromString(option)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, gov.VoteOptionToString(msg.Option))
|
||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, msg.Option)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
@ -195,8 +195,7 @@ func GetCmdQueryProposal(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
proposalRest := gov.ProposalToRest(proposal)
|
||||
output, err := wire.MarshalJSONIndent(cdc, proposalRest)
|
||||
output, err := wire.MarshalJSONIndent(cdc, proposal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -232,8 +231,7 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
var vote gov.Vote
|
||||
cdc.MustUnmarshalBinary(res, &vote)
|
||||
voteRest := gov.VoteToRest(vote)
|
||||
output, err := wire.MarshalJSONIndent(cdc, voteRest)
|
||||
output, err := wire.MarshalJSONIndent(cdc, vote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -36,24 +36,24 @@ func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
|
|||
}
|
||||
|
||||
type postProposalReq struct {
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Title string `json:"title"` // Title of the proposal
|
||||
Description string `json:"description"` // Description of the proposal
|
||||
ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
Proposer string `json:"proposer"` // Address of the proposer
|
||||
InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Title string `json:"title"` // Title of the proposal
|
||||
Description string `json:"description"` // Description of the proposal
|
||||
ProposalType gov.ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer
|
||||
InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit
|
||||
}
|
||||
|
||||
type depositReq struct {
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Depositer string `json:"depositer"` // Address of the depositer
|
||||
Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
|
||||
Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit
|
||||
}
|
||||
|
||||
type voteReq struct {
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Voter string `json:"voter"` // address of the voter
|
||||
Option string `json:"option"` // option from OptionSet chosen by the voter
|
||||
BaseReq baseReq `json:"base_req"`
|
||||
Voter sdk.AccAddress `json:"voter"` // address of the voter
|
||||
Option gov.VoteOption `json:"option"` // option from OptionSet chosen by the voter
|
||||
}
|
||||
|
||||
func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
|
||||
|
@ -68,20 +68,8 @@ func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.Handle
|
|||
return
|
||||
}
|
||||
|
||||
proposer, err := sdk.AccAddressFromBech32(req.Proposer)
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
proposalTypeByte, err := gov.StringToProposalType(req.ProposalType)
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// create the message
|
||||
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, proposalTypeByte, proposer, req.InitialDeposit)
|
||||
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, req.ProposalType, req.Proposer, req.InitialDeposit)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
|
@ -117,19 +105,12 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !req.BaseReq.baseReqValidate(w) {
|
||||
return
|
||||
}
|
||||
|
||||
depositer, err := sdk.AccAddressFromBech32(req.Depositer)
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// create the message
|
||||
msg := gov.NewMsgDeposit(depositer, proposalID, req.Amount)
|
||||
msg := gov.NewMsgDeposit(req.Depositer, proposalID, req.Amount)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
|
@ -165,25 +146,12 @@ func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !req.BaseReq.baseReqValidate(w) {
|
||||
return
|
||||
}
|
||||
|
||||
voter, err := sdk.AccAddressFromBech32(req.Voter)
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
voteOptionByte, err := gov.StringToVoteOption(req.Option)
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// create the message
|
||||
msg := gov.NewMsgVote(voter, proposalID, voteOptionByte)
|
||||
msg := gov.NewMsgVote(req.Voter, proposalID, req.Option)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
writeErr(&w, http.StatusBadRequest, err.Error())
|
||||
|
@ -225,8 +193,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
proposalRest := gov.ProposalToRest(proposal)
|
||||
output, err := wire.MarshalJSONIndent(cdc, proposalRest)
|
||||
output, err := wire.MarshalJSONIndent(cdc, proposal)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -291,8 +258,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
var deposit gov.Deposit
|
||||
cdc.MustUnmarshalBinary(res, &deposit)
|
||||
depositRest := gov.DepositToRest(deposit)
|
||||
output, err := wire.MarshalJSONIndent(cdc, depositRest)
|
||||
output, err := wire.MarshalJSONIndent(cdc, deposit)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -358,8 +324,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
var vote gov.Vote
|
||||
cdc.MustUnmarshalBinary(res, &vote)
|
||||
voteRest := gov.VoteToRest(vote)
|
||||
output, err := wire.MarshalJSONIndent(cdc, voteRest)
|
||||
output, err := wire.MarshalJSONIndent(cdc, vote)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -411,7 +376,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
var maxProposalID int64
|
||||
cdc.MustUnmarshalBinary(res, &maxProposalID)
|
||||
|
||||
matchingProposals := []gov.ProposalRest{}
|
||||
matchingProposals := []gov.Proposal{}
|
||||
|
||||
for proposalID := int64(0); proposalID < maxProposalID; proposalID++ {
|
||||
if voterAddr != nil {
|
||||
|
@ -435,7 +400,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
|
||||
matchingProposals = append(matchingProposals, gov.ProposalToRest(proposal))
|
||||
matchingProposals = append(matchingProposals, proposal)
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, matchingProposals)
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
package gov
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Type that represents VoteOption as a byte
|
||||
type VoteOption = byte
|
||||
|
||||
//nolint
|
||||
const (
|
||||
OptionEmpty VoteOption = 0x00
|
||||
OptionYes VoteOption = 0x01
|
||||
OptionAbstain VoteOption = 0x02
|
||||
OptionNo VoteOption = 0x03
|
||||
OptionNoWithVeto VoteOption = 0x04
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Vote
|
||||
|
@ -30,9 +22,80 @@ type Deposit struct {
|
|||
Amount sdk.Coins `json:"amount"` // Deposit amount
|
||||
}
|
||||
|
||||
// ProposalTypeToString for pretty prints of ProposalType
|
||||
func VoteOptionToString(option VoteOption) string {
|
||||
switch option {
|
||||
// Type that represents VoteOption as a byte
|
||||
type VoteOption byte
|
||||
|
||||
//nolint
|
||||
const (
|
||||
OptionEmpty VoteOption = 0x00
|
||||
OptionYes VoteOption = 0x01
|
||||
OptionAbstain VoteOption = 0x02
|
||||
OptionNo VoteOption = 0x03
|
||||
OptionNoWithVeto VoteOption = 0x04
|
||||
)
|
||||
|
||||
// String to proposalType byte. Returns ff if invalid.
|
||||
func VoteOptionFromString(str string) (VoteOption, error) {
|
||||
switch str {
|
||||
case "Yes":
|
||||
return OptionYes, nil
|
||||
case "Abstain":
|
||||
return OptionAbstain, nil
|
||||
case "No":
|
||||
return OptionNo, nil
|
||||
case "NoWithVeto":
|
||||
return OptionNoWithVeto, nil
|
||||
default:
|
||||
return VoteOption(0xff), errors.Errorf("'%s' is not a valid vote option", str)
|
||||
}
|
||||
}
|
||||
|
||||
// Is defined VoteOption
|
||||
func validVoteOption(option VoteOption) bool {
|
||||
if option == OptionYes ||
|
||||
option == OptionAbstain ||
|
||||
option == OptionNo ||
|
||||
option == OptionNoWithVeto {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Marshal needed for protobuf compatibility
|
||||
func (vo VoteOption) Marshal() ([]byte, error) {
|
||||
return []byte{byte(vo)}, nil
|
||||
}
|
||||
|
||||
// Unmarshal needed for protobuf compatibility
|
||||
func (vo *VoteOption) Unmarshal(data []byte) error {
|
||||
*vo = VoteOption(data[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshals to JSON using string
|
||||
func (vo VoteOption) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(vo.String())
|
||||
}
|
||||
|
||||
// Unmarshals from JSON assuming Bech32 encoding
|
||||
func (vo *VoteOption) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
err := json.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bz2, err := VoteOptionFromString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*vo = bz2
|
||||
return nil
|
||||
}
|
||||
|
||||
// Turns VoteOption byte to String
|
||||
func (vo VoteOption) String() string {
|
||||
switch vo {
|
||||
case OptionYes:
|
||||
return "Yes"
|
||||
case OptionAbstain:
|
||||
|
@ -46,63 +109,12 @@ func VoteOptionToString(option VoteOption) string {
|
|||
}
|
||||
}
|
||||
|
||||
func validVoteOption(option VoteOption) bool {
|
||||
if option == OptionYes ||
|
||||
option == OptionAbstain ||
|
||||
option == OptionNo ||
|
||||
option == OptionNoWithVeto {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// String to proposalType byte. Returns ff if invalid.
|
||||
func StringToVoteOption(str string) (VoteOption, sdk.Error) {
|
||||
switch str {
|
||||
case "Yes":
|
||||
return OptionYes, nil
|
||||
case "Abstain":
|
||||
return OptionAbstain, nil
|
||||
case "No":
|
||||
return OptionNo, nil
|
||||
case "NoWithVeto":
|
||||
return OptionNoWithVeto, nil
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
func (vo VoteOption) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
s.Write([]byte(fmt.Sprintf("%s", vo.String())))
|
||||
default:
|
||||
return VoteOption(0xff), ErrInvalidVote(DefaultCodespace, str)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// REST
|
||||
|
||||
// Rest Deposits
|
||||
type DepositRest struct {
|
||||
Depositer sdk.AccAddress `json:"depositer"` // address of the depositer
|
||||
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal
|
||||
Amount sdk.Coins `json:"option"`
|
||||
}
|
||||
|
||||
// Turn any Deposit to a DepositRest
|
||||
func DepositToRest(deposit Deposit) DepositRest {
|
||||
return DepositRest{
|
||||
Depositer: deposit.Depositer,
|
||||
ProposalID: deposit.ProposalID,
|
||||
Amount: deposit.Amount,
|
||||
}
|
||||
}
|
||||
|
||||
// Rest Votes
|
||||
type VoteRest struct {
|
||||
Voter sdk.AccAddress `json:"voter"` // address of the voter
|
||||
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal
|
||||
Option string `json:"option"`
|
||||
}
|
||||
|
||||
// Turn any Vote to a VoteRest
|
||||
func VoteToRest(vote Vote) VoteRest {
|
||||
return VoteRest{
|
||||
Voter: vote.Voter,
|
||||
ProposalID: vote.ProposalID,
|
||||
Option: VoteOptionToString(vote.Option),
|
||||
s.Write([]byte(fmt.Sprintf("%v", byte(vo))))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ const (
|
|||
CodeInvalidProposalType sdk.CodeType = 8
|
||||
CodeInvalidVote sdk.CodeType = 9
|
||||
CodeInvalidGenesis sdk.CodeType = 10
|
||||
CodeInvalidProposalStatus sdk.CodeType = 11
|
||||
)
|
||||
|
||||
//----------------------------------------
|
||||
|
@ -53,12 +54,12 @@ func ErrInvalidDescription(codespace sdk.CodespaceType, description string) sdk.
|
|||
return sdk.NewError(codespace, CodeInvalidDescription, fmt.Sprintf("Proposal Desciption '%s' is not valid", description))
|
||||
}
|
||||
|
||||
func ErrInvalidProposalType(codespace sdk.CodespaceType, strProposalType string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidProposalType, fmt.Sprintf("Proposal Type '%s' is not valid", strProposalType))
|
||||
func ErrInvalidProposalType(codespace sdk.CodespaceType, proposalType ProposalKind) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidProposalType, fmt.Sprintf("Proposal Type '%s' is not valid", proposalType))
|
||||
}
|
||||
|
||||
func ErrInvalidVote(codespace sdk.CodespaceType, strOption string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidVote, fmt.Sprintf("'%s' is not a valid voting option", strOption))
|
||||
func ErrInvalidVote(codespace sdk.CodespaceType, voteOption VoteOption) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidVote, fmt.Sprintf("'%v' is not a valid voting option", voteOption))
|
||||
}
|
||||
|
||||
func ErrInvalidGenesis(codespace sdk.CodespaceType, msg string) sdk.Error {
|
||||
|
|
|
@ -48,7 +48,7 @@ func (keeper Keeper) WireCodec() *wire.Codec {
|
|||
// Proposals
|
||||
|
||||
// Creates a NewProposal
|
||||
func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description string, proposalType byte) Proposal {
|
||||
func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description string, proposalType ProposalKind) Proposal {
|
||||
proposalID, err := keeper.getNewProposalID(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
@ -165,8 +165,8 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID int64, voterAddr sdk.Ac
|
|||
return ErrInactiveProposal(keeper.codespace, proposalID)
|
||||
}
|
||||
|
||||
if option != OptionYes && option != OptionAbstain && option != OptionNo && option != OptionNoWithVeto {
|
||||
return ErrInvalidVote(keeper.codespace, VoteOptionToString(option))
|
||||
if !validVoteOption(option) {
|
||||
return ErrInvalidVote(keeper.codespace, option)
|
||||
}
|
||||
|
||||
vote := Vote{
|
||||
|
|
|
@ -41,7 +41,7 @@ func (msg MsgSubmitProposal) ValidateBasic() sdk.Error {
|
|||
return ErrInvalidDescription(DefaultCodespace, msg.Description) // TODO: Proper Error
|
||||
}
|
||||
if !validProposalType(msg.ProposalType) {
|
||||
return ErrInvalidProposalType(DefaultCodespace, ProposalTypeToString(msg.ProposalType))
|
||||
return ErrInvalidProposalType(DefaultCodespace, msg.ProposalType)
|
||||
}
|
||||
if len(msg.Proposer) == 0 {
|
||||
return sdk.ErrInvalidAddress(msg.Proposer.String())
|
||||
|
@ -56,7 +56,7 @@ func (msg MsgSubmitProposal) ValidateBasic() sdk.Error {
|
|||
}
|
||||
|
||||
func (msg MsgSubmitProposal) String() string {
|
||||
return fmt.Sprintf("MsgSubmitProposal{%v, %v, %v, %v}", msg.Title, msg.Description, ProposalTypeToString(msg.ProposalType), msg.InitialDeposit)
|
||||
return fmt.Sprintf("MsgSubmitProposal{%s, %s, %s, %v}", msg.Title, msg.Description, msg.ProposalType, msg.InitialDeposit)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -66,19 +66,7 @@ func (msg MsgSubmitProposal) Get(key interface{}) (value interface{}) {
|
|||
|
||||
// Implements Msg.
|
||||
func (msg MsgSubmitProposal) GetSignBytes() []byte {
|
||||
b, err := msgCdc.MarshalJSON(struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
ProposalType string `json:"proposal_type"`
|
||||
Proposer sdk.AccAddress `json:"proposer"`
|
||||
InitialDeposit sdk.Coins `json:"deposit"`
|
||||
}{
|
||||
Title: msg.Title,
|
||||
Description: msg.Description,
|
||||
ProposalType: ProposalTypeToString(msg.ProposalType),
|
||||
Proposer: msg.Proposer,
|
||||
InitialDeposit: msg.InitialDeposit,
|
||||
})
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -127,7 +115,7 @@ func (msg MsgDeposit) ValidateBasic() sdk.Error {
|
|||
}
|
||||
|
||||
func (msg MsgDeposit) String() string {
|
||||
return fmt.Sprintf("MsgDeposit{%v=>%v: %v}", msg.Depositer, msg.ProposalID, msg.Amount)
|
||||
return fmt.Sprintf("MsgDeposit{%s=>%v: %v}", msg.Depositer, msg.ProposalID, msg.Amount)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -137,15 +125,7 @@ func (msg MsgDeposit) Get(key interface{}) (value interface{}) {
|
|||
|
||||
// Implements Msg.
|
||||
func (msg MsgDeposit) GetSignBytes() []byte {
|
||||
b, err := msgCdc.MarshalJSON(struct {
|
||||
ProposalID int64 `json:"proposalID"`
|
||||
Depositer sdk.AccAddress `json:"proposer"`
|
||||
Amount sdk.Coins `json:"deposit"`
|
||||
}{
|
||||
ProposalID: msg.ProposalID,
|
||||
Depositer: msg.Depositer,
|
||||
Amount: msg.Amount,
|
||||
})
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -185,13 +165,13 @@ func (msg MsgVote) ValidateBasic() sdk.Error {
|
|||
return ErrUnknownProposal(DefaultCodespace, msg.ProposalID)
|
||||
}
|
||||
if !validVoteOption(msg.Option) {
|
||||
return ErrInvalidVote(DefaultCodespace, VoteOptionToString(msg.Option))
|
||||
return ErrInvalidVote(DefaultCodespace, msg.Option)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg MsgVote) String() string {
|
||||
return fmt.Sprintf("MsgVote{%v - %v}", msg.ProposalID, msg.Option)
|
||||
return fmt.Sprintf("MsgVote{%v - %s}", msg.ProposalID, msg.Option)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -201,15 +181,7 @@ func (msg MsgVote) Get(key interface{}) (value interface{}) {
|
|||
|
||||
// Implements Msg.
|
||||
func (msg MsgVote) GetSignBytes() []byte {
|
||||
b, err := msgCdc.MarshalJSON(struct {
|
||||
ProposalID int64 `json:"proposalID"`
|
||||
Voter sdk.AccAddress `json:"voter"`
|
||||
Option string `json:"option"`
|
||||
}{
|
||||
ProposalID: msg.ProposalID,
|
||||
Voter: msg.Voter,
|
||||
Option: VoteOptionToString(msg.Option),
|
||||
})
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestMsgSubmitProposal(t *testing.T) {
|
|||
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
|
||||
tests := []struct {
|
||||
title, description string
|
||||
proposalType byte
|
||||
proposalType ProposalKind
|
||||
proposerAddr sdk.AccAddress
|
||||
initialDeposit sdk.Coins
|
||||
expectPass bool
|
||||
|
|
|
@ -1,27 +1,14 @@
|
|||
package gov
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Type that represents Status as a byte
|
||||
type VoteStatus = byte
|
||||
|
||||
// Type that represents Proposal Type as a byte
|
||||
type ProposalKind = byte
|
||||
|
||||
//nolint
|
||||
const (
|
||||
StatusDepositPeriod VoteStatus = 0x01
|
||||
StatusVotingPeriod VoteStatus = 0x02
|
||||
StatusPassed VoteStatus = 0x03
|
||||
StatusRejected VoteStatus = 0x04
|
||||
|
||||
ProposalTypeText ProposalKind = 0x01
|
||||
ProposalTypeParameterChange ProposalKind = 0x02
|
||||
ProposalTypeSoftwareUpgrade ProposalKind = 0x03
|
||||
)
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Proposal interface
|
||||
type Proposal interface {
|
||||
|
@ -37,8 +24,8 @@ type Proposal interface {
|
|||
GetProposalType() ProposalKind
|
||||
SetProposalType(ProposalKind)
|
||||
|
||||
GetStatus() VoteStatus
|
||||
SetStatus(VoteStatus)
|
||||
GetStatus() ProposalStatus
|
||||
SetStatus(ProposalStatus)
|
||||
|
||||
GetSubmitBlock() int64
|
||||
SetSubmitBlock(int64)
|
||||
|
@ -73,7 +60,7 @@ type TextProposal struct {
|
|||
Description string `json:"description"` // Description of the proposal
|
||||
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
|
||||
Status VoteStatus `json:"string"` // Status of the Proposal {Pending, Active, Passed, Rejected}
|
||||
Status ProposalStatus `json:"string"` // Status of the Proposal {Pending, Active, Passed, Rejected}
|
||||
|
||||
SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
|
||||
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||
|
@ -93,8 +80,8 @@ func (tp TextProposal) GetDescription() string { return tp.D
|
|||
func (tp *TextProposal) SetDescription(description string) { tp.Description = description }
|
||||
func (tp TextProposal) GetProposalType() ProposalKind { return tp.ProposalType }
|
||||
func (tp *TextProposal) SetProposalType(proposalType ProposalKind) { tp.ProposalType = proposalType }
|
||||
func (tp TextProposal) GetStatus() VoteStatus { return tp.Status }
|
||||
func (tp *TextProposal) SetStatus(status VoteStatus) { tp.Status = status }
|
||||
func (tp TextProposal) GetStatus() ProposalStatus { return tp.Status }
|
||||
func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status }
|
||||
func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock }
|
||||
func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock }
|
||||
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
|
||||
|
@ -104,12 +91,82 @@ func (tp *TextProposal) SetVotingStartBlock(votingStartBlock int64) {
|
|||
tp.VotingStartBlock = votingStartBlock
|
||||
}
|
||||
|
||||
// Current Active Proposals
|
||||
//-----------------------------------------------------------
|
||||
// ProposalQueue
|
||||
type ProposalQueue []int64
|
||||
|
||||
// ProposalTypeToString for pretty prints of ProposalType
|
||||
func ProposalTypeToString(proposalType ProposalKind) string {
|
||||
switch proposalType {
|
||||
//-----------------------------------------------------------
|
||||
// ProposalKind
|
||||
|
||||
// Type that represents Proposal Type as a byte
|
||||
type ProposalKind byte
|
||||
|
||||
//nolint
|
||||
const (
|
||||
ProposalTypeText ProposalKind = 0x01
|
||||
ProposalTypeParameterChange ProposalKind = 0x02
|
||||
ProposalTypeSoftwareUpgrade ProposalKind = 0x03
|
||||
)
|
||||
|
||||
// String to proposalType byte. Returns ff if invalid.
|
||||
func ProposalTypeFromString(str string) (ProposalKind, error) {
|
||||
switch str {
|
||||
case "Text":
|
||||
return ProposalTypeText, nil
|
||||
case "ParameterChange":
|
||||
return ProposalTypeParameterChange, nil
|
||||
case "SoftwareUpgrade":
|
||||
return ProposalTypeSoftwareUpgrade, nil
|
||||
default:
|
||||
return ProposalKind(0xff), errors.Errorf("'%s' is not a valid proposal type", str)
|
||||
}
|
||||
}
|
||||
|
||||
// is defined ProposalType?
|
||||
func validProposalType(pt ProposalKind) bool {
|
||||
if pt == ProposalTypeText ||
|
||||
pt == ProposalTypeParameterChange ||
|
||||
pt == ProposalTypeSoftwareUpgrade {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Marshal needed for protobuf compatibility
|
||||
func (pt ProposalKind) Marshal() ([]byte, error) {
|
||||
return []byte{byte(pt)}, nil
|
||||
}
|
||||
|
||||
// Unmarshal needed for protobuf compatibility
|
||||
func (pt *ProposalKind) Unmarshal(data []byte) error {
|
||||
*pt = ProposalKind(data[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshals to JSON using string
|
||||
func (pt ProposalKind) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(pt.String())
|
||||
}
|
||||
|
||||
// Unmarshals from JSON assuming Bech32 encoding
|
||||
func (pt *ProposalKind) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
err := json.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bz2, err := ProposalTypeFromString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*pt = bz2
|
||||
return nil
|
||||
}
|
||||
|
||||
// Turns VoteOption byte to String
|
||||
func (pt ProposalKind) String() string {
|
||||
switch pt {
|
||||
case 0x00:
|
||||
return "Text"
|
||||
case 0x01:
|
||||
|
@ -121,31 +178,91 @@ func ProposalTypeToString(proposalType ProposalKind) string {
|
|||
}
|
||||
}
|
||||
|
||||
func validProposalType(proposalType ProposalKind) bool {
|
||||
if proposalType == ProposalTypeText ||
|
||||
proposalType == ProposalTypeParameterChange ||
|
||||
proposalType == ProposalTypeSoftwareUpgrade {
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
func (pt ProposalKind) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
s.Write([]byte(fmt.Sprintf("%s", pt.String())))
|
||||
default:
|
||||
s.Write([]byte(fmt.Sprintf("%v", pt)))
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// ProposalStatus
|
||||
|
||||
// Type that represents Proposal Status as a byte
|
||||
type ProposalStatus byte
|
||||
|
||||
//nolint
|
||||
const (
|
||||
StatusDepositPeriod ProposalStatus = 0x01
|
||||
StatusVotingPeriod ProposalStatus = 0x02
|
||||
StatusPassed ProposalStatus = 0x03
|
||||
StatusRejected ProposalStatus = 0x04
|
||||
)
|
||||
|
||||
// ProposalStatusToString turns a string into a ProposalStatus
|
||||
func ProposalStatusFromString(str string) (ProposalStatus, error) {
|
||||
switch str {
|
||||
case "DepositPeriod":
|
||||
return StatusDepositPeriod, nil
|
||||
case "VotingPeriod":
|
||||
return StatusVotingPeriod, nil
|
||||
case "Passed":
|
||||
return StatusPassed, nil
|
||||
case "Rejected":
|
||||
return StatusRejected, nil
|
||||
default:
|
||||
return ProposalStatus(0xff), errors.Errorf("'%s' is not a valid proposal status", str)
|
||||
}
|
||||
}
|
||||
|
||||
// is defined ProposalType?
|
||||
func validProposalStatus(status ProposalStatus) bool {
|
||||
if status == StatusDepositPeriod ||
|
||||
status == StatusVotingPeriod ||
|
||||
status == StatusPassed ||
|
||||
status == StatusRejected {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// String to proposalType byte. Returns ff if invalid.
|
||||
func StringToProposalType(str string) (ProposalKind, sdk.Error) {
|
||||
switch str {
|
||||
case "Text":
|
||||
return ProposalTypeText, nil
|
||||
case "ParameterChange":
|
||||
return ProposalTypeParameterChange, nil
|
||||
case "SoftwareUpgrade":
|
||||
return ProposalTypeSoftwareUpgrade, nil
|
||||
default:
|
||||
return ProposalKind(0xff), ErrInvalidProposalType(DefaultCodespace, str)
|
||||
}
|
||||
// Marshal needed for protobuf compatibility
|
||||
func (status ProposalStatus) Marshal() ([]byte, error) {
|
||||
return []byte{byte(status)}, nil
|
||||
}
|
||||
|
||||
// StatusToString for pretty prints of Status
|
||||
func StatusToString(status VoteStatus) string {
|
||||
// Unmarshal needed for protobuf compatibility
|
||||
func (status *ProposalStatus) Unmarshal(data []byte) error {
|
||||
*status = ProposalStatus(data[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshals to JSON using string
|
||||
func (status ProposalStatus) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(status.String())
|
||||
}
|
||||
|
||||
// Unmarshals from JSON assuming Bech32 encoding
|
||||
func (status *ProposalStatus) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
err := json.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bz2, err := ProposalStatusFromString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*status = bz2
|
||||
return nil
|
||||
}
|
||||
|
||||
// Turns VoteStatus byte to String
|
||||
func (status ProposalStatus) String() string {
|
||||
switch status {
|
||||
case StatusDepositPeriod:
|
||||
return "DepositPeriod"
|
||||
|
@ -160,45 +277,12 @@ func StatusToString(status VoteStatus) string {
|
|||
}
|
||||
}
|
||||
|
||||
// StatusToString for pretty prints of Status
|
||||
func StringToStatus(status string) VoteStatus {
|
||||
switch status {
|
||||
case "DepositPeriod":
|
||||
return StatusDepositPeriod
|
||||
case "VotingPeriod":
|
||||
return StatusVotingPeriod
|
||||
case "Passed":
|
||||
return StatusPassed
|
||||
case "Rejected":
|
||||
return StatusRejected
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
func (status ProposalStatus) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
s.Write([]byte(fmt.Sprintf("%s", status.String())))
|
||||
default:
|
||||
return VoteStatus(0xff)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Rest Proposals
|
||||
type ProposalRest struct {
|
||||
ProposalID int64 `json:"proposal_id"` // ID of the proposal
|
||||
Title string `json:"title"` // Title of the proposal
|
||||
Description string `json:"description"` // Description of the proposal
|
||||
ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
Status string `json:"string"` // Status of the Proposal {Pending, Active, Passed, Rejected}
|
||||
SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
|
||||
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||
VotingStartBlock int64 `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
|
||||
}
|
||||
|
||||
// Turn any Proposal to a ProposalRest
|
||||
func ProposalToRest(proposal Proposal) ProposalRest {
|
||||
return ProposalRest{
|
||||
ProposalID: proposal.GetProposalID(),
|
||||
Title: proposal.GetTitle(),
|
||||
Description: proposal.GetDescription(),
|
||||
ProposalType: ProposalTypeToString(proposal.GetProposalType()),
|
||||
Status: StatusToString(proposal.GetStatus()),
|
||||
SubmitBlock: proposal.GetSubmitBlock(),
|
||||
TotalDeposit: proposal.GetTotalDeposit(),
|
||||
VotingStartBlock: proposal.GetVotingStartBlock(),
|
||||
s.Write([]byte(fmt.Sprintf("%v", status)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,132 +191,152 @@ func (k Keeper) ClearTendermintUpdates(ctx sdk.Context) {
|
|||
|
||||
//___________________________________________________________________________
|
||||
|
||||
// perfom all the nessisary steps for when a validator changes its power
|
||||
// updates all validator stores as well as tendermint update store
|
||||
// may kick out validators if new validator is entering the bonded validator group
|
||||
// Perfom all the nessisary steps for when a validator changes its power. This
|
||||
// function updates all validator stores as well as tendermint update store.
|
||||
// It may kick out validators if new validator is entering the bonded validator
|
||||
// group.
|
||||
//
|
||||
// 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)
|
||||
pool := k.GetPool(ctx)
|
||||
ownerAddr := validator.Owner
|
||||
oldValidator, oldFound := k.GetValidator(ctx, validator.Owner)
|
||||
|
||||
// always update the main list ordered by owner address before exiting
|
||||
defer func() {
|
||||
k.SetValidator(ctx, validator)
|
||||
}()
|
||||
validator = k.updateForRevoking(ctx, oldFound, oldValidator, validator)
|
||||
powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator)
|
||||
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator, validator)
|
||||
valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool)
|
||||
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||
|
||||
// retrieve the old validator record
|
||||
oldValidator, oldFound := k.GetValidator(ctx, ownerAddr)
|
||||
switch {
|
||||
// if already bonded and power increasing only need to update tendermint
|
||||
case powerIncreasing && !validator.Revoked &&
|
||||
(oldFound && oldValidator.Status() == sdk.Bonded):
|
||||
|
||||
if validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
||||
validator = k.unbondValidator(ctx, validator)
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(validator.Owner), bz)
|
||||
|
||||
// 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
|
||||
// skip to completion
|
||||
|
||||
// if was unbonded and the new power is less than the cliff validator
|
||||
case cliffPower != nil &&
|
||||
(oldFound && oldValidator.Status() == sdk.Unbonded) &&
|
||||
bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower
|
||||
// skip to completion
|
||||
|
||||
// default case - validator was either:
|
||||
// a) not-bonded and now has power-rank greater than cliff validator
|
||||
// b) bonded and now has decreased in power
|
||||
default:
|
||||
|
||||
// update the validator set for this validator
|
||||
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
||||
if updated { // updates to validator occurred to be updated
|
||||
validator = updatedVal
|
||||
} else {
|
||||
|
||||
// if decreased in power but still bonded, update Tendermint validator
|
||||
// (if updatedVal is set, the validator has changed bonding status)
|
||||
stillBonded := oldFound && oldValidator.Status() == sdk.Bonded
|
||||
if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) {
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(validator.Owner), bz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k.SetValidator(ctx, validator)
|
||||
return validator
|
||||
}
|
||||
|
||||
func (k Keeper) updateForRevoking(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator {
|
||||
if newValidator.Revoked && oldFound && oldValidator.Status() == sdk.Bonded {
|
||||
newValidator = k.unbondValidator(ctx, newValidator)
|
||||
|
||||
// need to also clear the cliff validator spot because the revoke has
|
||||
// opened up a new spot which will be filled when
|
||||
// updateValidatorsBonded is called
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
return newValidator
|
||||
}
|
||||
|
||||
powerIncreasing := false
|
||||
if oldFound && oldValidator.PoolShares.Bonded().LT(validator.PoolShares.Bonded()) {
|
||||
powerIncreasing = true
|
||||
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
||||
if oldFound && oldValidator.PoolShares.Bonded().LT(newValidator.PoolShares.Bonded()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// get the bond height and incremented intra-tx counter
|
||||
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
newValidator 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 {
|
||||
validator.BondHeight = oldValidator.BondHeight
|
||||
validator.BondIntraTxCounter = oldValidator.BondIntraTxCounter
|
||||
} else {
|
||||
validator.BondHeight = ctx.BlockHeight()
|
||||
counter := k.GetIntraTxCounter(ctx)
|
||||
validator.BondIntraTxCounter = counter
|
||||
k.SetIntraTxCounter(ctx, counter+1)
|
||||
height = oldValidator.BondHeight
|
||||
intraTxCounter = oldValidator.BondIntraTxCounter
|
||||
return
|
||||
}
|
||||
height = ctx.BlockHeight()
|
||||
counter := k.GetIntraTxCounter(ctx)
|
||||
intraTxCounter = counter
|
||||
k.SetIntraTxCounter(ctx, counter+1)
|
||||
return
|
||||
}
|
||||
|
||||
func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
newValidator types.Validator, pool types.Pool) (valPower []byte) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
// update the list ordered by voting power
|
||||
if oldFound {
|
||||
store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool))
|
||||
}
|
||||
valPower := GetValidatorsByPowerIndexKey(validator, pool)
|
||||
store.Set(valPower, validator.Owner)
|
||||
valPower = GetValidatorsByPowerIndexKey(newValidator, pool)
|
||||
store.Set(valPower, newValidator.Owner)
|
||||
|
||||
// efficiency case:
|
||||
// if already bonded and power increasing only need to update tendermint
|
||||
if powerIncreasing && !validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(ownerAddr), bz)
|
||||
return validator
|
||||
}
|
||||
|
||||
// efficiency case:
|
||||
// if was unbonded/or is a new validator - and the new power is less than the cliff validator
|
||||
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||
if cliffPower != nil &&
|
||||
(!oldFound || (oldFound && oldValidator.Status() == sdk.Unbonded)) &&
|
||||
bytes.Compare(valPower, cliffPower) == -1 { //(valPower < cliffPower
|
||||
return validator
|
||||
}
|
||||
|
||||
// update the validator set for this validator
|
||||
updatedVal := k.UpdateBondedValidators(ctx, validator)
|
||||
if updatedVal.Owner != nil { // updates to validator occurred to be updated
|
||||
validator = updatedVal
|
||||
}
|
||||
// if decreased in power but still bonded, update Tendermint validator
|
||||
// (if updatedVal is set, the validator has changed bonding status)
|
||||
stillBonded := oldFound && oldValidator.Status() == sdk.Bonded && updatedVal.Owner == nil
|
||||
if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) {
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
store.Set(GetTendermintUpdatesKey(ownerAddr), bz)
|
||||
}
|
||||
return validator
|
||||
return valPower
|
||||
}
|
||||
|
||||
// Update the validator group and kick out any old validators. In addition this
|
||||
// function adds (or doesn't add) a validator which has updated its bonded
|
||||
// tokens to the validator group. -> this validator is specified through the
|
||||
// updatedValidatorAddr term.
|
||||
// Update the bonded validator group based on a change to the validator
|
||||
// affectedValidator. This function potentially adds the affectedValidator to
|
||||
// the bonded validator group which kicks out the cliff validator. Under this
|
||||
// situation this function returns the updated affectedValidator.
|
||||
//
|
||||
// The correct subset is retrieved by iterating through an index of the
|
||||
// validators sorted by power, stored using the ValidatorsByPowerIndexKey.
|
||||
// Simultaneously the current validator records are updated in store with the
|
||||
// ValidatorsBondedIndexKey. This store is used to determine if a validator is a
|
||||
// validator without needing to iterate over the subspace as we do in
|
||||
// GetValidators.
|
||||
// The correct bonded subset of validators is retrieved by iterating through an
|
||||
// index of the validators sorted by power, stored using the
|
||||
// ValidatorsByPowerIndexKey. Simultaneously the current validator records are
|
||||
// updated in store with the ValidatorsBondedIndexKey. This store is used to
|
||||
// determine if a validator is a validator without needing to iterate over all
|
||||
// validators.
|
||||
//
|
||||
// Optionally also return the validator from a retrieve address if the validator has been bonded
|
||||
// nolint: gocyclo
|
||||
// TODO: Remove the above golint
|
||||
func (k Keeper) UpdateBondedValidators(ctx sdk.Context,
|
||||
affectedValidator types.Validator) (updatedVal types.Validator) {
|
||||
affectedValidator types.Validator) (updatedVal types.Validator, updated bool) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
kickCliffValidator := false
|
||||
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
||||
|
||||
// add the actual validator power sorted store
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
||||
bondedValidatorsCount := 0
|
||||
var validator types.Validator
|
||||
var validator, validatorToBond types.Validator
|
||||
newValidatorBonded := false
|
||||
|
||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
||||
for {
|
||||
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
||||
|
||||
// TODO benchmark if we should read the current power and not write if it's the same
|
||||
if bondedValidatorsCount == int(maxValidators) { // is cliff validator
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
} else if len(oldCliffValidatorAddr) > 0 {
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// either retrieve the original validator from the store, or under the
|
||||
// situation that this is the "new validator" just use the validator
|
||||
// provided because it has not yet been updated in the main validator
|
||||
// store
|
||||
// situation that this is the "affected validator" just use the
|
||||
// validator provided because it has not yet been updated in the store
|
||||
ownerAddr := iterator.Value()
|
||||
if bytes.Equal(ownerAddr, affectedValidator.Owner) {
|
||||
validator = affectedValidator
|
||||
|
@ -328,39 +348,50 @@ func (k Keeper) UpdateBondedValidators(ctx sdk.Context,
|
|||
}
|
||||
}
|
||||
|
||||
// if not previously a validator (and unrevoked),
|
||||
// kick the cliff validator / bond this new validator
|
||||
if validator.Status() != sdk.Bonded && !validator.Revoked {
|
||||
kickCliffValidator = true
|
||||
|
||||
validator = k.bondValidator(ctx, validator)
|
||||
if bytes.Equal(ownerAddr, affectedValidator.Owner) {
|
||||
updatedVal = validator
|
||||
}
|
||||
}
|
||||
|
||||
// increment bondedValidatorsCount / get the validator to bond
|
||||
if !validator.Revoked {
|
||||
bondedValidatorsCount++
|
||||
} else {
|
||||
if validator.Status() == sdk.Bonded {
|
||||
panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr))
|
||||
if validator.Status() != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
newValidatorBonded = true
|
||||
}
|
||||
bondedValidatorsCount++
|
||||
|
||||
// sanity check
|
||||
} else if validator.Status() == sdk.Bonded {
|
||||
panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr))
|
||||
}
|
||||
|
||||
iterator.Next()
|
||||
}
|
||||
iterator.Close()
|
||||
|
||||
// perform the actual kicks
|
||||
if oldCliffValidatorAddr != nil && kickCliffValidator {
|
||||
validator, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", oldCliffValidatorAddr))
|
||||
}
|
||||
k.unbondValidator(ctx, validator)
|
||||
// clear or set the cliff validator
|
||||
if bondedValidatorsCount == int(maxValidators) {
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
} else if len(oldCliffValidatorAddr) > 0 {
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
|
||||
return
|
||||
// swap the cliff validator for a new validator if the affected validator was bonded
|
||||
if newValidatorBonded {
|
||||
|
||||
// unbond the cliff validator
|
||||
if oldCliffValidatorAddr != nil {
|
||||
cliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", oldCliffValidatorAddr))
|
||||
}
|
||||
k.unbondValidator(ctx, cliffVal)
|
||||
|
||||
}
|
||||
|
||||
// bond the new validator
|
||||
validator = k.bondValidator(ctx, validatorToBond)
|
||||
if bytes.Equal(validator.Owner, affectedValidator.Owner) {
|
||||
return validator, true
|
||||
}
|
||||
}
|
||||
return types.Validator{}, false
|
||||
}
|
||||
|
||||
// full update of the bonded validator set, many can be added/kicked
|
||||
|
@ -377,17 +408,14 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
|||
}
|
||||
iterator.Close()
|
||||
|
||||
// add the actual validator power sorted store
|
||||
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
||||
bondedValidatorsCount := 0
|
||||
|
||||
iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
||||
var validator types.Validator
|
||||
for {
|
||||
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
||||
|
||||
if bondedValidatorsCount == int(maxValidators) { // is cliff validator
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -425,6 +453,13 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
|||
}
|
||||
iterator.Close()
|
||||
|
||||
// clear or set the cliff validator
|
||||
if bondedValidatorsCount == int(maxValidators) {
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
} else if len(oldCliffValidatorAddr) > 0 {
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
|
||||
// perform the actual kicks
|
||||
kickOutValidators(k, ctx, toKickOut)
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue