Merge branch 'develop' into sunny/get_all_delegations_validator_querier

This commit is contained in:
Christopher Goes 2018-11-09 15:28:03 +01:00 committed by GitHub
commit 4d1246dae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 1667 additions and 837 deletions

View File

@ -137,6 +137,24 @@ jobs:
export PATH="$GOBIN:$PATH"
make test_sim_gaia_fast
test_sim_gaia_import_export:
<<: *defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- run:
name: Test Gaia import/export simulation
command: |
export PATH="$GOBIN:$PATH"
make test_sim_gaia_import_export
test_sim_gaia_multi_seed:
<<: *defaults
parallelism: 1
@ -259,6 +277,9 @@ workflows:
- test_sim_gaia_fast:
requires:
- setup_dependencies
- test_sim_gaia_import_export:
requires:
- setup_dependencies
- test_sim_gaia_multi_seed:
requires:
- setup_dependencies

2
.github/CODEOWNERS vendored
View File

@ -1,7 +1,7 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Primary repo maintainers
* @jaekwon
* @ebuchman @rigelrozanski @cwgoes
# Precious documentation
/docs/ @zramsay @jolesbi

View File

@ -1,5 +1,62 @@
# Changelog
## 0.26.0
BREAKING CHANGES
* Gaia
* [gaiad init] [\#2602](https://github.com/cosmos/cosmos-sdk/issues/2602) New genesis workflow
* SDK
* [simulation] [\#2665](https://github.com/cosmos/cosmos-sdk/issues/2665) only argument to simulation.Invariant is now app
* Tendermint
* Upgrade to version 0.26.0
FEATURES
* Gaia CLI (`gaiacli`)
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
* [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on.
* [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction.
* SDK
* [\#1336](https://github.com/cosmos/cosmos-sdk/issues/1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
IMPROVEMENTS
* Gaia
* [\#2637](https://github.com/cosmos/cosmos-sdk/issues/2637) [x/gov] Switched inactive and active proposal queues to an iterator based queue
* SDK
* [\#2573](https://github.com/cosmos/cosmos-sdk/issues/2573) [x/distribution] add accum invariance
* [\#2556](https://github.com/cosmos/cosmos-sdk/issues/2556) [x/mock/simulation] Fix debugging output
* [\#2396](https://github.com/cosmos/cosmos-sdk/issues/2396) [x/mock/simulation] Change parameters to get more slashes
* [\#2617](https://github.com/cosmos/cosmos-sdk/issues/2617) [x/mock/simulation] Randomize all genesis parameters
* [\#2669](https://github.com/cosmos/cosmos-sdk/issues/2669) [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store.
* [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) [x/mock/simulation] Use a transition matrix for block size
* [\#2660](https://github.com/cosmos/cosmos-sdk/issues/2660) [x/mock/simulation] Staking transactions get tested far more frequently
* [\#2610](https://github.com/cosmos/cosmos-sdk/issues/2610) [x/stake] Block redelegation to and from the same validator
* [\#2652](https://github.com/cosmos/cosmos-sdk/issues/2652) [x/auth] Add benchmark for get and set account
* [\#2685](https://github.com/cosmos/cosmos-sdk/issues/2685) [store] Add general merkle absence proof (also for empty substores)
* [\#2708](https://github.com/cosmos/cosmos-sdk/issues/2708) [store] Disallow setting nil values
BUG FIXES
* Gaia
* [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
* [\#2691](https://github.com/cosmos/cosmos-sdk/issues/2691) Fix local testnet creation by using a single canonical genesis time
- [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
- [\#2648](https://github.com/cosmos/cosmos-sdk/issues/2648) [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI
* SDK
* [\#2625](https://github.com/cosmos/cosmos-sdk/issues/2625) [x/gov] fix AppendTag function usage error
* [\#2677](https://github.com/cosmos/cosmos-sdk/issues/2677) [x/stake, x/distribution] various staking/distribution fixes as found by the simulator
* [\#2674](https://github.com/cosmos/cosmos-sdk/issues/2674) [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see [\#2686](https://github.com/cosmos/cosmos-sdk/issues/2686))
* [\#2711](https://github.com/cosmos/cosmos-sdk/issues/2711) [x/stake] Add commission data to `MsgCreateValidator` signature bytes.
* Temporarily disable insecure mode for Gaia Lite
## 0.25.0
*October 24th, 2018*

9
Gopkg.lock generated
View File

@ -165,13 +165,12 @@
version = "v1.2.0"
[[projects]]
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
@ -435,7 +434,7 @@
version = "v0.11.1"
[[projects]]
digest = "1:92d7d1678577fd1a6f3348168cef87880bbc710ef5f4e9a1216f45c56567d734"
digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
@ -501,7 +500,8 @@
"version",
]
pruneopts = "UT"
revision = "ebee4377b15f2958b08994485375dd2ee8a649ac"
revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de"
version = "v0.26.1-rc0"
[[projects]]
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
@ -689,6 +689,7 @@
"github.com/tendermint/tendermint/rpc/lib/client",
"github.com/tendermint/tendermint/rpc/lib/server",
"github.com/tendermint/tendermint/types",
"github.com/tendermint/tendermint/types/time",
"github.com/tendermint/tendermint/version",
"github.com/zondax/ledger-goclient",
"golang.org/x/crypto/bcrypt",

View File

@ -36,7 +36,7 @@
[[override]]
name = "github.com/tendermint/tendermint"
revision = "ebee4377b15f2958b08994485375dd2ee8a649ac" # TODO replace w/ 0.26.1
version = "v0.26.1-rc0" # TODO replace w/ 0.26.1
## deps without releases:
@ -84,4 +84,3 @@
[prune]
go-tests = true
unused-packages = true

View File

@ -171,6 +171,15 @@ test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h
test_sim_gaia_import_export:
@echo "Running Gaia import/export simulation. This may take several minutes..."
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4 -v -timeout 24h
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=12 -v -timeout 24h
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=13 -v -timeout 24h
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=414 -v -timeout 24h
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4142 -v -timeout 24h
test_sim_gaia_multi_seed:
@echo "Running multi-seed Gaia simulation. This may take awhile!"
@bash scripts/multisim.sh 25
@ -250,4 +259,5 @@ localnet-stop:
check_tools check_dev_tools get_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
build-linux build-docker-gaiadnode localnet-start localnet-stop \
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast test_sim_gaia_multi_seed update_tools update_dev_tools
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools

View File

@ -7,29 +7,22 @@ BREAKING CHANGES
* Gaia CLI (`gaiacli`)
* Gaia
* [gaiad init] \#2602 New genesis workflow
* SDK
* [simulation] \#2665 only argument to simulation.Invariant is now app
* Tendermint
* Upgrade to version 0.26.0
FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)
* Gaia CLI (`gaiacli`)
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
* [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on.
* [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction.
* [stake][cli] [\#2027] Add CLI query command for getting all delegations to a specific validator.
* Gaia
* SDK
* (#1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
* Tendermint
@ -43,16 +36,6 @@ IMPROVEMENTS
* Gaia
* SDK
- \#2573 [x/distribution] add accum invariance
- \#2556 [x/mock/simulation] Fix debugging output
- \#2396 [x/mock/simulation] Change parameters to get more slashes
- \#2617 [x/mock/simulation] Randomize all genesis parameters
- \#2669 [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store.
- \#1924 [x/mock/simulation] Use a transition matrix for block size
- \#2660 [x/mock/simulation] Staking transactions get tested far more frequently
- \#2027 [x/stake] Add `Querier` for getting all delegations to a specific validator.
- \#2610 [x/stake] Block redelegation to and from the same validator
- \#2652 [x/auth] Add benchmark for get and set account
* Tendermint
@ -64,10 +47,7 @@ BUG FIXES
* Gaia CLI (`gaiacli`)
* Gaia
- \#2670 [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
* SDK
- \#2625 [x/gov] fix AppendTag function usage error
- \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator
* Tendermint

View File

@ -632,8 +632,8 @@ func TestSubmitProposal(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal
proposal := getProposal(t, port, proposalID)
@ -654,8 +654,8 @@ func TestDeposit(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal
proposal := getProposal(t, port, proposalID)
@ -688,8 +688,8 @@ func TestVote(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal
proposal := getProposal(t, port, proposalID)
@ -736,18 +736,18 @@ func TestProposalsQuery(t *testing.T) {
// Addr1 proposes (and deposits) proposals #1 and #2
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
var proposalID1 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1)
var proposalID1 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID1)
tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
var proposalID2 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2)
var proposalID2 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID2)
tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 proposes (and deposits) proposals #3
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], 5)
var proposalID3 int64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3)
var proposalID3 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID3)
tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 deposits on proposals #2 & #3
@ -1245,7 +1245,7 @@ func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValA
// ============= Governance Module ================
func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
func getProposal(t *testing.T, port string, proposalID uint64) 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.Proposal
@ -1254,7 +1254,7 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
return proposal
}
func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
func getDeposits(t *testing.T, port string, proposalID uint64) []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
@ -1263,7 +1263,7 @@ func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
return deposits
}
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit {
func getDeposit(t *testing.T, port string, proposalID uint64, 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.Deposit
@ -1272,7 +1272,7 @@ func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.A
return deposit
}
func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddress) gov.Vote {
func getVote(t *testing.T, port string, proposalID uint64, 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.Vote
@ -1281,7 +1281,7 @@ func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddre
return vote
}
func getVotes(t *testing.T, port string, proposalID int64) []gov.Vote {
func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var votes []gov.Vote
@ -1373,7 +1373,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
return results
}
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber()
@ -1403,7 +1403,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
return results
}
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) {
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber()

View File

@ -2,6 +2,11 @@ package lcd
import (
"errors"
"fmt"
"net"
"net/http"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
@ -20,9 +25,6 @@ import (
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
"net"
"net/http"
"os"
)
const (
@ -46,7 +48,9 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) (err error) {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
registerSwaggerUI(handler)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
maxOpen := viper.GetInt(flagMaxOpenConnections)
sslHosts := viper.GetString(flagSSLHosts)
@ -62,14 +66,20 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
})
var cleanupFunc func()
// TODO: re-enable insecure mode once #2715 has been addressed
if viper.GetBool(flagInsecure) {
listener, err = tmserver.StartHTTPServer(
listenAddr, handler, logger,
tmserver.Config{MaxOpenConnections: maxOpen},
fmt.Println(
"Insecure mode is temporarily disabled, please locally generate an " +
"SSL certificate to test. Support will be re-enabled soon!",
)
if err != nil {
return
}
// listener, err = tmserver.StartHTTPServer(
// listenAddr, handler, logger,
// tmserver.Config{MaxOpenConnections: maxOpen},
// )
// if err != nil {
// return
// }
} else {
if certFile != "" {
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
@ -77,6 +87,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
if err != nil {
return err
}
// cert/key pair is provided, read the fingerprint
fingerprint, err = fingerprintFromFile(certFile)
if err != nil {
@ -88,10 +99,12 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
if err != nil {
return err
}
cleanupFunc = func() {
os.Remove(certFile)
os.Remove(keyFile)
}
defer cleanupFunc()
}
@ -104,9 +117,12 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
if err != nil {
return
}
logger.Info(fingerprint)
logger.Info("REST server started")
}
logger.Info("REST server started")
// logger.Info("REST server started")
return nil
},
@ -123,6 +139,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))

View File

@ -65,6 +65,20 @@ func ParseInt64OrReturnBadRequest(w http.ResponseWriter, s string) (n int64, ok
return n, true
}
// ParseUint64OrReturnBadRequest converts s to a uint64 value.
func ParseUint64OrReturnBadRequest(w http.ResponseWriter, s string) (n uint64, ok bool) {
var err error
n, err = strconv.ParseUint(s, 10, 64)
if err != nil {
err := fmt.Errorf("'%s' is not a valid uint64", s)
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return n, false
}
return n, true
}
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a
// default value, defaultIfEmpty, if the string is empty.
func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) {

View File

@ -210,9 +210,6 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
tags := gov.EndBlocker(ctx, app.govKeeper)
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
// Add these new validators to the addr -> pubkey map.
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
Tags: tags,
@ -231,6 +228,10 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
// sort by account number to maintain consistency
sort.Slice(genesisState.Accounts, func(i, j int) bool {
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
})
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
@ -244,7 +245,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
panic(err) // TODO find a way to do this w/o panics
}
// load the address to pubkey map
// initialize module-specific stores
auth.InitGenesis(ctx, app.feeCollectionKeeper, genesisState.AuthData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
@ -270,7 +272,6 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}
app.slashingKeeper.AddValidators(ctx, validators)
// sanity check
if len(req.Validators) > 0 {
@ -306,11 +307,12 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
app.accountKeeper.IterateAccounts(ctx, appendAccount)
genState := NewGenesisState(
accounts,
stake.WriteGenesis(ctx, app.stakeKeeper),
mint.WriteGenesis(ctx, app.mintKeeper),
distr.WriteGenesis(ctx, app.distrKeeper),
gov.WriteGenesis(ctx, app.govKeeper),
slashing.GenesisState{}, // TODO create write methods
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
stake.ExportGenesis(ctx, app.stakeKeeper),
mint.ExportGenesis(ctx, app.mintKeeper),
distr.ExportGenesis(ctx, app.distrKeeper),
gov.ExportGenesis(ctx, app.govKeeper),
slashing.ExportGenesis(ctx, app.slashingKeeper),
)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
@ -337,12 +339,15 @@ var _ sdk.StakingHooks = Hooks{}
// nolint
func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.OnValidatorCreated(ctx, valAddr)
h.sh.OnValidatorCreated(ctx, valAddr)
}
func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.OnValidatorModified(ctx, valAddr)
h.sh.OnValidatorModified(ctx, valAddr)
}
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.OnValidatorRemoved(ctx, valAddr)
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorRemoved(ctx, consAddr, valAddr)
h.sh.OnValidatorRemoved(ctx, consAddr, valAddr)
}
func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorBonded(ctx, consAddr, valAddr)
@ -358,10 +363,13 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre
}
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationCreated(ctx, delAddr, valAddr)
h.sh.OnDelegationCreated(ctx, delAddr, valAddr)
}
func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr)
h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr)
}
func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationRemoved(ctx, delAddr, valAddr)
h.sh.OnDelegationRemoved(ctx, delAddr, valAddr)
}

View File

@ -32,6 +32,7 @@ var (
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
AuthData auth.GenesisState `json:"auth"`
StakeData stake.GenesisState `json:"stake"`
MintData mint.GenesisState `json:"mint"`
DistrData distr.GenesisState `json:"distr"`
@ -40,11 +41,12 @@ type GenesisState struct {
GenTxs []json.RawMessage `json:"gentxs"`
}
func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState,
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState,
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
return GenesisState{
Accounts: accounts,
AuthData: authData,
StakeData: stakeData,
MintData: mintData,
DistrData: distrData,
@ -53,31 +55,39 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi
}
}
// GenesisAccount doesn't need pubkey or sequence
// nolint
type GenesisAccount struct {
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
Sequence int64 `json:"sequence_number"`
AccountNumber int64 `json:"account_number"`
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
Address: acc.Address,
Coins: acc.Coins,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
}
}
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
return GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
AccountNumber: acc.GetAccountNumber(),
Sequence: acc.GetSequence(),
}
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
Address: ga.Address,
Coins: ga.Coins.Sort(),
AccountNumber: ga.AccountNumber,
Sequence: ga.Sequence,
}
}

View File

@ -2,9 +2,10 @@ package app
import (
"encoding/json"
"testing"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmtypes "github.com/tendermint/tendermint/types"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
@ -91,8 +92,10 @@ func TestGaiaAppGenState(t *testing.T) {
func makeMsg(name string, pk crypto.PubKey) auth.StdTx {
desc := stake.NewDescription(name, "", "", "")
comm := stakeTypes.CommissionMsg{}
msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(bondDenom,
50), desc, comm)
msg := stake.NewMsgCreateValidator(
sdk.ValAddress(pk.Address()), pk,
sdk.NewInt64Coin(bondDenom, 50), desc, comm,
)
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
}

View File

@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
@ -70,15 +71,15 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
// Random genesis states
govGenesis := gov.GenesisState{
StartingProposalID: int64(r.Intn(100)),
DepositProcedure: gov.DepositProcedure{
StartingProposalID: uint64(r.Intn(100)),
DepositParams: gov.DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))},
MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
},
VotingProcedure: gov.VotingProcedure{
VotingParams: gov.VotingParams{
VotingPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
},
TallyingProcedure: gov.TallyingProcedure{
TallyParams: gov.TallyParams{
Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
@ -166,7 +167,7 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorRewardsAll(app.accountKeeper, app.distrKeeper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper)},
{100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)},
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
{100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)},
@ -266,6 +267,103 @@ func TestFullGaiaSimulation(t *testing.T) {
require.Nil(t, err)
}
func TestGaiaImportExport(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia import/export simulation")
}
// Setup Gaia application
var logger log.Logger
if verbose {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
db, _ = dbm.NewGoLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
invariants(app),
numBlocks,
blockSize,
commit,
)
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
require.Nil(t, err)
fmt.Printf("Exporting genesis...\n")
appState, _, err := app.ExportAppStateAndValidators()
if err != nil {
panic(err)
}
fmt.Printf("Importing genesis...\n")
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
newDB, _ := dbm.NewGoLevelDB("Simulation-2", dir)
defer func() {
newDB.Close()
os.RemoveAll(newDir)
}()
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
require.Equal(t, "GaiaApp", newApp.Name())
request := abci.RequestInitChain{
AppStateBytes: appState,
}
newApp.InitChain(request)
newApp.Commit()
fmt.Printf("Comparing stores...\n")
ctxA := app.NewContext(true, abci.Header{})
ctxB := newApp.NewContext(true, abci.Header{})
type StoreKeysPrefixes struct {
A sdk.StoreKey
B sdk.StoreKey
Prefixes [][]byte
}
storeKeysPrefixes := []StoreKeysPrefixes{
{app.keyMain, newApp.keyMain, [][]byte{}},
{app.keyAccount, newApp.keyAccount, [][]byte{}},
{app.keyStake, newApp.keyStake, [][]byte{stake.UnbondingQueueKey, stake.RedelegationQueueKey, stake.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keySlashing, newApp.keySlashing, [][]byte{}},
{app.keyMint, newApp.keyMint, [][]byte{}},
{app.keyDistr, newApp.keyDistr, [][]byte{}},
{app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}},
{app.keyParams, newApp.keyParams, [][]byte{}},
{app.keyGov, newApp.keyGov, [][]byte{}},
}
for _, storeKeysPrefix := range storeKeysPrefixes {
storeKeyA := storeKeysPrefix.A
storeKeyB := storeKeysPrefix.B
prefixes := storeKeysPrefix.Prefixes
storeA := ctxA.KVStore(storeKeyA)
storeB := ctxB.KVStore(storeKeyB)
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)",
storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value)
}
}
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on gaia
func TestAppStateDeterminism(t *testing.T) {

View File

@ -5,13 +5,14 @@ package clitest
import (
"encoding/json"
"fmt"
"github.com/tendermint/tendermint/types"
"io/ioutil"
"os"
"path"
"path/filepath"
"testing"
"github.com/tendermint/tendermint/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
@ -352,7 +353,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID())
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
@ -395,7 +396,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID())
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
voteStr := fmt.Sprintf("gaiacli tx vote %v", flags)
@ -417,12 +418,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
tests.WaitForNextNBlocksTM(2, port)
vote := executeGetVote(t, fmt.Sprintf("gaiacli query vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
require.Equal(t, int64(1), vote.ProposalID)
require.Equal(t, uint64(1), vote.ProposalID)
require.Equal(t, gov.OptionYes, vote.Option)
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query votes --proposal-id=1 --output=json %v", flags))
require.Len(t, votes, 1)
require.Equal(t, int64(1), votes[0].ProposalID)
require.Equal(t, uint64(1), votes[0].ProposalID)
require.Equal(t, gov.OptionYes, votes[0].Option)
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
@ -442,7 +443,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, spStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "")
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --limit=1 %v", flags), "")
require.Equal(t, " 2 - Apples", proposalsQuery)
}

View File

@ -2,7 +2,6 @@ package init
import (
"encoding/json"
"io/ioutil"
"path/filepath"
"github.com/cosmos/cosmos-sdk/client"
@ -12,7 +11,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/go-amino"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/cli"
@ -35,12 +33,13 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
name := viper.GetString(client.FlagName)
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
if err != nil {
return err
}
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
if err != nil {
return err
@ -59,12 +58,14 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
NodeID: nodeID,
ValPubKey: valPubKey,
}
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
if err != nil {
return err
}
toPrint.AppMessage = appMessage
// print out some key information
return displayInfo(cdc, toPrint)
},
@ -74,23 +75,29 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
return cmd
}
func genAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig,
genDoc types.GenesisDoc) (appState json.RawMessage, err error) {
func genAppStateFromConfig(
cdc *codec.Codec, config *cfg.Config, initCfg initConfig, genDoc types.GenesisDoc,
) (appState json.RawMessage, err error) {
genFile := config.GenesisFile()
// process genesis transactions, else create default genesis.json
var appGenTxs []auth.StdTx
var persistentPeers string
var genTxs []json.RawMessage
var jsonRawTx json.RawMessage
var (
appGenTxs []auth.StdTx
persistentPeers string
genTxs []json.RawMessage
jsonRawTx json.RawMessage
)
// process genesis transactions, else create default genesis.json
appGenTxs, persistentPeers, err = app.CollectStdTxs(
cdc, config.Moniker, initCfg.GenTxsDir, genDoc)
cdc, config.Moniker, initCfg.GenTxsDir, genDoc,
)
if err != nil {
return
}
genTxs = make([]json.RawMessage, len(appGenTxs))
config.P2P.PersistentPeers = persistentPeers
for i, stdTx := range appGenTxs {
jsonRawTx, err = cdc.MarshalJSON(stdTx)
if err != nil {
@ -100,20 +107,12 @@ func genAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, initCfg initCon
}
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
appState, err = app.GaiaAppGenStateJSON(cdc, genDoc, genTxs)
if err != nil {
return
}
err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState)
return
}
func loadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
genContents, err := ioutil.ReadFile(genFile)
if err != nil {
return
}
err = cdc.UnmarshalJSON(genContents, &genDoc)
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
return
}

View File

@ -3,7 +3,6 @@ package init
import (
"encoding/json"
"fmt"
"github.com/tendermint/tendermint/privval"
"os"
"path/filepath"
@ -14,11 +13,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
const (
@ -74,7 +70,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
viper.GetBool(flagOverwrite)); err != nil {
return err
}
if err = WriteGenesisFile(genFile, chainID, nil, appState); err != nil {
if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil {
return err
}
@ -97,54 +93,3 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
cmd.Flags().String(flagMoniker, "", "set the validator's moniker")
return cmd
}
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error) {
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return
}
nodeID = string(nodeKey.ID())
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
return
}
// WriteGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
// nolint: unparam
func WriteGenesisFile(genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error {
genDoc := types.GenesisDoc{
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
return genDoc.SaveAs(genesisFile)
}
// read of create the private key file for this config
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
// private validator
var privValidator *privval.FilePV
if common.FileExists(privValFile) {
privValidator = privval.LoadFilePV(privValFile)
} else {
privValidator = privval.GenFilePV(privValFile)
privValidator.Save()
}
return privValidator.GetPubKey()
}
func initializeEmptyGenesis(cdc *codec.Codec, genFile string, chainID string,
overwrite bool) (appState json.RawMessage, err error) {
if !overwrite && common.FileExists(genFile) {
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
return
}
return codec.MarshalJSONIndent(cdc, app.NewDefaultGenesisState())
}

View File

@ -3,6 +3,10 @@ package init
import (
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
@ -10,10 +14,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/tendermint/tendermint/types"
"net"
"os"
"path/filepath"
"github.com/cosmos/cosmos-sdk/server"
"github.com/spf13/cobra"
@ -21,16 +21,17 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
var (
nodeDirPrefix = "node-dir-prefix"
nValidators = "v"
outputDir = "output-dir"
nodeDaemonHome = "node-daemon-home"
nodeCliHome = "node-cli-home"
startingIPAddress = "starting-ip-address"
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagNodeCliHome = "node-cli-home"
flagStartingIPAddress = "starting-ip-address"
)
const nodeDirPerm = 0755
@ -48,50 +49,59 @@ necessary files (private validator, genesis, config, etc.).
Note, strict routability for addresses is turned off in the config file.
Example:
gaiad testnet --v 4 --o ./output --starting-ip-address 192.168.10.2
gaiad testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2
`,
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
return testnetWithConfig(config, cdc)
return initTestnet(config, cdc)
},
}
cmd.Flags().Int(nValidators, 4,
"Number of validators to initialize the testnet with")
cmd.Flags().StringP(outputDir, "o", "./mytestnet",
"Directory to store initialization data for the testnet")
cmd.Flags().String(nodeDirPrefix, "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)")
cmd.Flags().String(nodeDaemonHome, "gaiad",
"Home directory of the node's daemon configuration")
cmd.Flags().String(nodeCliHome, "gaiacli",
"Home directory of the node's cli configuration")
cmd.Flags().String(startingIPAddress, "192.168.0.1",
cmd.Flags().Int(flagNumValidators, 4,
"Number of validators to initialize the testnet with",
)
cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet",
"Directory to store initialization data for the testnet",
)
cmd.Flags().String(flagNodeDirPrefix, "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)",
)
cmd.Flags().String(flagNodeDaemonHome, "gaiad",
"Home directory of the node's daemon configuration",
)
cmd.Flags().String(flagNodeCliHome, "gaiacli",
"Home directory of the node's cli configuration",
)
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
return cmd
}
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
outDir := viper.GetString(outputDir)
numValidators := viper.GetInt(nValidators)
func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
outDir := viper.GetString(flagOutputDir)
numValidators := viper.GetInt(flagNumValidators)
// Generate genesis.json and config.toml
chainID := "chain-" + cmn.RandStr(6)
monikers := make([]string, numValidators)
nodeIDs := make([]string, numValidators)
valPubKeys := make([]crypto.PubKey, numValidators)
// Generate private key, node ID, initial transaction
var accs []app.GenesisAccount
var genFiles []string
var (
accs []app.GenesisAccount
genFiles []string
)
// generate private keys, node IDs, and initial transactions
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
nodeCliHomeName := viper.GetString(nodeCliHome)
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(flagNodeDirPrefix), i)
nodeDaemonHomeName := viper.GetString(flagNodeDaemonHome)
nodeCliHomeName := viper.GetString(flagNodeCliHome)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
clientDir := filepath.Join(outDir, nodeDirName, nodeCliHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
@ -108,24 +118,27 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
monikers = append(monikers, nodeDirName)
config.Moniker = nodeDirName
ip, err := getIP(i)
ip, err := getIP(i, viper.GetString(flagStartingIPAddress))
if err != nil {
_ = os.RemoveAll(outDir)
return err
}
nodeIDs[i], valPubKeys[i], err = InitializeNodeValidatorFiles(config)
if err != nil {
_ = os.RemoveAll(outDir)
return err
}
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
// write genesis
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
genFiles = append(genFiles, config.GenesisFile())
buf := client.BufferStdin()
prompt := fmt.Sprintf(
"Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass)
"Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass,
)
keyPass, err := client.GetPassword(prompt, buf)
if err != nil && keyPass != "" {
// An error was returned that either failed to read the password from
@ -133,6 +146,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
// length requirements.
return err
}
if keyPass == "" {
keyPass = app.DefaultKeyPass
}
@ -142,11 +156,14 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
_ = os.RemoveAll(outDir)
return err
}
info := map[string]string{"secret": secret}
cliPrint, err := json.Marshal(info)
if err != nil {
return err
}
// save private key seed words
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint)
if err != nil {
@ -170,6 +187,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
)
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo)
signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false)
if err != nil {
_ = os.RemoveAll(outDir)
@ -182,7 +200,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
return err
}
// Gather gentxs folder
// gather gentxs folder
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
if err != nil {
_ = os.RemoveAll(outDir)
@ -190,37 +208,70 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
}
}
// Generate empty genesis.json
if err := initGenFiles(cdc, chainID, accs, genFiles, numValidators); err != nil {
return err
}
err := collectGenFiles(
cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators,
outDir, viper.GetString(flagNodeDirPrefix), viper.GetString(flagNodeDaemonHome),
)
if err != nil {
return err
}
fmt.Printf("Successfully initialized %d node directories\n", numValidators)
return nil
}
func initGenFiles(
cdc *codec.Codec, chainID string, accs []app.GenesisAccount,
genFiles []string, numValidators int,
) error {
appGenState := app.NewDefaultGenesisState()
appGenState.Accounts = accs
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
if err != nil {
return err
}
genDoc := types.GenesisDoc{
ChainID: chainID,
AppState: appGenStateJSON,
Validators: nil,
}
// Save all genesis.json files
// generate empty genesis files for each validator and save
for i := 0; i < numValidators; i++ {
if err := genDoc.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func collectGenFiles(
cdc *codec.Codec, config *cfg.Config, chainID string,
monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
numValidators int, outDir, nodeDirPrefix, nodeDaemonHomeName string,
) error {
var appState json.RawMessage
genTime := tmtime.Now()
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
moniker := monikers[i]
config.Moniker = nodeDirName
config.SetRoot(nodeDir)
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
// Run `init` and generate genesis.json and config.toml
initCfg := initConfig{
ChainID: chainID,
GenTxsDir: gentxsDir,
@ -228,46 +279,69 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
NodeID: nodeID,
ValPubKey: valPubKey,
}
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
if err != nil {
return err
}
if _, err := genAppStateFromConfig(cdc, config, initCfg, genDoc); err != nil {
nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
if err != nil {
return err
}
if appState == nil {
// set the canonical application state (they should not differ)
appState = nodeAppState
}
genFile := config.GenesisFile()
// overwrite each validator's genesis file to have a canonical genesis time
err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
if err != nil {
return err
}
}
fmt.Printf("Successfully initialized %v node directories\n", viper.GetInt(nValidators))
return nil
}
func getIP(i int) (ip string, err error) {
ip = viper.GetString(startingIPAddress)
if len(ip) == 0 {
func getIP(i int, startingIPAddr string) (string, error) {
var (
ip string
err error
)
if len(startingIPAddr) == 0 {
ip, err = server.ExternalIP()
if err != nil {
return "", err
}
} else {
ip, err = calculateIP(ip, i)
ip, err = calculateIP(startingIPAddr, i)
if err != nil {
return "", err
}
}
return ip, nil
}
func writeFile(name string, dir string, contents []byte) error {
writePath := filepath.Join(dir)
file := filepath.Join(writePath, name)
err := cmn.EnsureDir(writePath, 0700)
if err != nil {
return err
}
err = cmn.WriteFile(file, contents, 0600)
if err != nil {
return err
}
return nil
}
@ -280,5 +354,6 @@ func calculateIP(ip string, i int) (string, error) {
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
}

112
cmd/gaia/init/utils.go Normal file
View File

@ -0,0 +1,112 @@
package init
import (
"encoding/json"
"fmt"
"io/ioutil"
"time"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
amino "github.com/tendermint/go-amino"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
)
// ExportGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
func ExportGenesisFile(
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
) error {
genDoc := types.GenesisDoc{
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
return genDoc.SaveAs(genFile)
}
// ExportGenesisFileWithTime creates and writes the genesis configuration to disk.
// An error is returned if building or writing the configuration to file fails.
func ExportGenesisFileWithTime(
genFile, chainID string, validators []types.GenesisValidator,
appState json.RawMessage, genTime time.Time,
) error {
genDoc := types.GenesisDoc{
GenesisTime: genTime,
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
return genDoc.SaveAs(genFile)
}
// read of create the private key file for this config
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
var privValidator *privval.FilePV
if common.FileExists(privValFile) {
privValidator = privval.LoadFilePV(privValFile)
} else {
privValidator = privval.GenFilePV(privValFile)
privValidator.Save()
}
return privValidator.GetPubKey()
}
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
func InitializeNodeValidatorFiles(
config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error,
) {
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return nodeID, valPubKey, err
}
nodeID = string(nodeKey.ID())
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
return nodeID, valPubKey, nil
}
func loadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
genContents, err := ioutil.ReadFile(genFile)
if err != nil {
return genDoc, err
}
if err := cdc.UnmarshalJSON(genContents, &genDoc); err != nil {
return genDoc, err
}
return genDoc, err
}
func initializeEmptyGenesis(
cdc *codec.Codec, genFile, chainID string, overwrite bool,
) (appState json.RawMessage, err error) {
if !overwrite && common.FileExists(genFile) {
return nil, fmt.Errorf("genesis.json file already exists: %v", genFile)
}
return codec.MarshalJSONIndent(cdc, app.NewDefaultGenesisState())
}

View File

@ -96,10 +96,12 @@ type Proposal struct {
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
Deposits []Deposit // List of deposits on the proposal
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
Submitter sdk.Address // Address of the submitter
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
DepositEndTime time.Time // Time that the DepositPeriod of a proposal would expire
Submitter sdk.AccAddress // Address of the submitter
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
VotingEndTime time.Time // Time of the block that the VotingPeriod for a proposal will end.
CurrentStatus ProposalStatus // Current status of the proposal
YesVotes sdk.Dec
@ -134,46 +136,26 @@ For pseudocode purposes, here are the two function we will use to read or write
**Store:**
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if
`CurrentTime == VotingStartTime + activeProcedure.VotingPeriod`. If it is,
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded.
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
`ProposalIDs` of proposals that reached `MinDeposit`. Each `EndBlock`, all the proposals
that have reached the end of their voting period are processed.
To process a finished proposal, the application tallies the votes, compute the votes of
each validator and checks if every validator in the valdiator set have voted.
If the proposal is accepted, deposits are refunded.
And the pseudocode for the `ProposalProcessingQueue`:
```go
in EndBlock do
checkProposal() // First call of the recursive function
// Recursive function. First call in BeginBlock
func checkProposal()
proposalID = ProposalProcessingQueue.Peek()
if (proposalID == nil)
return
for finishedProposalID in GetAllFinishedProposalIDs(block.Time)
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
votingProcedure = load(GlobalParams, 'VotingProcedure')
validators = Keeper.getAllValidators()
tmpValMap := map(sdk.AccAddress)ValidatorGovInfo
if (CurrentTime == proposal.VotingStartTime + votingProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive)
// End of voting period, tally
ProposalProcessingQueue.pop()
validators =
Keeper.getAllValidators()
tmpValMap := map(sdk.Address)ValidatorGovInfo
// Initiate mapping at 0. Validators that remain at 0 at the end of tally will be punished
// Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes
for each validator in validators
tmpValMap(validator).Minus = 0
tmpValMap(validator.OperatorAddr).Minus = 0
// Tally
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
@ -212,5 +194,4 @@ And the pseudocode for the `ProposalProcessingQueue`:
proposal.CurrentStatus = ProposalStatusRejected
store(Governance, <proposalID|'proposal'>, proposal)
checkProposal()
```

View File

@ -45,6 +45,8 @@ upon receiving txGovSubmitProposal from sender do
if (txGovSubmitProposal.Type != ProposalTypePlainText) OR (txGovSubmitProposal.Type != ProposalTypeSoftwareUpgrade)
sender.AtomBalance -= initialDeposit.Atoms
depositProcedure = load(GlobalParams, 'DepositProcedure')
proposalID = generate new proposalID
proposal = NewProposal()
@ -53,27 +55,15 @@ upon receiving txGovSubmitProposal from sender do
proposal.Description = txGovSubmitProposal.Description
proposal.Type = txGovSubmitProposal.Type
proposal.TotalDeposit = initialDeposit
proposal.SubmitBlock = CurrentBlock
proposal.SubmitTime = <CurrentTime>
proposal.DepositEndTime = <CurrentTime>.Add(depositProcedure.MaxDepositPeriod)
proposal.Deposits.append({initialDeposit, sender})
proposal.Submitter = sender
proposal.YesVotes = 0
proposal.NoVotes = 0
proposal.NoWithVetoVotes = 0
proposal.AbstainVotes = 0
depositProcedure = load(GlobalParams, 'DepositProcedure')
if (initialDeposit < depositProcedure.MinDeposit)
// MinDeposit is not reached
proposal.CurrentStatus = ProposalStatusOpen
else
// MinDeposit is reached
proposal.CurrentStatus = ProposalStatusActive
proposal.VotingStartBlock = CurrentBlock
ProposalProcessingQueue.push(proposalID)
proposal.CurrentStatus = ProposalStatusOpen
store(Proposals, <proposalID|'proposal'>, proposal) // Store proposal in Proposals mapping
return proposalID

View File

@ -7,7 +7,7 @@ The staking module allow for the following hooks to be registered with staking e
type StakingHooks interface {
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
OnValidatorRemoved(ctx Context, address ConsAddress, operator ValAddress) // Must be called when a validator is deleted
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding

View File

@ -108,7 +108,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
return err
}
fmt.Fprintf(os.Stderr, "%s\n", string(out))
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
[]tmtypes.GenesisValidator{validator}, appStateJSON)
},
}

View File

@ -186,8 +186,8 @@ func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage,
genState := types.GenesisState{
Accounts: accounts,
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
POWGenesis: pow.ExportGenesis(ctx, app.powKeeper),
CoolGenesis: cool.ExportGenesis(ctx, app.coolKeeper),
}
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {

View File

@ -115,7 +115,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
return err
}
fmt.Fprintf(os.Stderr, "%s\n", string(out))
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
[]tmtypes.GenesisValidator{validator}, appStateJSON)
},
}

View File

@ -49,8 +49,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error {
return nil
}
// WriteGenesis - output the genesis trend
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
// ExportGenesis - output the genesis trend
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
trend := k.GetTrend(ctx)
return Genesis{trend}
}

View File

@ -37,7 +37,7 @@ func TestCoolKeeper(t *testing.T) {
err := InitGenesis(ctx, keeper, Genesis{"icy"})
require.Nil(t, err)
genesis := WriteGenesis(ctx, keeper)
genesis := ExportGenesis(ctx, keeper)
require.Nil(t, err)
require.Equal(t, genesis, Genesis{"icy"})

View File

@ -43,8 +43,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, genesis Genesis) error {
return nil
}
// WriteGenesis for the PoW module
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
// ExportGenesis for the PoW module
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
difficulty, err := k.GetLastDifficulty(ctx)
if err != nil {
panic(err)

View File

@ -41,7 +41,7 @@ func TestPowKeeperGetSet(t *testing.T) {
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})
require.Nil(t, err)
genesis := WriteGenesis(ctx, keeper)
genesis := ExportGenesis(ctx, keeper)
require.Nil(t, err)
require.Equal(t, genesis, Genesis{uint64(1), uint64(0)})

View File

@ -61,6 +61,7 @@ func (ci *cacheKVStore) Set(key []byte, value []byte) {
ci.mtx.Lock()
defer ci.mtx.Unlock()
ci.assertValidKey(key)
ci.assertValidValue(value)
ci.setCacheValue(key, value, false, true)
}
@ -196,6 +197,12 @@ func (ci *cacheKVStore) assertValidKey(key []byte) {
}
}
func (ci *cacheKVStore) assertValidValue(value []byte) {
if value == nil {
panic("value is nil")
}
}
// Only entrypoint to mutate ci.cache.
func (ci *cacheKVStore) setCacheValue(key, value []byte, deleted bool, dirty bool) {
ci.cache[string(key)] = cValue{

View File

@ -225,8 +225,21 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
res.Log = err.Error()
break
}
res.Value = value
res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(key, proof).ProofOp()}}
if proof == nil {
// Proof == nil implies that the store is empty.
if value != nil {
panic("unexpected value for an empty proof")
}
}
if value != nil {
// value was found
res.Value = value
res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(key, proof).ProofOp()}}
} else {
// value wasn't found
res.Value = nil
res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(key, proof).ProofOp()}}
}
} else {
_, res.Value = tree.GetVersioned(key, res.Height)
}

View File

@ -106,3 +106,69 @@ func TestVerifyMultiStoreQueryProof(t *testing.T) {
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte(nil))
require.NotNil(t, err)
}
func TestVerifyMultiStoreQueryProofEmptyStore(t *testing.T) {
// Create main tree for testing.
db := dbm.NewMemDB()
store := NewCommitMultiStore(db)
iavlStoreKey := sdk.NewKVStoreKey("iavlStoreKey")
store.MountStoreWithDB(iavlStoreKey, sdk.StoreTypeIAVL, nil)
store.LoadVersion(0)
cid := store.Commit() // Commit with empty iavl store.
// Get Proof
res := store.Query(abci.RequestQuery{
Path: "/iavlStoreKey/key", // required path to get key/value+proof
Data: []byte("MYKEY"),
Prove: true,
})
require.NotNil(t, res.Proof)
// Verify proof.
prt := DefaultProofRuntime()
err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY")
require.Nil(t, err)
// Verify (bad) proof.
prt = DefaultProofRuntime()
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
require.NotNil(t, err)
}
func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) {
// Create main tree for testing.
db := dbm.NewMemDB()
store := NewCommitMultiStore(db)
iavlStoreKey := sdk.NewKVStoreKey("iavlStoreKey")
store.MountStoreWithDB(iavlStoreKey, sdk.StoreTypeIAVL, nil)
store.LoadVersion(0)
iavlStore := store.GetCommitStore(iavlStoreKey).(*iavlStore)
iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE"))
cid := store.Commit() // Commit with empty iavl store.
// Get Proof
res := store.Query(abci.RequestQuery{
Path: "/iavlStoreKey/key", // required path to get key/value+proof
Data: []byte("MYABSENTKEY"),
Prove: true,
})
require.NotNil(t, res.Proof)
// Verify proof.
prt := DefaultProofRuntime()
err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY")
require.Nil(t, err)
// Verify (bad) proof.
prt = DefaultProofRuntime()
err = prt.VerifyAbsence(res.Proof, cid.Hash, "/MYABSENTKEY")
require.NotNil(t, err)
// Verify (bad) proof.
prt = DefaultProofRuntime()
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY", []byte(""))
require.NotNil(t, err)
}

View File

@ -295,6 +295,10 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery {
return res
}
if res.Proof == nil || len(res.Proof.Ops) == 0 {
return sdk.ErrInternal("substore proof was nil/empty when it should never be").QueryResult()
}
commitInfo, errMsg := getCommitInfo(rs.db, res.Height)
if errMsg != nil {
return sdk.ErrInternal(errMsg.Error()).QueryResult()

View File

@ -49,7 +49,7 @@ func (coin Coin) IsGTE(other Coin) bool {
// IsLT returns true if they are the same type and the receiver is
// a smaller value
func (coin Coin) IsLT(other Coin) bool {
return !coin.IsGTE(other)
return coin.SameDenomAs(other) && coin.Amount.LT(other.Amount)
}
// IsEqual returns true if the two sets of Coins have the same value
@ -142,7 +142,11 @@ func (coins Coins) Plus(coinsB Coins) Coins {
coinA, coinB := coins[indexA], coinsB[indexB]
switch strings.Compare(coinA.Denom, coinB.Denom) {
case -1:
sum = append(sum, coinA)
if coinA.IsZero() {
// ignore 0 sum coin type
} else {
sum = append(sum, coinA)
}
indexA++
case 0:
if coinA.Amount.Add(coinB.Amount).IsZero() {
@ -153,7 +157,11 @@ func (coins Coins) Plus(coinsB Coins) Coins {
indexA++
indexB++
case 1:
sum = append(sum, coinB)
if coinB.IsZero() {
// ignore 0 sum coin type
} else {
sum = append(sum, coinB)
}
indexB++
}
}
@ -176,10 +184,19 @@ func (coins Coins) Minus(coinsB Coins) Coins {
return coins.Plus(coinsB.Negative())
}
// IsGTE returns True iff coins is NonNegative(), and for every
// currency in coinsB, the currency is present at an equal or greater
// amount in coinsB
func (coins Coins) IsGTE(coinsB Coins) bool {
// IsAllGT returns True iff for every denom in coins, the denom is present at a
// greater amount in coinsB.
func (coins Coins) IsAllGT(coinsB Coins) bool {
diff := coins.Minus(coinsB)
if len(diff) == 0 {
return false
}
return diff.IsPositive()
}
// IsAllGTE returns True iff for every denom in coins, the denom is present at an
// equal or greater amount in coinsB.
func (coins Coins) IsAllGTE(coinsB Coins) bool {
diff := coins.Minus(coinsB)
if len(diff) == 0 {
return true
@ -187,14 +204,27 @@ func (coins Coins) IsGTE(coinsB Coins) bool {
return diff.IsNotNegative()
}
// IsLT returns True iff every currency in coins, the currency is
// present at a smaller amount in coins
func (coins Coins) IsLT(coinsB Coins) bool {
return !coins.IsGTE(coinsB)
// IsAllLT returns True iff for every denom in coins, the denom is present at
// a smaller amount in coinsB.
func (coins Coins) IsAllLT(coinsB Coins) bool {
diff := coinsB.Minus(coins)
if len(diff) == 0 {
return false
}
return diff.IsPositive()
}
// IsZero returns true if there are no coins
// or all coins are zero.
// IsAllLTE returns True iff for every denom in coins, the denom is present at
// a smaller or equal amount in coinsB.
func (coins Coins) IsAllLTE(coinsB Coins) bool {
diff := coinsB.Minus(coins)
if len(diff) == 0 {
return true
}
return diff.IsNotNegative()
}
// IsZero returns true if there are no coins or all coins are zero.
func (coins Coins) IsZero() bool {
for _, coin := range coins {
if !coin.IsZero() {

View File

@ -86,7 +86,10 @@ func TestIsLTCoin(t *testing.T) {
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), true},
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), true},
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 2), true},
}
for tcIndex, tc := range cases {
@ -245,9 +248,9 @@ func TestCoins(t *testing.T) {
assert.True(t, good.IsValid(), "Coins are valid")
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good)
assert.False(t, null.IsPositive(), "Expected coins to not be positive: %v", null)
assert.True(t, good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
assert.False(t, good.IsLT(empty), "Expected %v to be < %v", good, empty)
assert.True(t, empty.IsLT(good), "Expected %v to be < %v", empty, good)
assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty)
assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
assert.Zero(t, len(sum), "Expected 0 coins")
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
@ -257,6 +260,60 @@ func TestCoins(t *testing.T) {
}
func TestCoinsGT(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAllGT(Coins{}))
assert.True(t, Coins{{"A", one}}.IsAllGT(Coins{}))
assert.False(t, Coins{{"A", one}}.IsAllGT(Coins{{"A", one}}))
assert.False(t, Coins{{"A", one}}.IsAllGT(Coins{{"B", one}}))
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllGT(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllGT(Coins{{"B", two}}))
}
func TestCoinsGTE(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.True(t, Coins{}.IsAllGTE(Coins{}))
assert.True(t, Coins{{"A", one}}.IsAllGTE(Coins{}))
assert.True(t, Coins{{"A", one}}.IsAllGTE(Coins{{"A", one}}))
assert.False(t, Coins{{"A", one}}.IsAllGTE(Coins{{"B", one}}))
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllGTE(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllGTE(Coins{{"B", two}}))
}
func TestCoinsLT(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAllLT(Coins{}))
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{}))
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{{"A", one}}))
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"B", two}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"A", one}, {"B", one}}))
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"A", one}, {"B", two}}))
assert.True(t, Coins{}.IsAllLT(Coins{{"A", one}}))
}
func TestCoinsLTE(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.True(t, Coins{}.IsAllLTE(Coins{}))
assert.False(t, Coins{{"A", one}}.IsAllLTE(Coins{}))
assert.True(t, Coins{{"A", one}}.IsAllLTE(Coins{{"A", one}}))
assert.False(t, Coins{{"A", one}}.IsAllLTE(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"B", one}}))
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"B", two}}))
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"A", one}, {"B", one}}))
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"A", one}, {"B", two}}))
assert.True(t, Coins{}.IsAllLTE(Coins{{"A", one}}))
}
func TestPlusCoins(t *testing.T) {
one := NewInt(1)
zero := NewInt(0)

View File

@ -115,9 +115,9 @@ type DelegationSet interface {
// event hooks for staking validator object
type StakingHooks interface {
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
OnValidatorRemoved(ctx Context, valAddr ValAddress) // Must be called when a validator is deleted
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
OnValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted
OnValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
OnValidatorBeginUnbonding(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator begins unbonding

View File

@ -1,6 +1,7 @@
package types
import (
"bytes"
"fmt"
"io"
@ -127,7 +128,7 @@ type KVStore interface {
// Has checks if a key exists. Panics on nil key.
Has(key []byte) bool
// Set sets the key. Panics on nil key.
// Set sets the key. Panics on nil key or value.
Set(key, value []byte)
// Delete deletes the key. Panics on nil key.
@ -176,6 +177,43 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator {
return kvs.ReverseIterator(prefix, PrefixEndBytes(prefix))
}
// Compare two KVstores, return either the first key/value pair
// at which they differ and whether or not they are equal, skipping
// value comparison for a set of provided prefixes
func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvA cmn.KVPair, kvB cmn.KVPair, count int64, equal bool) {
iterA := a.Iterator(nil, nil)
iterB := b.Iterator(nil, nil)
count = int64(0)
for {
if !iterA.Valid() && !iterB.Valid() {
break
}
var kvA, kvB cmn.KVPair
if iterA.Valid() {
kvA = cmn.KVPair{Key: iterA.Key(), Value: iterA.Value()}
iterA.Next()
}
if iterB.Valid() {
kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()}
iterB.Next()
}
compareValue := true
for _, prefix := range prefixesToSkip {
if bytes.Equal(kvA.Key[:len(prefix)], prefix) {
compareValue = false
}
}
if !bytes.Equal(kvA.Key, kvB.Key) {
return kvA, kvB, count, false
}
if compareValue && !bytes.Equal(kvA.Value, kvB.Value) {
return kvA, kvB, count, false
}
count++
}
return cmn.KVPair{}, cmn.KVPair{}, count, true
}
// CacheKVStore cache-wraps a KVStore. After calling .Write() on
// the CacheKVStore, all previously created CacheKVStores on the
// object expire.

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/binary"
"encoding/json"
"time"
@ -36,6 +37,13 @@ func MustSortJSON(toSortJSON []byte) []byte {
return js
}
// Uint64ToBigEndian - marshals uint64 to a bigendian byte slice so it can be sorted
func Uint64ToBigEndian(i uint64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, i)
return b
}
// Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info
const SortableTimeFormat = "2006-01-02T15:04:05.000000000"

View File

@ -282,7 +282,8 @@ func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
// TODO: Make the gasPrice not a constant, and account for tx size.
requiredFees := adjustFeesByGas(ctx.MinimumFees(), stdTx.Fee.Gas)
if !ctx.MinimumFees().IsZero() && stdTx.Fee.Amount.IsLT(requiredFees) {
// NOTE: !A.IsAllGTE(B) is not the same as A.IsAllLT(B).
if !ctx.MinimumFees().IsZero() && !stdTx.Fee.Amount.IsAllGTE(requiredFees) {
// validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
return sdk.ErrInsufficientFee(fmt.Sprintf(
"insufficient fee, got: %q required: %q", stdTx.Fee.Amount, requiredFees)).Result()

33
x/auth/genesis.go Normal file
View File

@ -0,0 +1,33 @@
package auth
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GenesisState - all auth state that must be provided at genesis
type GenesisState struct {
CollectedFees sdk.Coins `json:"collected_fees"` // collected fees
}
// Create a new genesis state
func NewGenesisState(collectedFees sdk.Coins) GenesisState {
return GenesisState{
CollectedFees: collectedFees,
}
}
// Return a default genesis state
func DefaultGenesisState() GenesisState {
return NewGenesisState(sdk.Coins{})
}
// Init store state from genesis data
func InitGenesis(ctx sdk.Context, keeper FeeCollectionKeeper, data GenesisState) {
keeper.setCollectedFees(ctx, data.CollectedFees)
}
// ExportGenesis returns a GenesisState for a given context and keeper
func ExportGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState {
collectedFees := keeper.GetCollectedFees(ctx)
return NewGenesisState(collectedFees)
}

View File

@ -59,7 +59,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command {
}
// ensure account has enough coins
if !account.GetCoins().IsGTE(coins) {
if !account.GetCoins().IsAllGTE(coins) {
return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from)
}

View File

@ -190,7 +190,7 @@ func setCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt s
// HasCoins returns whether or not an account has at least amt coins.
func hasCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) bool {
ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins")
return getCoins(ctx, am, addr).IsGTE(amt)
return getCoins(ctx, am, addr).IsAllGTE(amt)
}
// SubtractCoins subtracts amt from the coins at the addr.

View File

@ -21,11 +21,12 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
for _, dw := range data.DelegatorWithdrawInfos {
keeper.SetDelegatorWithdrawAddr(ctx, dw.DelegatorAddr, dw.WithdrawAddr)
}
keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer)
}
// WriteGenesis returns a GenesisState for a given context and keeper. The
// ExportGenesis returns a GenesisState for a given context and keeper. The
// GenesisState will contain the pool, and validator/delegator distribution info's
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
feePool := keeper.GetFeePool(ctx)
communityTax := keeper.GetCommunityTax(ctx)
baseProposerRewards := keeper.GetBaseProposerReward(ctx)
@ -33,6 +34,7 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
vdis := keeper.GetAllValidatorDistInfos(ctx)
ddis := keeper.GetAllDelegationDistInfos(ctx)
dwis := keeper.GetAllDelegatorWithdrawInfos(ctx)
pp := keeper.GetPreviousProposerConsAddr(ctx)
return NewGenesisState(feePool, communityTax, baseProposerRewards,
bonusProposerRewards, vdis, ddis, dwis)
bonusProposerRewards, vdis, ddis, dwis, pp)
}

View File

@ -36,12 +36,12 @@ func (k Keeper) GetAllDelegationDistInfos(ctx sdk.Context) (ddis []types.Delegat
// Get the set of all delegator-withdraw addresses with no limits, used during genesis dump
func (k Keeper) GetAllDelegatorWithdrawInfos(ctx sdk.Context) (dwis []types.DelegatorWithdrawInfo) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, DelegationDistInfoKey)
iterator := sdk.KVStorePrefixIterator(store, DelegatorWithdrawInfoKey)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
dw := types.DelegatorWithdrawInfo{
DelegatorAddr: sdk.AccAddress(iterator.Key()),
DelegatorAddr: GetDelegatorWithdrawInfoAddress(iterator.Key()),
WithdrawAddr: sdk.AccAddress(iterator.Value()),
}
dwis = append(dwis, dw)

View File

@ -103,7 +103,7 @@ func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
h.k.onValidatorModified(ctx, valAddr)
}
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
h.k.onValidatorRemoved(ctx, valAddr)
}
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {

View File

@ -44,3 +44,12 @@ func GetDelegationDistInfosKey(delAddr sdk.AccAddress) []byte {
func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte {
return append(DelegatorWithdrawInfoKey, delAddr.Bytes()...)
}
// gets an address from a delegator's withdraw info key
func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
panic("unexpected key length")
}
return sdk.AccAddress(addr)
}

View File

@ -18,10 +18,11 @@ type GenesisState struct {
ValidatorDistInfos []ValidatorDistInfo `json:"validator_dist_infos"`
DelegationDistInfos []DelegationDistInfo `json:"delegator_dist_infos"`
DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos"`
PreviousProposer sdk.ConsAddress `json:"previous_proposer"`
}
func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusProposerReward sdk.Dec,
vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo) GenesisState {
vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress) GenesisState {
return GenesisState{
FeePool: feePool,
@ -31,6 +32,7 @@ func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusPro
ValidatorDistInfos: vdis,
DelegationDistInfos: ddis,
DelegatorWithdrawInfos: dwis,
PreviousProposer: pp,
}
}

View File

@ -21,17 +21,17 @@ import (
)
const (
flagProposalID = "proposal-id"
flagTitle = "title"
flagDescription = "description"
flagProposalType = "type"
flagDeposit = "deposit"
flagVoter = "voter"
flagOption = "option"
flagDepositer = "depositer"
flagStatus = "status"
flagLatestProposalIDs = "latest"
flagProposal = "proposal"
flagProposalID = "proposal-id"
flagTitle = "title"
flagDescription = "description"
flagProposalType = "type"
flagDeposit = "deposit"
flagVoter = "voter"
flagOption = "option"
flagDepositer = "depositer"
flagStatus = "status"
flagNumLimit = "limit"
flagProposal = "proposal"
)
type proposal struct {
@ -170,7 +170,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
return err
}
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
amount, err := sdk.ParseCoins(viper.GetString(flagDeposit))
if err != nil {
@ -215,7 +215,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
return err
}
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
option := viper.GetString(flagOption)
byteVoteOption, err := gov.VoteOptionFromString(client.NormalizeVoteOption(option))
@ -256,7 +256,7 @@ func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a single proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryProposalParams{
ProposalID: proposalID,
@ -291,10 +291,10 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
bechDepositerAddr := viper.GetString(flagDepositer)
bechVoterAddr := viper.GetString(flagVoter)
strProposalStatus := viper.GetString(flagStatus)
latestProposalsIDs := viper.GetInt64(flagLatestProposalIDs)
numLimit := uint64(viper.GetInt64(flagNumLimit))
params := gov.QueryProposalsParams{
NumLatestProposals: latestProposalsIDs,
Limit: numLimit,
}
if len(bechDepositerAddr) != 0 {
@ -352,7 +352,7 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
},
}
cmd.Flags().String(flagLatestProposalIDs, "", "(optional) limit to latest [number] proposals. Defaults to all proposals")
cmd.Flags().String(flagNumLimit, "", "(optional) limit to latest [number] proposals. Defaults to all proposals")
cmd.Flags().String(flagDepositer, "", "(optional) filter by proposals deposited on by depositer")
cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted")
cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected")
@ -368,7 +368,7 @@ func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a single vote",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter))
if err != nil {
@ -407,7 +407,7 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query votes on a proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryVotesParams{
ProposalID: proposalID,
@ -440,7 +440,7 @@ func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a deposit",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
depositerAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagDepositer))
if err != nil {
@ -479,7 +479,7 @@ func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query deposits on a proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryDepositsParams{
ProposalID: proposalID,
@ -511,7 +511,7 @@ func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Get the tally of a proposal vote",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryTallyParams{
ProposalID: proposalID,

View File

@ -22,7 +22,7 @@ const (
RestDepositer = "depositer"
RestVoter = "voter"
RestProposalStatus = "status"
RestNumLatest = "latest"
RestNumLimit = "limit"
storeName = "gov"
)
@ -104,7 +104,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -143,7 +143,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -188,7 +188,7 @@ func queryProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -218,7 +218,7 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
vars := mux.Vars(r)
strProposalID := vars[RestProposalID]
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -255,7 +255,7 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -319,7 +319,7 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -386,7 +386,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext)
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -416,7 +416,7 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext)
bechVoterAddr := r.URL.Query().Get(RestVoter)
bechDepositerAddr := r.URL.Query().Get(RestDepositer)
strProposalStatus := r.URL.Query().Get(RestProposalStatus)
strNumLatest := r.URL.Query().Get(RestNumLatest)
strNumLimit := r.URL.Query().Get(RestNumLimit)
params := gov.QueryProposalsParams{}
@ -446,12 +446,12 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext)
}
params.ProposalStatus = proposalStatus
}
if len(strNumLatest) != 0 {
numLatest, ok := utils.ParseInt64OrReturnBadRequest(w, strNumLatest)
if len(strNumLimit) != 0 {
numLimit, ok := utils.ParseUint64OrReturnBadRequest(w, strNumLimit)
if !ok {
return
}
params.NumLatestProposals = numLatest
params.Limit = numLimit
}
bz, err := cdc.MarshalJSON(params)
@ -484,7 +484,7 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext)
return
}
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}

View File

@ -11,7 +11,7 @@ import (
// Vote
type Vote struct {
Voter sdk.AccAddress `json:"voter"` // address of the voter
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal
ProposalID uint64 `json:"proposal_id"` // proposalID of the proposal
Option VoteOption `json:"option"` // option from OptionSet chosen by the voter
}
@ -29,7 +29,7 @@ func (voteA Vote) Empty() bool {
// Deposit
type Deposit struct {
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal
ProposalID uint64 `json:"proposal_id"` // proposalID of the proposal
Amount sdk.Coins `json:"amount"` // Deposit amount
}

View File

@ -16,35 +16,40 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod)
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod)
ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
}
func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
@ -53,49 +58,54 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res = govHandler(ctx, newProposalMsg2)
require.True(t, res.IsOK())
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second)
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
}
func TestTickPassedDepositPeriod(t *testing.T) {
@ -104,45 +114,39 @@ func TestTickPassedDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, shouldPopActiveProposalQueue(ctx, keeper))
inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
activeQueue := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
var proposalID int64
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &proposalID)
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res = govHandler(ctx, newDepositMsg)
require.True(t, res.IsOK())
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, shouldPopActiveProposalQueue(ctx, keeper))
activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
}
func TestTickPassedVotingPeriod(t *testing.T) {
@ -152,17 +156,19 @@ func TestTickPassedVotingPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, shouldPopActiveProposalQueue(ctx, keeper))
inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
activeQueue := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK())
var proposalID int64
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &proposalID)
newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
@ -172,24 +178,27 @@ func TestTickPassedVotingPeriod(t *testing.T) {
res = govHandler(ctx, newDepositMsg)
require.True(t, res.IsOK())
EndBlocker(ctx, keeper)
newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod)
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(keeper.GetVotingParams(ctx).VotingPeriod)
ctx = ctx.WithBlockHeader(newHeader)
require.True(t, shouldPopActiveProposalQueue(ctx, keeper))
inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, activeQueue.Valid())
var activeProposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeQueue.Value(), &activeProposalID)
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, activeProposalID).GetStatus())
depositsIterator := keeper.GetDeposits(ctx, proposalID)
require.True(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus())
activeQueue.Close()
EndBlocker(ctx, keeper)
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
depositsIterator = keeper.GetDeposits(ctx, proposalID)
require.False(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus())
require.True(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult()))
activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
}

View File

@ -26,19 +26,19 @@ const (
//----------------------------------------
// Error constructors
func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error {
func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeUnknownProposal, fmt.Sprintf("Unknown proposal with id %d", proposalID))
}
func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error {
func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeInactiveProposal, fmt.Sprintf("Inactive proposal with id %d", proposalID))
}
func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error {
func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeAlreadyActiveProposal, fmt.Sprintf("Proposal %d has been already active", proposalID))
}
func ErrAlreadyFinishedProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error {
func ErrAlreadyFinishedProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeAlreadyFinishedProposal, fmt.Sprintf("Proposal %d has already passed its voting period", proposalID))
}

View File

@ -8,18 +8,33 @@ import (
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
StartingProposalID int64 `json:"starting_proposalID"`
DepositProcedure DepositProcedure `json:"deposit_period"`
VotingProcedure VotingProcedure `json:"voting_period"`
TallyingProcedure TallyingProcedure `json:"tallying_procedure"`
StartingProposalID uint64 `json:"starting_proposal_id"`
Deposits []DepositWithMetadata `json:"deposits"`
Votes []VoteWithMetadata `json:"votes"`
Proposals []Proposal `json:"proposals"`
DepositParams DepositParams `json:"deposit_params"`
VotingParams VotingParams `json:"voting_params"`
TallyParams TallyParams `json:"tally_params"`
}
func NewGenesisState(startingProposalID int64, dp DepositProcedure, vp VotingProcedure, tp TallyingProcedure) GenesisState {
// DepositWithMetadata (just for genesis)
type DepositWithMetadata struct {
ProposalID uint64 `json:"proposal_id"`
Deposit Deposit `json:"deposit"`
}
// VoteWithMetadata (just for genesis)
type VoteWithMetadata struct {
ProposalID uint64 `json:"proposal_id"`
Vote Vote `json:"vote"`
}
func NewGenesisState(startingProposalID uint64, dp DepositParams, vp VotingParams, tp TallyParams) GenesisState {
return GenesisState{
StartingProposalID: startingProposalID,
DepositProcedure: dp,
VotingProcedure: vp,
TallyingProcedure: tp,
DepositParams: dp,
VotingParams: vp,
TallyParams: tp,
}
}
@ -27,14 +42,14 @@ func NewGenesisState(startingProposalID int64, dp DepositProcedure, vp VotingPro
func DefaultGenesisState() GenesisState {
return GenesisState{
StartingProposalID: 1,
DepositProcedure: DepositProcedure{
DepositParams: DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)},
MaxDepositPeriod: time.Duration(172800) * time.Second,
},
VotingProcedure: VotingProcedure{
VotingParams: VotingParams{
VotingPeriod: time.Duration(172800) * time.Second,
},
TallyingProcedure: TallyingProcedure{
TallyParams: TallyParams{
Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
@ -49,22 +64,52 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
// TODO: Handle this with #870
panic(err)
}
k.setDepositProcedure(ctx, data.DepositProcedure)
k.setVotingProcedure(ctx, data.VotingProcedure)
k.setTallyingProcedure(ctx, data.TallyingProcedure)
k.setDepositParams(ctx, data.DepositParams)
k.setVotingParams(ctx, data.VotingParams)
k.setTallyParams(ctx, data.TallyParams)
for _, deposit := range data.Deposits {
k.setDeposit(ctx, deposit.ProposalID, deposit.Deposit.Depositer, deposit.Deposit)
}
for _, vote := range data.Votes {
k.setVote(ctx, vote.ProposalID, vote.Vote.Voter, vote.Vote)
}
for _, proposal := range data.Proposals {
k.SetProposal(ctx, proposal)
}
}
// WriteGenesis - output genesis parameters
func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
startingProposalID, _ := k.getNewProposalID(ctx)
depositProcedure := k.GetDepositProcedure(ctx)
votingProcedure := k.GetVotingProcedure(ctx)
tallyingProcedure := k.GetTallyingProcedure(ctx)
// ExportGenesis - output genesis parameters
func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
startingProposalID, _ := k.peekCurrentProposalID(ctx)
depositParams := k.GetDepositParams(ctx)
votingParams := k.GetVotingParams(ctx)
tallyParams := k.GetTallyParams(ctx)
var deposits []DepositWithMetadata
var votes []VoteWithMetadata
proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0)
for _, proposal := range proposals {
proposalID := proposal.GetProposalID()
depositsIterator := k.GetDeposits(ctx, proposalID)
for ; depositsIterator.Valid(); depositsIterator.Next() {
var deposit Deposit
k.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), &deposit)
deposits = append(deposits, DepositWithMetadata{proposalID, deposit})
}
votesIterator := k.GetVotes(ctx, proposalID)
for ; votesIterator.Valid(); votesIterator.Next() {
var vote Vote
k.cdc.MustUnmarshalBinaryLengthPrefixed(votesIterator.Value(), &vote)
votes = append(votes, VoteWithMetadata{proposalID, vote})
}
}
return GenesisState{
StartingProposalID: startingProposalID,
DepositProcedure: depositProcedure,
VotingProcedure: votingProcedure,
TallyingProcedure: tallyingProcedure,
Deposits: deposits,
Votes: votes,
Proposals: proposals,
DepositParams: depositParams,
VotingParams: votingParams,
TallyParams: tallyParams,
}
}

View File

@ -33,7 +33,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos
return err.Result()
}
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(proposal.GetProposalID())
proposalIDBytes := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal.GetProposalID())
resTags := sdk.NewTags(
tags.Action, tags.ActionSubmitProposal,
@ -102,40 +102,35 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
resTags = sdk.NewTags()
// Delete proposals that haven't met minDeposit
for shouldPopInactiveProposalQueue(ctx, keeper) {
inactiveProposal := keeper.InactiveProposalQueuePop(ctx)
if inactiveProposal.GetStatus() != StatusDepositPeriod {
continue
}
inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
for ; inactiveIterator.Valid(); inactiveIterator.Next() {
var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
inactiveProposal := keeper.GetProposal(ctx, proposalID)
keeper.DeleteProposal(ctx, proposalID)
keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(inactiveProposal.GetProposalID())
keeper.DeleteProposal(ctx, inactiveProposal)
resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
resTags = resTags.AppendTag(tags.ProposalID, proposalIDBytes)
resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
logger.Info(
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %v steak (had only %v steak); deleted",
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
inactiveProposal.GetProposalID(),
inactiveProposal.GetTitle(),
keeper.GetDepositProcedure(ctx).MinDeposit.AmountOf("steak"),
inactiveProposal.GetTotalDeposit().AmountOf("steak"),
keeper.GetDepositParams(ctx).MinDeposit,
inactiveProposal.GetTotalDeposit(),
),
)
}
inactiveIterator.Close()
// Check if earliest Active Proposal ended voting period yet
for shouldPopActiveProposalQueue(ctx, keeper) {
activeProposal := keeper.ActiveProposalQueuePop(ctx)
proposalStartTime := activeProposal.GetVotingStartTime()
votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod
if ctx.BlockHeader().Time.Before(proposalStartTime.Add(votingPeriod)) {
continue
}
activeIterator := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
for ; activeIterator.Valid(); activeIterator.Next() {
var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
activeProposal := keeper.GetProposal(ctx, proposalID)
passes, tallyResults := tally(ctx, keeper, activeProposal)
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID())
var action []byte
if passes {
keeper.RefundDeposits(ctx, activeProposal.GetProposalID())
@ -149,37 +144,15 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
activeProposal.SetTallyResult(tallyResults)
keeper.SetProposal(ctx, activeProposal)
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.GetVotingEndTime(), activeProposal.GetProposalID())
logger.Info(fmt.Sprintf("proposal %d (%s) tallied; passed: %v",
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes))
resTags = resTags.AppendTag(tags.Action, action)
resTags = resTags.AppendTag(tags.ProposalID, proposalIDBytes)
resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
}
activeIterator.Close()
return resTags
}
func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
depositProcedure := keeper.GetDepositProcedure(ctx)
peekProposal := keeper.InactiveProposalQueuePeek(ctx)
if peekProposal == nil {
return false
} else if peekProposal.GetStatus() != StatusDepositPeriod {
return true
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetSubmitTime().Add(depositProcedure.MaxDepositPeriod)) {
return true
}
return false
}
func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
votingProcedure := keeper.GetVotingProcedure(ctx)
peekProposal := keeper.ActiveProposalQueuePeek(ctx)
if peekProposal == nil {
return false
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetVotingStartTime().Add(votingProcedure.VotingPeriod)) {
return true
}
return false
}

View File

@ -1,10 +1,14 @@
package gov
import (
"time"
codec "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/tendermint/tendermint/crypto"
)
// Parameter store default namestore
@ -14,17 +18,20 @@ const (
// Parameter store key
var (
ParamStoreKeyDepositProcedure = []byte("depositprocedure")
ParamStoreKeyVotingProcedure = []byte("votingprocedure")
ParamStoreKeyTallyingProcedure = []byte("tallyingprocedure")
ParamStoreKeyDepositParams = []byte("depositparams")
ParamStoreKeyVotingParams = []byte("votingparams")
ParamStoreKeyTallyParams = []byte("tallyparams")
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
)
// Type declaration for parameters
func ParamTypeTable() params.TypeTable {
return params.NewTypeTable(
ParamStoreKeyDepositProcedure, DepositProcedure{},
ParamStoreKeyVotingProcedure, VotingProcedure{},
ParamStoreKeyTallyingProcedure, TallyingProcedure{},
ParamStoreKeyDepositParams, DepositParams{},
ParamStoreKeyVotingParams, VotingParams{},
ParamStoreKeyTallyParams, TallyParams{},
)
}
@ -92,13 +99,17 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description
TotalDeposit: sdk.Coins{},
SubmitTime: ctx.BlockHeader().Time,
}
depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
proposal.SetDepositEndTime(proposal.GetSubmitTime().Add(depositPeriod))
keeper.SetProposal(ctx, proposal)
keeper.InactiveProposalQueuePush(ctx, proposal)
keeper.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
return proposal
}
// Get Proposal from store by ProposalID
func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID int64) Proposal {
func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) Proposal {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyProposal(proposalID))
if bz == nil {
@ -119,13 +130,16 @@ func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) {
}
// Implements sdk.AccountKeeper.
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposal Proposal) {
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
store.Delete(KeyProposal(proposal.GetProposalID()))
proposal := keeper.GetProposal(ctx, proposalID)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposalID)
store.Delete(KeyProposal(proposalID))
}
// Get Proposal from store by ProposalID
func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositerAddr sdk.AccAddress, status ProposalStatus, numLatest int64) []Proposal {
func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositerAddr sdk.AccAddress, status ProposalStatus, numLatest uint64) []Proposal {
maxProposalID, err := keeper.peekCurrentProposalID(ctx)
if err != nil {
@ -134,7 +148,7 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
matchingProposals := []Proposal{}
if numLatest <= 0 {
if numLatest == 0 {
numLatest = maxProposalID
}
@ -169,7 +183,7 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
return matchingProposals
}
func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk.Error {
func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID uint64) sdk.Error {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID)
if bz != nil {
@ -181,7 +195,7 @@ func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk
}
// Get the last used proposal ID
func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) {
func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID uint64) {
proposalID, err := keeper.peekCurrentProposalID(ctx)
if err != nil {
return 0
@ -191,11 +205,11 @@ func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) {
}
// Gets the next available ProposalID and increments it
func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) {
func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID)
if bz == nil {
return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
bz = keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID + 1)
@ -204,11 +218,11 @@ func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sd
}
// Peeks the next available ProposalID without incrementing it
func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) {
func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID)
if bz == nil {
return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
return proposalID, nil
@ -216,58 +230,62 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
proposal.SetVotingStartTime(ctx.BlockHeader().Time)
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.SetVotingEndTime(proposal.GetVotingStartTime().Add(votingPeriod))
proposal.SetStatus(StatusVotingPeriod)
keeper.SetProposal(ctx, proposal)
keeper.ActiveProposalQueuePush(ctx, proposal)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID())
keeper.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID())
}
// =====================================================
// Procedures
// Params
// Returns the current Deposit Procedure from the global param store
// Returns the current DepositParams from the global param store
// nolint: errcheck
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
var depositProcedure DepositProcedure
keeper.paramSpace.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
return depositProcedure
func (keeper Keeper) GetDepositParams(ctx sdk.Context) DepositParams {
var depositParams DepositParams
keeper.paramSpace.Get(ctx, ParamStoreKeyDepositParams, &depositParams)
return depositParams
}
// Returns the current Voting Procedure from the global param store
// nolint: errcheck
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
var votingProcedure VotingProcedure
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
return votingProcedure
func (keeper Keeper) GetVotingParams(ctx sdk.Context) VotingParams {
var votingParams VotingParams
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingParams, &votingParams)
return votingParams
}
// Returns the current Tallying Procedure from the global param store
// nolint: errcheck
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
var tallyingProcedure TallyingProcedure
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
return tallyingProcedure
func (keeper Keeper) GetTallyParams(ctx sdk.Context) TallyParams {
var tallyParams TallyParams
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyParams, &tallyParams)
return tallyParams
}
// nolint: errcheck
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
func (keeper Keeper) setDepositParams(ctx sdk.Context, depositParams DepositParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositParams, &depositParams)
}
// nolint: errcheck
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
func (keeper Keeper) setVotingParams(ctx sdk.Context, votingParams VotingParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingParams, &votingParams)
}
// nolint: errcheck
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyParams, &tallyParams)
}
// =====================================================
// Votes
// Adds a vote on a specific proposal
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
return ErrUnknownProposal(keeper.codespace, proposalID)
@ -291,7 +309,7 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID int64, voterAddr sdk.Ac
}
// Gets the vote of a specific voter on a specific proposal
func (keeper Keeper) GetVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress) (Vote, bool) {
func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) (Vote, bool) {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyVote(proposalID, voterAddr))
if bz == nil {
@ -302,19 +320,19 @@ func (keeper Keeper) GetVote(ctx sdk.Context, proposalID int64, voterAddr sdk.Ac
return vote, true
}
func (keeper Keeper) setVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress, vote Vote) {
func (keeper Keeper) setVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, vote Vote) {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(vote)
store.Set(KeyVote(proposalID, voterAddr), bz)
}
// Gets all the votes on a specific proposal
func (keeper Keeper) GetVotes(ctx sdk.Context, proposalID int64) sdk.Iterator {
func (keeper Keeper) GetVotes(ctx sdk.Context, proposalID uint64) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey)
return sdk.KVStorePrefixIterator(store, KeyVotesSubspace(proposalID))
}
func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress) {
func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
store := ctx.KVStore(keeper.storeKey)
store.Delete(KeyVote(proposalID, voterAddr))
}
@ -323,7 +341,7 @@ func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID int64, voterAddr sdk
// Deposits
// Gets the deposit of a specific depositer on a specific proposal
func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress) (Deposit, bool) {
func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress) (Deposit, bool) {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyDeposit(proposalID, depositerAddr))
if bz == nil {
@ -334,7 +352,7 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID int64, depositerAddr
return deposit, true
}
func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress, deposit Deposit) {
func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress, deposit Deposit) {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit)
store.Set(KeyDeposit(proposalID, depositerAddr), bz)
@ -342,7 +360,7 @@ func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID int64, depositerAddr
// Adds or updates a deposit of a specific depositer on a specific proposal
// Activates voting period when appropriate
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
// Checks to see if proposal exists
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
@ -354,8 +372,8 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
}
// Subtract coins from depositer's account
_, _, err := keeper.ck.SubtractCoins(ctx, depositerAddr, depositAmount)
// Send coins from depositer's account to DepositedCoinsAccAddr account
_, err := keeper.ck.SendCoins(ctx, depositerAddr, DepositedCoinsAccAddr, depositAmount)
if err != nil {
return err, false
}
@ -367,7 +385,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
// Check if deposit tipped proposal into voting period
// Active voting period if so
activatedVotingPeriod := false
if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsGTE(keeper.GetDepositProcedure(ctx).MinDeposit) {
if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) {
keeper.activateVotingPeriod(ctx, proposal)
activatedVotingPeriod = true
}
@ -386,13 +404,13 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
}
// Gets all the deposits on a specific proposal
func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID int64) sdk.Iterator {
func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey)
return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID))
}
// Returns and deletes all the deposits on a specific proposal
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) {
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -400,7 +418,7 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) {
deposit := &Deposit{}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
_, _, err := keeper.ck.AddCoins(ctx, deposit.Depositer, deposit.Amount)
_, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositer, deposit.Amount)
if err != nil {
panic("should not happen")
}
@ -412,11 +430,19 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) {
}
// Deletes all the deposits on a specific proposal without refunding them
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID int64) {
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
depositsIterator := keeper.GetDeposits(ctx, proposalID)
for ; depositsIterator.Valid(); depositsIterator.Next() {
deposit := &Deposit{}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
_, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount)
if err != nil {
panic("should not happen")
}
store.Delete(depositsIterator.Key())
}
@ -426,93 +452,40 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID int64) {
// =====================================================
// ProposalQueues
func (keeper Keeper) getActiveProposalQueue(ctx sdk.Context) ProposalQueue {
// Returns an iterator for all the proposals in the Active Queue that expire by endTime
func (keeper Keeper) ActiveProposalQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyActiveProposalQueue)
if bz == nil {
return nil
}
var proposalQueue ProposalQueue
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalQueue)
return proposalQueue
return store.Iterator(PrefixActiveProposalQueue, sdk.PrefixEndBytes(PrefixActiveProposalQueueTime(endTime)))
}
func (keeper Keeper) setActiveProposalQueue(ctx sdk.Context, proposalQueue ProposalQueue) {
// Inserts a ProposalID into the active proposal queue at endTime
func (keeper Keeper) InsertActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalQueue)
store.Set(KeyActiveProposalQueue, bz)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
store.Set(KeyActiveProposalQueueProposal(endTime, proposalID), bz)
}
// Return the Proposal at the front of the ProposalQueue
func (keeper Keeper) ActiveProposalQueuePeek(ctx sdk.Context) Proposal {
proposalQueue := keeper.getActiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
return keeper.GetProposal(ctx, proposalQueue[0])
}
// Remove and return a Proposal from the front of the ProposalQueue
func (keeper Keeper) ActiveProposalQueuePop(ctx sdk.Context) Proposal {
proposalQueue := keeper.getActiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
frontElement, proposalQueue := proposalQueue[0], proposalQueue[1:]
keeper.setActiveProposalQueue(ctx, proposalQueue)
return keeper.GetProposal(ctx, frontElement)
}
// Add a proposalID to the back of the ProposalQueue
func (keeper Keeper) ActiveProposalQueuePush(ctx sdk.Context, proposal Proposal) {
proposalQueue := append(keeper.getActiveProposalQueue(ctx), proposal.GetProposalID())
keeper.setActiveProposalQueue(ctx, proposalQueue)
}
func (keeper Keeper) getInactiveProposalQueue(ctx sdk.Context) ProposalQueue {
// removes a proposalID from the Active Proposal Queue
func (keeper Keeper) RemoveFromActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyInactiveProposalQueue)
if bz == nil {
return nil
}
var proposalQueue ProposalQueue
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalQueue)
return proposalQueue
store.Delete(KeyActiveProposalQueueProposal(endTime, proposalID))
}
func (keeper Keeper) setInactiveProposalQueue(ctx sdk.Context, proposalQueue ProposalQueue) {
// Returns an iterator for all the proposals in the Inactive Queue that expire by endTime
func (keeper Keeper) InactiveProposalQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalQueue)
store.Set(KeyInactiveProposalQueue, bz)
return store.Iterator(PrefixInactiveProposalQueue, sdk.PrefixEndBytes(PrefixInactiveProposalQueueTime(endTime)))
}
// Return the Proposal at the front of the ProposalQueue
func (keeper Keeper) InactiveProposalQueuePeek(ctx sdk.Context) Proposal {
proposalQueue := keeper.getInactiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
return keeper.GetProposal(ctx, proposalQueue[0])
// Inserts a ProposalID into the inactive proposal queue at endTime
func (keeper Keeper) InsertInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
store.Set(KeyInactiveProposalQueueProposal(endTime, proposalID), bz)
}
// Remove and return a Proposal from the front of the ProposalQueue
func (keeper Keeper) InactiveProposalQueuePop(ctx sdk.Context) Proposal {
proposalQueue := keeper.getInactiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
frontElement, proposalQueue := proposalQueue[0], proposalQueue[1:]
keeper.setInactiveProposalQueue(ctx, proposalQueue)
return keeper.GetProposal(ctx, frontElement)
}
// Add a proposalID to the back of the ProposalQueue
func (keeper Keeper) InactiveProposalQueuePush(ctx sdk.Context, proposal Proposal) {
proposalQueue := append(keeper.getInactiveProposalQueue(ctx), proposal.GetProposalID())
keeper.setInactiveProposalQueue(ctx, proposalQueue)
// removes a proposalID from the Inactive Proposal Queue
func (keeper Keeper) RemoveFromInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey)
store.Delete(KeyInactiveProposalQueueProposal(endTime, proposalID))
}

View File

@ -1,7 +1,9 @@
package gov
import (
"bytes"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -10,32 +12,68 @@ import (
// Key for getting a the next available proposalID from the store
var (
KeyNextProposalID = []byte("newProposalID")
KeyActiveProposalQueue = []byte("activeProposalQueue")
KeyInactiveProposalQueue = []byte("inactiveProposalQueue")
KeyDelimiter = []byte(":")
KeyNextProposalID = []byte("newProposalID")
PrefixActiveProposalQueue = []byte("activeProposalQueue")
PrefixInactiveProposalQueue = []byte("inactiveProposalQueue")
)
// Key for getting a specific proposal from the store
func KeyProposal(proposalID int64) []byte {
func KeyProposal(proposalID uint64) []byte {
return []byte(fmt.Sprintf("proposals:%d", proposalID))
}
// Key for getting a specific deposit from the store
func KeyDeposit(proposalID int64, depositerAddr sdk.AccAddress) []byte {
func KeyDeposit(proposalID uint64, depositerAddr sdk.AccAddress) []byte {
return []byte(fmt.Sprintf("deposits:%d:%d", proposalID, depositerAddr))
}
// Key for getting a specific vote from the store
func KeyVote(proposalID int64, voterAddr sdk.AccAddress) []byte {
func KeyVote(proposalID uint64, voterAddr sdk.AccAddress) []byte {
return []byte(fmt.Sprintf("votes:%d:%d", proposalID, voterAddr))
}
// Key for getting all deposits on a proposal from the store
func KeyDepositsSubspace(proposalID int64) []byte {
func KeyDepositsSubspace(proposalID uint64) []byte {
return []byte(fmt.Sprintf("deposits:%d:", proposalID))
}
// Key for getting all votes on a proposal from the store
func KeyVotesSubspace(proposalID int64) []byte {
func KeyVotesSubspace(proposalID uint64) []byte {
return []byte(fmt.Sprintf("votes:%d:", proposalID))
}
// Returns the key for a proposalID in the activeProposalQueue
func PrefixActiveProposalQueueTime(endTime time.Time) []byte {
return bytes.Join([][]byte{
PrefixActiveProposalQueue,
sdk.FormatTimeBytes(endTime),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func KeyActiveProposalQueueProposal(endTime time.Time, proposalID uint64) []byte {
return bytes.Join([][]byte{
PrefixActiveProposalQueue,
sdk.FormatTimeBytes(endTime),
sdk.Uint64ToBigEndian(proposalID),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func PrefixInactiveProposalQueueTime(endTime time.Time) []byte {
return bytes.Join([][]byte{
PrefixInactiveProposalQueue,
sdk.FormatTimeBytes(endTime),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func KeyInactiveProposalQueueProposal(endTime time.Time, proposalID uint64) []byte {
return bytes.Join([][]byte{
PrefixInactiveProposalQueue,
sdk.FormatTimeBytes(endTime),
sdk.Uint64ToBigEndian(proposalID),
}, KeyDelimiter)
}

View File

@ -36,7 +36,7 @@ func TestIncrementProposalNumber(t *testing.T) {
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
require.Equal(t, int64(6), proposal6.GetProposalID())
require.Equal(t, uint64(6), proposal6.GetProposalID())
}
func TestActivateVotingPeriod(t *testing.T) {
@ -47,12 +47,17 @@ func TestActivateVotingPeriod(t *testing.T) {
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
require.True(t, proposal.GetVotingStartTime().Equal(time.Time{}))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
keeper.activateVotingPeriod(ctx, proposal)
require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time))
require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime())
require.True(t, activeIterator.Valid())
var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
activeIterator.Close()
}
func TestDeposits(t *testing.T) {
@ -79,7 +84,6 @@ func TestDeposits(t *testing.T) {
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
require.False(t, found)
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{}))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
// Check first deposit
err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourSteak)
@ -116,8 +120,6 @@ func TestDeposits(t *testing.T) {
// Check that proposal moved to voting period
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
// Test deposit iterator
depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -207,44 +209,21 @@ func TestProposalQueues(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
mapp.InitChainer(ctx, abci.RequestInitChain{})
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
// create test proposals
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal2 := keeper.NewTextProposal(ctx, "Test2", "description", ProposalTypeText)
proposal3 := keeper.NewTextProposal(ctx, "Test3", "description", ProposalTypeText)
proposal4 := keeper.NewTextProposal(ctx, "Test4", "description", ProposalTypeText)
// test pushing to inactive proposal queue
keeper.InactiveProposalQueuePush(ctx, proposal)
keeper.InactiveProposalQueuePush(ctx, proposal2)
keeper.InactiveProposalQueuePush(ctx, proposal3)
keeper.InactiveProposalQueuePush(ctx, proposal4)
inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.GetDepositEndTime())
require.True(t, inactiveIterator.Valid())
var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
inactiveIterator.Close()
// test peeking and popping from inactive proposal queue
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID())
keeper.activateVotingPeriod(ctx, proposal)
// test pushing to active proposal queue
keeper.ActiveProposalQueuePush(ctx, proposal)
keeper.ActiveProposalQueuePush(ctx, proposal2)
keeper.ActiveProposalQueuePush(ctx, proposal3)
keeper.ActiveProposalQueuePush(ctx, proposal4)
// test peeking and popping from active proposal queue
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID())
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime())
require.True(t, activeIterator.Valid())
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
activeIterator.Close()
}

View File

@ -84,12 +84,12 @@ func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress {
//-----------------------------------------------------------
// MsgDeposit
type MsgDeposit struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal
ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit
}
func NewMsgDeposit(depositer sdk.AccAddress, proposalID int64, amount sdk.Coins) MsgDeposit {
func NewMsgDeposit(depositer sdk.AccAddress, proposalID uint64, amount sdk.Coins) MsgDeposit {
return MsgDeposit{
ProposalID: proposalID,
Depositer: depositer,
@ -145,12 +145,12 @@ func (msg MsgDeposit) GetSigners() []sdk.AccAddress {
//-----------------------------------------------------------
// MsgVote
type MsgVote struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal
ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Voter sdk.AccAddress `json:"voter"` // address of the voter
Option VoteOption `json:"option"` // option from OptionSet chosen by the voter
}
func NewMsgVote(voter sdk.AccAddress, proposalID int64, option VoteOption) MsgVote {
func NewMsgVote(voter sdk.AccAddress, proposalID uint64, option VoteOption) MsgVote {
return MsgVote{
ProposalID: proposalID,
Voter: voter,

View File

@ -53,13 +53,12 @@ func TestMsgSubmitProposal(t *testing.T) {
func TestMsgDeposit(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
tests := []struct {
proposalID int64
proposalID uint64
depositerAddr sdk.AccAddress
depositAmount sdk.Coins
expectPass bool
}{
{0, addrs[0], coinsPos, true},
{-1, addrs[0], coinsPos, false},
{1, sdk.AccAddress{}, coinsPos, false},
{1, addrs[0], coinsZero, true},
{1, addrs[0], coinsNeg, false},
@ -80,13 +79,12 @@ func TestMsgDeposit(t *testing.T) {
func TestMsgVote(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
tests := []struct {
proposalID int64
proposalID uint64
voterAddr sdk.AccAddress
option VoteOption
expectPass bool
}{
{0, addrs[0], OptionYes, true},
{-1, addrs[0], OptionYes, false},
{0, sdk.AccAddress{}, OptionYes, false},
{0, addrs[0], OptionNo, true},
{0, addrs[0], OptionNoWithVeto, true},

View File

@ -7,19 +7,19 @@ import (
)
// Procedure around Deposits for governance
type DepositProcedure struct {
type DepositParams struct {
MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period.
MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
}
// Procedure around Tallying votes in governance
type TallyingProcedure struct {
type TallyParams struct {
Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote
}
// Procedure around Voting in governance
type VotingProcedure struct {
type VotingParams struct {
VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period.
}

View File

@ -13,8 +13,8 @@ import (
//-----------------------------------------------------------
// Proposal interface
type Proposal interface {
GetProposalID() int64
SetProposalID(int64)
GetProposalID() uint64
SetProposalID(uint64)
GetTitle() string
SetTitle(string)
@ -34,11 +34,17 @@ type Proposal interface {
GetSubmitTime() time.Time
SetSubmitTime(time.Time)
GetDepositEndTime() time.Time
SetDepositEndTime(time.Time)
GetTotalDeposit() sdk.Coins
SetTotalDeposit(sdk.Coins)
GetVotingStartTime() time.Time
SetVotingStartTime(time.Time)
GetVotingEndTime() time.Time
SetVotingEndTime(time.Time)
}
// checks if two proposals are equal
@ -50,8 +56,10 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
proposalA.GetStatus() == proposalB.GetStatus() &&
proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) &&
proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) &&
proposalA.GetDepositEndTime().Equal(proposalB.GetDepositEndTime()) &&
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) {
proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) &&
proposalA.GetVotingEndTime().Equal(proposalB.GetVotingEndTime()) {
return true
}
return false
@ -60,7 +68,7 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
//-----------------------------------------------------------
// Text Proposals
type TextProposal struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal
ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Title string `json:"title"` // Title of the proposal
Description string `json:"description"` // Description of the proposal
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
@ -68,18 +76,20 @@ type TextProposal struct {
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
TallyResult TallyResult `json:"tally_result"` // Result of Tallys
SubmitTime time.Time `json:"submit_time"` // 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
SubmitTime time.Time `json:"submit_time"` // Time of the block where TxGovSubmitProposal was included
DepositEndTime time.Time `json:"deposit_end_time"` // Time that the Proposal would expire if deposit amount isn't met
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
VotingStartTime time.Time `json:"voting_start_time"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
VotingStartTime time.Time `json:"voting_start_time"` // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached
VotingEndTime time.Time `json:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied
}
// Implements Proposal Interface
var _ Proposal = (*TextProposal)(nil)
// nolint
func (tp TextProposal) GetProposalID() int64 { return tp.ProposalID }
func (tp *TextProposal) SetProposalID(proposalID int64) { tp.ProposalID = proposalID }
func (tp TextProposal) GetProposalID() uint64 { return tp.ProposalID }
func (tp *TextProposal) SetProposalID(proposalID uint64) { tp.ProposalID = proposalID }
func (tp TextProposal) GetTitle() string { return tp.Title }
func (tp *TextProposal) SetTitle(title string) { tp.Title = title }
func (tp TextProposal) GetDescription() string { return tp.Description }
@ -92,16 +102,24 @@ func (tp TextProposal) GetTallyResult() TallyResult { return tp.T
func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult }
func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime }
func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime }
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime }
func (tp TextProposal) GetDepositEndTime() time.Time { return tp.DepositEndTime }
func (tp *TextProposal) SetDepositEndTime(depositEndTime time.Time) {
tp.DepositEndTime = depositEndTime
}
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime }
func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) {
tp.VotingStartTime = votingStartTime
}
func (tp TextProposal) GetVotingEndTime() time.Time { return tp.VotingEndTime }
func (tp *TextProposal) SetVotingEndTime(votingEndTime time.Time) {
tp.VotingEndTime = votingEndTime
}
//-----------------------------------------------------------
// ProposalQueue
type ProposalQueue []int64
type ProposalQueue []uint64
//-----------------------------------------------------------
// ProposalKind

View File

@ -42,7 +42,7 @@ func NewQuerier(keeper Keeper) sdk.Querier {
// Params for query 'custom/gov/proposal'
type QueryProposalParams struct {
ProposalID int64
ProposalID uint64
}
// nolint: unparam
@ -67,7 +67,7 @@ func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/deposit'
type QueryDepositParams struct {
ProposalID int64
ProposalID uint64
Depositer sdk.AccAddress
}
@ -89,7 +89,7 @@ func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/vote'
type QueryVoteParams struct {
ProposalID int64
ProposalID uint64
Voter sdk.AccAddress
}
@ -111,7 +111,7 @@ func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Kee
// Params for query 'custom/gov/deposits'
type QueryDepositsParams struct {
ProposalID int64
ProposalID uint64
}
// nolint: unparam
@ -139,7 +139,7 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/votes'
type QueryVotesParams struct {
ProposalID int64
ProposalID uint64
}
// nolint: unparam
@ -168,10 +168,10 @@ func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke
// Params for query 'custom/gov/proposals'
type QueryProposalsParams struct {
Voter sdk.AccAddress
Depositer sdk.AccAddress
ProposalStatus ProposalStatus
NumLatestProposals int64
Voter sdk.AccAddress
Depositer sdk.AccAddress
ProposalStatus ProposalStatus
Limit uint64
}
// nolint: unparam
@ -182,7 +182,7 @@ func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keepe
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error()))
}
proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.NumLatestProposals)
proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.Limit)
bz, err2 := codec.MarshalJSONIndent(keeper.cdc, proposals)
if err2 != nil {
@ -193,19 +193,21 @@ func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keepe
// Params for query 'custom/gov/tally'
type QueryTallyParams struct {
ProposalID int64
ProposalID uint64
}
// nolint: unparam
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
// TODO: Dependant on #1914
var proposalID int64
err2 := keeper.cdc.UnmarshalJSON(req.Data, proposalID)
var params QueryTallyParams
err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
if err2 != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error()))
}
proposalID := params.ProposalID
proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil {
return nil, ErrUnknownProposal(DefaultCodespace, proposalID)

View File

@ -50,7 +50,7 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
if err != nil {
return "", nil, err
}
action, ok := simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
action, ok := simulateHandleMsgSubmitProposal(msg, handler, ctx, event)
// don't schedule votes if proposal failed
if !ok {
return action, nil, nil
@ -64,11 +64,11 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
whoVotes := r.Perm(len(accs))
// didntVote := whoVotes[numVotes:]
whoVotes = whoVotes[:numVotes]
votingPeriod := k.GetVotingProcedure(ctx).VotingPeriod
votingPeriod := k.GetVotingParams(ctx).VotingPeriod
fops := make([]simulation.FutureOperation, numVotes+1)
for i := 0; i < numVotes; i++ {
whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second)
fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, accs[whoVotes[i]], proposalID)}
fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, accs[whoVotes[i]], proposalID)}
}
// 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant)
// TODO: Find a way to check if a validator was slashed other than just checking their balance a block
@ -80,7 +80,7 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
// SimulateMsgSubmitProposal simulates a msg Submit Proposal
// Note: Currently doesn't ensure that the proposal txt is in JSON form
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
func SimulateMsgSubmitProposal(k gov.Keeper) simulation.Operation {
handler := gov.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
sender := simulation.RandomAcc(r, accs)
@ -88,22 +88,14 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operati
if err != nil {
return "", nil, err
}
action, _ = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
action, _ = simulateHandleMsgSubmitProposal(msg, handler, ctx, event)
return action, nil, nil
}
}
func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, sk stake.Keeper, handler sdk.Handler, ctx sdk.Context, event func(string)) (action string, ok bool) {
ctx, write := ctx.CacheContext()
result := handler(ctx, msg)
ok = result.IsOK()
if ok {
// Update pool to keep invariants
pool := sk.GetPool(ctx)
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(msg.InitialDeposit.AmountOf(denom)))
sk.SetPool(ctx, pool)
write()
}
func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, handler sdk.Handler, ctx sdk.Context, event func(string)) (action string, ok bool) {
ctx, _ = ctx.CacheContext()
handler(ctx, msg)
event(fmt.Sprintf("gov/MsgSubmitProposal/%v", ok))
action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", ok, msg.GetSignBytes())
return
@ -125,7 +117,7 @@ func simulationCreateMsgSubmitProposal(r *rand.Rand, sender simulation.Account)
}
// SimulateMsgDeposit
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
func SimulateMsgDeposit(k gov.Keeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
acc := simulation.RandomAcc(r, accs)
proposalID, ok := randomProposalID(r, k, ctx)
@ -137,15 +129,8 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
}
ctx, write := ctx.CacheContext()
ctx, _ = ctx.CacheContext()
result := gov.NewHandler(k)(ctx, msg)
if result.IsOK() {
// Update pool to keep invariants
pool := sk.GetPool(ctx)
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(deposit.AmountOf(denom)))
sk.SetPool(ctx, pool)
write()
}
event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil, nil
@ -154,12 +139,12 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
// SimulateMsgVote
// nolint: unparam
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return operationSimulateMsgVote(k, sk, simulation.Account{}, -1)
func SimulateMsgVote(k gov.Keeper) simulation.Operation {
return operationSimulateMsgVote(k, simulation.Account{}, 0)
}
// nolint: unparam
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, acc simulation.Account, proposalID int64) simulation.Operation {
func operationSimulateMsgVote(k gov.Keeper, acc simulation.Account, proposalID uint64) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
if acc.Equals(simulation.Account{}) {
acc = simulation.RandomAcc(r, accs)
@ -200,12 +185,12 @@ func randomDeposit(r *rand.Rand) sdk.Coins {
}
// Pick a random proposal ID
func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID int64, ok bool) {
func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID uint64, ok bool) {
lastProposalID := k.GetLastProposalID(ctx)
if lastProposalID < 1 {
return 0, false
}
proposalID = int64(r.Intn(int(lastProposalID)))
proposalID = uint64(r.Intn(int(lastProposalID)))
return proposalID, true
}

View File

@ -59,9 +59,9 @@ func TestGovWithRandomMessages(t *testing.T) {
simulation.Simulate(
t, mapp.BaseApp, appStateFn,
[]simulation.WeightedOperation{
{2, SimulateMsgSubmitProposal(govKeeper, stakeKeeper)},
{3, SimulateMsgDeposit(govKeeper, stakeKeeper)},
{20, SimulateMsgVote(govKeeper, stakeKeeper)},
{2, SimulateMsgSubmitProposal(govKeeper)},
{3, SimulateMsgDeposit(govKeeper)},
{20, SimulateMsgVote(govKeeper)},
}, []simulation.RandSetup{
setup,
}, []simulation.Invariant{
@ -75,7 +75,7 @@ func TestGovWithRandomMessages(t *testing.T) {
t, mapp.BaseApp, appStateFn,
[]simulation.WeightedOperation{
{10, SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper)},
{5, SimulateMsgDeposit(govKeeper, stakeKeeper)},
{5, SimulateMsgDeposit(govKeeper)},
}, []simulation.RandSetup{
setup,
}, []simulation.Invariant{

View File

@ -84,7 +84,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
totalVotingPower = totalVotingPower.Add(votingPower)
}
tallyingProcedure := keeper.GetTallyingProcedure(ctx)
tallyParams := keeper.GetTallyParams(ctx)
tallyResults = TallyResult{
Yes: results[OptionYes],
@ -98,11 +98,11 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
return false, tallyResults
}
// If more than 1/3 of voters veto, proposal fails
if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyingProcedure.Veto) {
if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyParams.Veto) {
return false, tallyResults
}
// If more than 1/2 of non-abstaining voters vote Yes, proposal passes
if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyingProcedure.Threshold) {
if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyParams.Threshold) {
return true, tallyResults
}
// If more than 1/2 of non-abstaining voters vote No, proposal fails

View File

@ -31,9 +31,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
keeper.SetParams(ctx, data.Params)
}
// WriteGenesis returns a GenesisState for a given context and keeper. The
// ExportGenesis returns a GenesisState for a given context and keeper. The
// GenesisState will contain the pool, and validator/delegator distribution info's
func WriteGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
minter := keeper.GetMinter(ctx)
params := keeper.GetParams(ctx)

View File

@ -7,13 +7,25 @@ import (
// GenesisState - all slashing state that must be provided at genesis
type GenesisState struct {
Params Params
Params Params
SigningInfos map[string]ValidatorSigningInfo
MissedBlocks map[string][]MissedBlock
SlashingPeriods []ValidatorSlashingPeriod
}
// MissedBlock
type MissedBlock struct {
Index int64 `json:"index"`
Missed bool `json:"missed"`
}
// HubDefaultGenesisState - default GenesisState used by Cosmos Hub
func DefaultGenesisState() GenesisState {
return GenesisState{
Params: DefaultParams(),
Params: DefaultParams(),
SigningInfos: make(map[string]ValidatorSigningInfo),
MissedBlocks: make(map[string][]MissedBlock),
SlashingPeriods: []ValidatorSlashingPeriod{},
}
}
@ -24,5 +36,64 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types.
keeper.addPubkey(ctx, validator.GetConsPubKey())
}
for addr, info := range data.SigningInfos {
address, err := sdk.ConsAddressFromBech32(addr)
if err != nil {
panic(err)
}
keeper.setValidatorSigningInfo(ctx, address, info)
}
for addr, array := range data.MissedBlocks {
address, err := sdk.ConsAddressFromBech32(addr)
if err != nil {
panic(err)
}
for _, missed := range array {
keeper.setValidatorMissedBlockBitArray(ctx, address, missed.Index, missed.Missed)
}
}
for _, slashingPeriod := range data.SlashingPeriods {
keeper.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
}
keeper.paramspace.SetParamSet(ctx, &data.Params)
}
// ExportGenesis writes the current store values
// to a genesis file, which can be imported again
// with InitGenesis
func ExportGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) {
var params Params
keeper.paramspace.GetParamSet(ctx, &params)
signingInfos := make(map[string]ValidatorSigningInfo)
missedBlocks := make(map[string][]MissedBlock)
keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) {
bechAddr := address.String()
signingInfos[bechAddr] = info
array := []MissedBlock{}
keeper.iterateValidatorMissedBlockBitArray(ctx, address, func(index int64, missed bool) (stop bool) {
array = append(array, MissedBlock{index, missed})
return false
})
missedBlocks[bechAddr] = array
return false
})
slashingPeriods := []ValidatorSlashingPeriod{}
keeper.iterateValidatorSlashingPeriods(ctx, func(slashingPeriod ValidatorSlashingPeriod) (stop bool) {
slashingPeriods = append(slashingPeriods, slashingPeriod)
return false
})
return GenesisState{
Params: params,
SigningInfos: signingInfos,
MissedBlocks: missedBlocks,
SlashingPeriods: slashingPeriods,
}
}

View File

@ -3,6 +3,8 @@ package slashing
import (
"time"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -36,6 +38,17 @@ func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddre
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
}
// When a validator is created, add the address-pubkey relation.
func (k Keeper) onValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
validator := k.validatorSet.Validator(ctx, valAddr)
k.addPubkey(ctx, validator.GetConsPubKey())
}
// When a validator is removed, delete the address-pubkey relation.
func (k Keeper) onValidatorRemoved(ctx sdk.Context, address sdk.ConsAddress) {
k.deleteAddrPubkeyRelation(ctx, crypto.Address(address))
}
//_________________________________________________________________________________________
// Wrapper struct
@ -60,12 +73,20 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre
h.k.onValidatorBeginUnbonding(ctx, consAddr, valAddr)
}
// Implements sdk.ValidatorHooks
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) {
h.k.onValidatorRemoved(ctx, consAddr)
}
// Implements sdk.ValidatorHooks
func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.k.onValidatorCreated(ctx, valAddr)
}
// nolint - unused hooks
func (h Hooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
}
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorModified(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}

View File

@ -4,13 +4,10 @@ import (
"fmt"
"time"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
stake "github.com/cosmos/cosmos-sdk/x/stake/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
@ -174,19 +171,6 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
k.setValidatorSigningInfo(ctx, consAddr, signInfo)
}
// AddValidators adds the validators to the keepers validator addr to pubkey mapping.
func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.ValidatorUpdate) {
for i := 0; i < len(vals); i++ {
val := vals[i]
pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey)
if err != nil {
panic(err)
}
k.addPubkey(ctx, pubkey)
}
}
// TODO: Make a method to remove the pubkey from the map when a validator is unbonded.
func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) {
addr := pubkey.Address()
k.setAddrPubkeyRelation(ctx, addr, pubkey)

View File

@ -34,8 +34,7 @@ func TestHandleDoubleSign(t *testing.T) {
operatorAddr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower()))
@ -75,9 +74,8 @@ func TestSlashingPeriodCap(t *testing.T) {
valConsPubKey, valConsAddr := pks[0], pks[0].Address()
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, valConsPubKey, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
stake.EndBlocker(ctx, sk)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower()))
@ -141,8 +139,7 @@ func TestHandleAbsentValidator(t *testing.T) {
slh := NewHandler(keeper)
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
// will exist since the validator has been bonded
@ -298,8 +295,7 @@ func TestHandleNewValidator(t *testing.T) {
// Validator created
got := sh(ctx, NewTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower())
@ -333,8 +329,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
sh := stake.NewHandler(sk)
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
// 1000 first blocks OK
height := int64(0)
@ -386,8 +381,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
sh := stake.NewHandler(sk)
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
// 100 first blocks OK
height := int64(0)
@ -400,9 +394,8 @@ func TestValidatorDippingInAndOut(t *testing.T) {
newAmt := int64(101)
got = sh(ctx, NewTestMsgCreateValidator(addrs[1], pks[1], sdk.NewInt(newAmt)))
require.True(t, got.IsOK())
validatorUpdates = stake.EndBlocker(ctx, sk)
validatorUpdates := stake.EndBlocker(ctx, sk)
require.Equal(t, 2, len(validatorUpdates))
keeper.AddValidators(ctx, validatorUpdates)
validator, _ := sk.GetValidator(ctx, addr)
require.Equal(t, sdk.Unbonding, validator.Status)

View File

@ -20,6 +20,15 @@ func GetValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
return append(ValidatorSigningInfoKey, v.Bytes()...)
}
// extract the address from a validator signing info key
func GetValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
panic("unexpected key length")
}
return sdk.ConsAddress(addr)
}
// stored by *Tendermint* address (not operator address)
func GetValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte {
return append(ValidatorMissedBlockBitArrayKey, v.Bytes()...)

View File

@ -20,6 +20,21 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress
return
}
// Stored by *validator* address (not operator address)
func (k Keeper) iterateValidatorSigningInfos(ctx sdk.Context, handler func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool)) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, ValidatorSigningInfoKey)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
address := GetValidatorSigningInfoAddress(iter.Key())
var info ValidatorSigningInfo
k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info)
if handler(address, info) {
break
}
}
}
// Stored by *validator* address (not operator address)
func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info ValidatorSigningInfo) {
store := ctx.KVStore(k.storeKey)
@ -40,6 +55,24 @@ func (k Keeper) getValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con
return
}
// Stored by *validator* address (not operator address)
func (k Keeper) iterateValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, handler func(index int64, missed bool) (stop bool)) {
store := ctx.KVStore(k.storeKey)
index := int64(0)
// Array may be sparse
for ; index < k.SignedBlocksWindow(ctx); index++ {
var missed bool
bz := store.Get(GetValidatorMissedBlockBitArrayKey(address, index))
if bz == nil {
continue
}
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed)
if handler(index, missed) {
break
}
}
}
// Stored by *validator* address (not operator address)
func (k Keeper) setValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) {
store := ctx.KVStore(k.storeKey)

View File

@ -51,6 +51,21 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk
return
}
// Iterate over all slashing periods in the store, calling on each
// decode slashing period a provided handler function
// Stop if the provided handler function returns true
func (k Keeper) iterateValidatorSlashingPeriods(ctx sdk.Context, handler func(slashingPeriod ValidatorSlashingPeriod) (stop bool)) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, ValidatorSlashingPeriodKey)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
slashingPeriod := k.unmarshalSlashingPeriodKeyValue(iter.Key(), iter.Value())
if handler(slashingPeriod) {
break
}
}
}
// Stored by validator Tendermint address (not operator address)
// This function sets a validator slashing period for a particular validator,
// start height, end height, and current slashed-so-far total, or updates

View File

@ -91,7 +91,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
sk.SetHooks(keeper.Hooks())
require.NotPanics(t, func() {
InitGenesis(ctx, keeper, GenesisState{defaults}, genesis)
InitGenesis(ctx, keeper, GenesisState{defaults, nil, nil, nil}, genesis)
})
return ctx, ck, sk, paramstore, keeper

View File

@ -19,8 +19,7 @@ func TestBeginBlocker(t *testing.T) {
// bond the validator
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(addr, pk, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))

View File

@ -2,13 +2,13 @@ package stake
import (
"fmt"
"sort"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/pkg/errors"
)
// InitGenesis sets the pool and parameters for the provided keeper and
@ -26,22 +26,33 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
keeper.SetPool(ctx, data.Pool)
keeper.SetParams(ctx, data.Params)
keeper.SetIntraTxCounter(ctx, data.IntraTxCounter)
keeper.SetLastTotalPower(ctx, data.LastTotalPower)
// We only need to set this if we're starting from a list of validators, not a state export
setBondIntraTxCounter := true
for _, validator := range data.Validators {
if validator.BondIntraTxCounter != 0 {
setBondIntraTxCounter = false
}
}
for i, validator := range data.Validators {
validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented
// set the intra-tx counter to the order the validators are presented, if necessary
if setBondIntraTxCounter {
validator.BondIntraTxCounter = int16(i)
}
keeper.SetValidator(ctx, validator)
if validator.Tokens.IsZero() {
return res, errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator)
}
if validator.DelegatorShares.IsZero() {
return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator)
}
// Manually set indices for the first time
keeper.SetValidatorByConsAddr(ctx, validator)
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
keeper.OnValidatorCreated(ctx, validator.OperatorAddr)
// Set timeslice if necessary
if validator.Status == sdk.Unbonding {
keeper.InsertValidatorQueue(ctx, validator)
}
}
for _, delegation := range data.Bonds {
@ -49,24 +60,56 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
}
sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool {
return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight
})
for _, ubd := range data.UnbondingDelegations {
keeper.SetUnbondingDelegation(ctx, ubd)
keeper.InsertUnbondingQueue(ctx, ubd)
}
sort.SliceStable(data.Redelegations[:], func(i, j int) bool {
return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight
})
for _, red := range data.Redelegations {
keeper.SetRedelegation(ctx, red)
keeper.InsertRedelegationQueue(ctx, red)
}
res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
return
}
// WriteGenesis returns a GenesisState for a given context and keeper. The
// ExportGenesis returns a GenesisState for a given context and keeper. The
// GenesisState will contain the pool, params, validators, and bonds found in
// the keeper.
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
pool := keeper.GetPool(ctx)
params := keeper.GetParams(ctx)
intraTxCounter := keeper.GetIntraTxCounter(ctx)
lastTotalPower := keeper.GetLastTotalPower(ctx)
validators := keeper.GetAllValidators(ctx)
bonds := keeper.GetAllDelegations(ctx)
var unbondingDelegations []types.UnbondingDelegation
keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) {
unbondingDelegations = append(unbondingDelegations, ubd)
return false
})
var redelegations []types.Redelegation
keeper.IterateRedelegations(ctx, func(_ int64, red types.Redelegation) (stop bool) {
redelegations = append(redelegations, red)
return false
})
return types.GenesisState{
Pool: pool,
Params: params,
Validators: validators,
Bonds: bonds,
Pool: pool,
Params: params,
IntraTxCounter: intraTxCounter,
LastTotalPower: lastTotalPower,
Validators: validators,
Bonds: bonds,
UnbondingDelegations: unbondingDelegations,
Redelegations: redelegations,
}
}
@ -118,11 +161,8 @@ func validateGenesisStateValidators(validators []types.Validator) (err error) {
if val.Jailed && val.Status == sdk.Bonded {
return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
}
if val.Tokens.IsZero() {
return fmt.Errorf("genesis validator cannot have zero pool shares, validator: %v", val)
}
if val.DelegatorShares.IsZero() {
return fmt.Errorf("genesis validator cannot have zero delegator shares, validator: %v", val)
if val.DelegatorShares.IsZero() && val.Status != sdk.Unbonding {
return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val)
}
addrMap[strKey] = true
}

View File

@ -22,29 +22,28 @@ func TestInitGenesis(t *testing.T) {
pool.BondedTokens = sdk.NewDec(2)
params := keeper.GetParams(ctx)
validators := make([]Validator, 2)
var delegations []Delegation
validators := []Validator{
NewValidator(sdk.ValAddress(keep.Addrs[0]), keep.PKs[0], Description{Moniker: "hoop"}),
NewValidator(sdk.ValAddress(keep.Addrs[1]), keep.PKs[1], Description{Moniker: "bloop"}),
}
genesisState := types.NewGenesisState(pool, params, validators, delegations)
_, err := InitGenesis(ctx, keeper, genesisState)
require.Error(t, err)
// initialize the validators
validators[0].OperatorAddr = sdk.ValAddress(keep.Addrs[0])
validators[0].ConsPubKey = keep.PKs[0]
validators[0].Description = Description{Moniker: "hoop"}
validators[0].Status = sdk.Bonded
validators[0].Tokens = sdk.OneDec()
validators[0].DelegatorShares = sdk.OneDec()
validators[1].OperatorAddr = sdk.ValAddress(keep.Addrs[1])
validators[1].ConsPubKey = keep.PKs[1]
validators[1].Description = Description{Moniker: "bloop"}
validators[1].Status = sdk.Bonded
validators[1].Tokens = sdk.OneDec()
validators[1].DelegatorShares = sdk.OneDec()
genesisState = types.NewGenesisState(pool, params, validators, delegations)
genesisState := types.NewGenesisState(pool, params, validators, delegations)
vals, err := InitGenesis(ctx, keeper, genesisState)
require.NoError(t, err)
actualGenesis := WriteGenesis(ctx, keeper)
actualGenesis := ExportGenesis(ctx, keeper)
require.Equal(t, genesisState.Pool, actualGenesis.Pool)
require.Equal(t, genesisState.Params, actualGenesis.Params)
require.Equal(t, genesisState.Bonds, actualGenesis.Bonds)
@ -126,10 +125,6 @@ func TestValidateGenesis(t *testing.T) {
(*data).Validators = genValidators1
(*data).Validators = append((*data).Validators, genValidators1[0])
}, true},
{"no pool shares", func(data *types.GenesisState) {
(*data).Validators = genValidators1
(*data).Validators[0].Tokens = sdk.ZeroDec()
}, true},
{"no delegator shares", func(data *types.GenesisState) {
(*data).Validators = genValidators1
(*data).Validators[0].DelegatorShares = sdk.ZeroDec()

View File

@ -298,6 +298,21 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) {
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
}
// iterate through all redelegations
func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red types.Redelegation) (stop bool)) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, RedelegationKey)
defer iterator.Close()
for i := int64(0); iterator.Valid(); iterator.Next() {
red := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value())
if stop := fn(i, red); stop {
break
}
i++
}
}
// remove a redelegation object and associated index
func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
store := ctx.KVStore(k.storeKey)

View File

@ -17,9 +17,9 @@ func (k Keeper) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
}
}
func (k Keeper) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
func (k Keeper) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnValidatorRemoved(ctx, valAddr)
k.hooks.OnValidatorRemoved(ctx, consAddr, valAddr)
}
}

View File

@ -191,11 +191,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
k.SetPool(ctx, pool)
// save the now bonded validator record to the three referenced stores
// save the now bonded validator record to the two referenced stores
k.SetValidator(ctx, validator)
k.SetValidatorByPowerIndex(ctx, validator, pool)
// delete from queue if present
k.DeleteValidatorQueue(ctx, validator)
// call the bond hook if present
if k.hooks != nil {
k.hooks.OnValidatorBonded(ctx, validator.ConsAddress(), validator.OperatorAddr)
@ -224,9 +226,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
validator.UnbondingHeight = ctx.BlockHeader().Height
// save the now unbonded validator record
// save the now unbonded validator record and power index
k.SetValidator(ctx, validator)
k.SetValidatorByPowerIndex(ctx, validator, pool)
// Adds to unbonding validator queue

View File

@ -1,6 +1,7 @@
package keeper
import (
"bytes"
"container/list"
"fmt"
"time"
@ -201,6 +202,11 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address())))
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
// call hook if present
if k.hooks != nil {
k.hooks.OnValidatorRemoved(ctx, validator.ConsAddress(), validator.OperatorAddr)
}
}
//___________________________________________________________________________
@ -320,6 +326,12 @@ func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time,
store.Set(GetValidatorQueueTimeKey(timestamp), bz)
}
// Deletes a specific validator queue timeslice.
func (k Keeper) DeleteValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) {
store := ctx.KVStore(k.storeKey)
store.Delete(GetValidatorQueueTimeKey(timestamp))
}
// 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)
@ -331,6 +343,22 @@ func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) {
}
}
// Delete a validator address from the validator queue
func (k Keeper) DeleteValidatorQueue(ctx sdk.Context, val types.Validator) {
timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
newTimeSlice := []sdk.ValAddress{}
for _, addr := range timeSlice {
if !bytes.Equal(addr, val.OperatorAddr) {
newTimeSlice = append(newTimeSlice, addr)
}
}
if len(newTimeSlice) == 0 {
k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
} else {
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, newTimeSlice)
}
}
// 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)
@ -358,9 +386,12 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) {
k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), &timeslice)
for _, valAddr := range timeslice {
val, found := k.GetValidator(ctx, valAddr)
if !found || val.GetStatus() != sdk.Unbonding {
if !found {
continue
}
if val.GetStatus() != sdk.Unbonding {
panic("unexpected validator in unbonding queue, status was not unbonding")
}
k.unbondingToUnbonded(ctx, val)
if val.GetDelegatorShares().IsZero() {
k.RemoveValidator(ctx, val.OperatorAddr)

View File

@ -57,6 +57,9 @@ var (
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
TestingUpdateValidator = keeper.TestingUpdateValidator
UnbondingQueueKey = keeper.UnbondingQueueKey
RedelegationQueueKey = keeper.RedelegationQueueKey
ValidatorQueueKey = keeper.ValidatorQueueKey
DefaultParamspace = keeper.DefaultParamspace
KeyUnbondingTime = types.KeyUnbondingTime

View File

@ -1,11 +1,19 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
Pool Pool `json:"pool"`
Params Params `json:"params"`
Validators []Validator `json:"validators"`
Bonds []Delegation `json:"bonds"`
Pool Pool `json:"pool"`
Params Params `json:"params"`
IntraTxCounter int16 `json:"intra_tx_counter"`
LastTotalPower sdk.Int `json:"last_total_power"`
Validators []Validator `json:"validators"`
Bonds []Delegation `json:"bonds"`
UnbondingDelegations []UnbondingDelegation `json:"unbonding_delegations"`
Redelegations []Redelegation `json:"redelegations"`
}
func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []Delegation) GenesisState {

View File

@ -68,6 +68,7 @@ func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress {
func (msg MsgCreateValidator) GetSignBytes() []byte {
b, err := MsgCdc.MarshalJSON(struct {
Description
Commission CommissionMsg
DelegatorAddr sdk.AccAddress `json:"delegator_address"`
ValidatorAddr sdk.ValAddress `json:"validator_address"`
PubKey string `json:"pubkey"`