Merge branch 'develop' into dev/sim_msg_edit_val
This commit is contained in:
commit
0228d8f694
|
@ -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
|
||||
|
|
57
CHANGELOG.md
57
CHANGELOG.md
|
@ -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.
|
||||
* [cli] [\#2704](https://github.com/cosmos/cosmos-sdk/pull/2704) New add-genesis-account convenience command to populate genesis.json with genesis accounts.
|
||||
|
||||
* 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
|
||||
* [\#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*
|
||||
|
|
|
@ -298,7 +298,7 @@
|
|||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6"
|
||||
revision = "0b1957f9d949dfa3084171a6ec5642b38055276a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -434,7 +434,7 @@
|
|||
version = "v0.11.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a"
|
||||
digest = "1:5b1373b03f39e6f6061cd91f3829100527ebb5f94240c092bf9e5d314b153501"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
|
@ -500,8 +500,8 @@
|
|||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de"
|
||||
version = "v0.26.1-rc0"
|
||||
revision = "48ab899923c564bbf2fa2f1244c11cb930e28132"
|
||||
version = "v0.26.1-rc3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "v0.26.1-rc0" # TODO replace w/ 0.26.1
|
||||
version = "v0.26.1-rc3" # TODO replace w/ 0.26.1
|
||||
|
||||
## deps without releases:
|
||||
|
||||
|
|
12
Makefile
12
Makefile
|
@ -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
|
||||
|
|
36
PENDING.md
36
PENDING.md
|
@ -5,30 +5,25 @@ BREAKING CHANGES
|
|||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] [\#2727](https://github.com/cosmos/cosmos-sdk/pull/2727) Fix unbonding command flow
|
||||
|
||||
* Gaia
|
||||
* [gaiad init] \#2602 New genesis workflow
|
||||
|
||||
* SDK
|
||||
* [simulation] \#2665 only argument to simulation.Invariant is now app
|
||||
* [\#2752](https://github.com/cosmos/cosmos-sdk/pull/2752) Don't hardcode bondable denom.
|
||||
|
||||
* 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.
|
||||
|
||||
* Gaia
|
||||
|
||||
* SDK
|
||||
* (#1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
|
||||
* [simulator] \#2682 MsgEditValidator now looks at the validator's max rate, thus it now succeeds a significant portion of the time
|
||||
|
||||
* Tendermint
|
||||
|
@ -39,22 +34,12 @@ IMPROVEMENTS
|
|||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [\#2749](https://github.com/cosmos/cosmos-sdk/pull/2749) Add --chain-id flag to gaiad testnet
|
||||
|
||||
* Gaia
|
||||
- #2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue
|
||||
|
||||
* 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
|
||||
- \#2610 [x/stake] Block redelegation to and from the same validator
|
||||
- \#2652 [x/auth] Add benchmark for get and set account
|
||||
- \#2685 [store] Add general merkle absence proof (also for empty substores)
|
||||
- \#2708 [store] Disallow setting nil values
|
||||
- [x/mock/simulation] [\#2720] major cleanup, introduction of helper objects, reorganization
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
@ -66,13 +51,10 @@ BUG FIXES
|
|||
* Gaia CLI (`gaiacli`)
|
||||
|
||||
* Gaia
|
||||
- \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
|
||||
- \#2691 Fix local testnet creation by using a single canonical genesis time
|
||||
|
||||
* [\#2723] Use `cosmosvalcons` Bech32 prefix in `tendermint show-address`
|
||||
* [\#2742](https://github.com/cosmos/cosmos-sdk/issues/2742) Fix time format of TimeoutCommit override
|
||||
|
||||
* SDK
|
||||
- \#2625 [x/gov] fix AppendTag function usage error
|
||||
- \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator
|
||||
- \#2674 [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see \#2686)
|
||||
- \#2711 [x/stake] Add commission data to `MsgCreateValidator` signature bytes.
|
||||
|
||||
* Tendermint
|
||||
* [\#2797](https://github.com/tendermint/tendermint/pull/2797) AddressBook requires addresses to have IDs; Do not crap out immediately after sending pex addrs in seed mode
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -265,7 +266,7 @@ func TestCoinSend(t *testing.T) {
|
|||
coins := acc.GetCoins()
|
||||
mycoins := coins[0]
|
||||
|
||||
require.Equal(t, "steak", mycoins.Denom)
|
||||
require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom)
|
||||
require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount)
|
||||
|
||||
// query receiver
|
||||
|
@ -273,7 +274,7 @@ func TestCoinSend(t *testing.T) {
|
|||
coins = acc.GetCoins()
|
||||
mycoins = coins[0]
|
||||
|
||||
require.Equal(t, "steak", mycoins.Denom)
|
||||
require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom)
|
||||
require.Equal(t, int64(1), mycoins.Amount.Int64())
|
||||
|
||||
// test failure with too little gas
|
||||
|
@ -326,7 +327,7 @@ func DisabledTestIBCTransfer(t *testing.T) {
|
|||
coins := acc.GetCoins()
|
||||
mycoins := coins[0]
|
||||
|
||||
require.Equal(t, "steak", mycoins.Denom)
|
||||
require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom)
|
||||
require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount)
|
||||
|
||||
// TODO: query ibc egress packet state
|
||||
|
@ -514,7 +515,7 @@ func TestValidatorQuery(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBonding(t *testing.T) {
|
||||
name, password, denom := "test", "1234567890", "steak"
|
||||
name, password, denom := "test", "1234567890", stakeTypes.DefaultBondDenom
|
||||
addr, seed := CreateAddr(t, name, password, GetKeyBase(t))
|
||||
|
||||
cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 2, []sdk.AccAddress{addr})
|
||||
|
@ -564,7 +565,7 @@ func TestBonding(t *testing.T) {
|
|||
// sender should have not received any coins as the unbonding has only just begun
|
||||
acc = getAccount(t, port, addr)
|
||||
coins = acc.GetCoins()
|
||||
require.Equal(t, int64(40), coins.AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), coins.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
unbonding := getUndelegation(t, port, addr, operAddrs[0])
|
||||
require.Equal(t, "30", unbonding.Balance.Amount.String())
|
||||
|
@ -663,11 +664,11 @@ func TestDeposit(t *testing.T) {
|
|||
|
||||
// query proposal
|
||||
proposal = getProposal(t, port, proposalID)
|
||||
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 10)}))
|
||||
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)}))
|
||||
|
||||
// query deposit
|
||||
deposit := getDeposit(t, port, proposalID, addr)
|
||||
require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 10)}))
|
||||
require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)}))
|
||||
}
|
||||
|
||||
func TestVote(t *testing.T) {
|
||||
|
@ -861,7 +862,7 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
|
|||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
// send
|
||||
coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin("steak", 1))
|
||||
coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -947,7 +948,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc
|
|||
"account_number":"%d",
|
||||
"sequence":"%d"
|
||||
}
|
||||
}`, "steak", name, password, chainID, accnum, sequence))
|
||||
}`, stakeTypes.DefaultBondDenom, name, password, chainID, accnum, sequence))
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/ibc/testchain/%s/send", receiveAddr), jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -1096,7 +1097,7 @@ func doDelegate(t *testing.T, port, seed, name, password string,
|
|||
"account_number":"%d",
|
||||
"sequence":"%d"
|
||||
}
|
||||
}`, delAddr, valAddr, "steak", amount, name, password, chainID, accnum, sequence))
|
||||
}`, delAddr, valAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence))
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -1339,7 +1340,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
|||
"description": "test",
|
||||
"proposal_type": "Text",
|
||||
"proposer": "%s",
|
||||
"initial_deposit": [{ "denom": "steak", "amount": "%d" }],
|
||||
"initial_deposit": [{ "denom": "%s", "amount": "%d" }],
|
||||
"base_req": {
|
||||
"name": "%s",
|
||||
"password": "%s",
|
||||
|
@ -1347,7 +1348,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
|||
"account_number":"%d",
|
||||
"sequence":"%d"
|
||||
}
|
||||
}`, proposerAddr, amount, name, password, chainID, accnum, sequence))
|
||||
}`, proposerAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence))
|
||||
res, body := Request(t, port, "POST", "/gov/proposals", jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
|
@ -1369,7 +1370,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
|||
// deposit on proposal
|
||||
jsonStr := []byte(fmt.Sprintf(`{
|
||||
"depositer": "%s",
|
||||
"amount": [{ "denom": "steak", "amount": "%d" }],
|
||||
"amount": [{ "denom": "%s", "amount": "%d" }],
|
||||
"base_req": {
|
||||
"name": "%s",
|
||||
"password": "%s",
|
||||
|
@ -1377,7 +1378,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
|||
"account_number":"%d",
|
||||
"sequence": "%d"
|
||||
}
|
||||
}`, proposerAddr, amount, name, password, chainID, accnum, sequence))
|
||||
}`, proposerAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence))
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -227,7 +228,7 @@ func InitializeTestLCD(
|
|||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(operAddr),
|
||||
pubKey,
|
||||
sdk.NewCoin("steak", sdk.NewInt(int64(delegation))),
|
||||
sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(int64(delegation))),
|
||||
stake.Description{Moniker: fmt.Sprintf("validator-%d", i+1)},
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
|
@ -245,7 +246,7 @@ func InitializeTestLCD(
|
|||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
||||
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 150)}
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150)}
|
||||
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
|
||||
}
|
||||
|
||||
|
@ -259,7 +260,7 @@ func InitializeTestLCD(
|
|||
// add some tokens to init accounts
|
||||
for _, addr := range initAddrs {
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)}
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100)}
|
||||
acc := gapp.NewGenesisAccount(&accAuth)
|
||||
genesisState.Accounts = append(genesisState.Accounts, acc)
|
||||
genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@ -26,12 +27,13 @@ var (
|
|||
// bonded tokens given to genesis validators/accounts
|
||||
freeFermionVal = int64(100)
|
||||
freeFermionsAcc = sdk.NewInt(150)
|
||||
bondDenom = "steak"
|
||||
bondDenom = stakeTypes.DefaultBondDenom
|
||||
)
|
||||
|
||||
// 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 +42,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 +56,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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,9 +287,11 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
|
|||
|
||||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
accAuth.Coins = []sdk.Coin{
|
||||
coins :=sdk.Coins{
|
||||
{"fooToken", sdk.NewInt(1000)},
|
||||
{"steak", freeFermionsAcc},
|
||||
{bondDenom, freeFermionsAcc},
|
||||
}
|
||||
coins.Sort()
|
||||
accAuth.Coins = coins
|
||||
return NewGenesisAccount(&accAuth)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -28,6 +29,7 @@ import (
|
|||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -61,7 +63,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
|
||||
// Randomly generate some genesis accounts
|
||||
for _, acc := range accs {
|
||||
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amount)}}
|
||||
coins := sdk.Coins{sdk.Coin{stakeTypes.DefaultBondDenom, sdk.NewInt(amount)}}
|
||||
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: coins,
|
||||
|
@ -72,7 +74,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
govGenesis := gov.GenesisState{
|
||||
StartingProposalID: uint64(r.Intn(100)),
|
||||
DepositParams: gov.DepositParams{
|
||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))},
|
||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, int64(r.Intn(1e3)))},
|
||||
MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
|
||||
},
|
||||
VotingParams: gov.VotingParams{
|
||||
|
@ -90,7 +92,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
Params: stake.Params{
|
||||
UnbondingTime: time.Duration(r.Intn(60*60*24*3*2)) * time.Second,
|
||||
MaxValidators: uint16(r.Intn(250)),
|
||||
BondDenom: "steak",
|
||||
BondDenom: stakeTypes.DefaultBondDenom,
|
||||
},
|
||||
}
|
||||
fmt.Printf("Selected randomly generated staking parameters: %+v\n", stakeGenesis)
|
||||
|
@ -112,7 +114,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
},
|
||||
Params: mint.Params{
|
||||
MintDenom: "steak",
|
||||
MintDenom: stakeTypes.DefaultBondDenom,
|
||||
InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
||||
|
@ -266,6 +268,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) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -55,10 +56,10 @@ func TestGaiaCLIMinimumFees(t *testing.T) {
|
|||
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
success := executeWrite(t, fmt.Sprintf(
|
||||
"gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
"gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.False(t, success)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -121,40 +122,40 @@ func TestGaiaCLISend(t *testing.T) {
|
|||
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo --dry-run", flags, barAddr), app.DefaultKeyPass)
|
||||
success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo --dry-run", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
// Check state didn't change
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
// test autosequencing
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(20), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
// test memo
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo --memo 'testmemo'", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(30), barAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(30), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
}
|
||||
|
||||
func TestGaiaCLIGasAuto(t *testing.T) {
|
||||
|
@ -172,26 +173,26 @@ func TestGaiaCLIGasAuto(t *testing.T) {
|
|||
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
// Test failure with auto gas disabled and very little gas set by hand
|
||||
success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=10 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=10 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.False(t, success)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
// Check state didn't change
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
// Test failure with negative gas
|
||||
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=-100 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=-100 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.False(t, success)
|
||||
|
||||
// Test failure with 0 gas
|
||||
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=0 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=0 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.False(t, success)
|
||||
|
||||
// Enable auto gas
|
||||
success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx send %v --json --gas=simulate --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx send %v --json --gas=simulate --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
// check that gas wanted == gas used
|
||||
cdc := app.MakeCodec()
|
||||
|
@ -205,7 +206,7 @@ func TestGaiaCLIGasAuto(t *testing.T) {
|
|||
tests.WaitForNextNBlocksTM(2, port)
|
||||
// Check state has changed accordingly
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
}
|
||||
|
||||
func TestGaiaCLICreateValidator(t *testing.T) {
|
||||
|
@ -223,13 +224,13 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
barCeshPubKey := sdk.MustBech32ifyConsPub(barPubKey)
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
defaultParams := stake.DefaultParams()
|
||||
initialPool := stake.InitialPool()
|
||||
|
@ -239,7 +240,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
cvStr := fmt.Sprintf("gaiacli tx create-validator %v", flags)
|
||||
cvStr += fmt.Sprintf(" --from=%s", "bar")
|
||||
cvStr += fmt.Sprintf(" --pubkey=%s", barCeshPubKey)
|
||||
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
|
||||
cvStr += fmt.Sprintf(" --amount=%v", fmt.Sprintf("2%s", stakeTypes.DefaultBondDenom))
|
||||
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||
cvStr += fmt.Sprintf(" --commission-rate=%v", "0.05")
|
||||
cvStr += fmt.Sprintf(" --commission-max-rate=%v", "0.20")
|
||||
|
@ -265,7 +266,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
|
||||
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64(), "%v", barAcc)
|
||||
|
||||
validator := executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
|
||||
require.Equal(t, validator.OperatorAddr, sdk.ValAddress(barAddr))
|
||||
|
@ -283,7 +284,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
|
||||
/* // this won't be what we expect because we've only started unbonding, haven't completed
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %v %v", barCech, flags))
|
||||
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
|
||||
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64(), "%v", barAcc)
|
||||
*/
|
||||
validator = executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
|
||||
require.Equal(t, "1.0000000000", validator.Tokens.String())
|
||||
|
@ -315,7 +316,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
proposalsQuery, _ := tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
require.Equal(t, "No matching proposals found", proposalsQuery)
|
||||
|
@ -323,7 +324,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
// submit a test proposal
|
||||
spStr := fmt.Sprintf("gaiacli tx submit-proposal %v", flags)
|
||||
spStr += fmt.Sprintf(" --from=%s", "foo")
|
||||
spStr += fmt.Sprintf(" --deposit=%s", "5steak")
|
||||
spStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("5%s", stakeTypes.DefaultBondDenom))
|
||||
spStr += fmt.Sprintf(" --type=%s", "Text")
|
||||
spStr += fmt.Sprintf(" --title=%s", "Test")
|
||||
spStr += fmt.Sprintf(" --description=%s", "test")
|
||||
|
@ -346,7 +347,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
|
@ -358,11 +359,11 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
deposit := executeGetDeposit(t,
|
||||
fmt.Sprintf("gaiacli query deposit --proposal-id=1 --depositer=%s --output=json %v",
|
||||
fooAddr, flags))
|
||||
require.Equal(t, int64(5), deposit.Amount.AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(5), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
depositStr := fmt.Sprintf("gaiacli tx deposit %v", flags)
|
||||
depositStr += fmt.Sprintf(" --from=%s", "foo")
|
||||
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
|
||||
depositStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("10%s", stakeTypes.DefaultBondDenom))
|
||||
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||
|
||||
// Test generate only
|
||||
|
@ -382,15 +383,15 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
deposits := executeGetDeposits(t,
|
||||
fmt.Sprintf("gaiacli query deposits --proposal-id=1 --output=json %v", flags))
|
||||
require.Len(t, deposits, 1)
|
||||
require.Equal(t, int64(15), deposits[0].Amount.AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(15), deposits[0].Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
deposit = executeGetDeposit(t,
|
||||
fmt.Sprintf("gaiacli query deposit --proposal-id=1 --depositer=%s --output=json %v",
|
||||
fooAddr, flags))
|
||||
require.Equal(t, int64(15), deposit.Amount.AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(15), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
|
||||
|
@ -431,7 +432,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
// submit a second test proposal
|
||||
spStr = fmt.Sprintf("gaiacli tx submit-proposal %v", flags)
|
||||
spStr += fmt.Sprintf(" --from=%s", "foo")
|
||||
spStr += fmt.Sprintf(" --deposit=%s", "5steak")
|
||||
spStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("5%s", stakeTypes.DefaultBondDenom))
|
||||
spStr += fmt.Sprintf(" --type=%s", "Text")
|
||||
spStr += fmt.Sprintf(" --title=%s", "Apples")
|
||||
spStr += fmt.Sprintf(" --description=%s", "test")
|
||||
|
@ -460,8 +461,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
|
||||
// Test generate sendTx with default gas
|
||||
success, stdout, stderr := executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --generate-only",
|
||||
flags, barAddr), []string{}...)
|
||||
"gaiacli tx send %v --amount=10%s --to=%s --from=foo --generate-only",
|
||||
flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg := unmarshalStdTx(t, stdout)
|
||||
|
@ -471,8 +472,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
|
||||
// Test generate sendTx with --gas=$amount
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=100 --generate-only",
|
||||
flags, barAddr), []string{}...)
|
||||
"gaiacli tx send %v --amount=10%s --to=%s --from=foo --gas=100 --generate-only",
|
||||
flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg = unmarshalStdTx(t, stdout)
|
||||
|
@ -482,8 +483,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
|
||||
// Test generate sendTx, estimate gas
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=simulate --generate-only",
|
||||
flags, barAddr), []string{}...)
|
||||
"gaiacli tx send %v --amount=10%s --to=%s --from=foo --gas=simulate --generate-only",
|
||||
flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...)
|
||||
require.True(t, success)
|
||||
require.NotEmpty(t, stderr)
|
||||
msg = unmarshalStdTx(t, stdout)
|
||||
|
@ -522,7 +523,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
|
||||
// Test broadcast
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
||||
|
@ -536,9 +537,9 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
}
|
||||
|
||||
func TestGaiaCLIConfig(t *testing.T) {
|
||||
|
|
|
@ -42,6 +42,7 @@ func main() {
|
|||
rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, server.AppInit{}))
|
||||
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
|
||||
rootCmd.AddCommand(gaiaInit.AddGenesisAccountCmd(ctx, cdc))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
|
|
@ -113,6 +113,6 @@ func genAppStateFromConfig(
|
|||
return
|
||||
}
|
||||
|
||||
err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command
|
||||
func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-genesis-account [address] [coin][,[coin]]",
|
||||
Short: "Add genesis account to genesis.json",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
addr, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
coins, err := sdk.ParseCoins(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
coins.Sort()
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
if !common.FileExists(genFile) {
|
||||
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
|
||||
}
|
||||
genDoc, err := loadGenesisDoc(cdc, genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var appState app.GenesisState
|
||||
if err = cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
acc := auth.NewBaseAccountWithAddress(addr)
|
||||
acc.Coins = coins
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc))
|
||||
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ExportGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
return cmd
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
|
@ -21,7 +22,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultAmount = "100steak"
|
||||
defaultAmount = "100" + stakeTypes.DefaultBondDenom
|
||||
defaultCommissionRate = "0.1"
|
||||
defaultCommissionMaxRate = "0.2"
|
||||
defaultCommissionMaxChangeRate = "0.01"
|
||||
|
|
|
@ -70,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
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ 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"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -75,14 +76,20 @@ Example:
|
|||
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, ...)")
|
||||
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
|
||||
var chainID string
|
||||
outDir := viper.GetString(flagOutputDir)
|
||||
numValidators := viper.GetInt(flagNumValidators)
|
||||
|
||||
chainID := "chain-" + cmn.RandStr(6)
|
||||
chainID = viper.GetString(client.FlagChainID)
|
||||
if chainID == "" {
|
||||
chainID = "chain-" + cmn.RandStr(6)
|
||||
}
|
||||
|
||||
monikers := make([]string, numValidators)
|
||||
nodeIDs := make([]string, numValidators)
|
||||
|
@ -174,14 +181,14 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
|
|||
Address: addr,
|
||||
Coins: sdk.Coins{
|
||||
sdk.NewInt64Coin(fmt.Sprintf("%sToken", nodeDirName), 1000),
|
||||
sdk.NewInt64Coin("steak", 150),
|
||||
sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150),
|
||||
},
|
||||
})
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
sdk.NewInt64Coin("steak", 100),
|
||||
sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100),
|
||||
stake.NewDescription(nodeDirName, "", "", ""),
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
|
@ -298,7 +305,7 @@ func collectGenFiles(
|
|||
genFile := config.GenesisFile()
|
||||
|
||||
// overwrite each validator's genesis file to have a canonical genesis time
|
||||
err = WriteGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
|
||||
err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ import (
|
|||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// ExportGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
func WriteGenesisFile(
|
||||
func ExportGenesisFile(
|
||||
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
|
||||
) error {
|
||||
|
||||
|
@ -36,9 +36,9 @@ func WriteGenesisFile(
|
|||
return genDoc.SaveAs(genFile)
|
||||
}
|
||||
|
||||
// WriteGenesisFileWithTime creates and writes the genesis configuration to disk.
|
||||
// ExportGenesisFileWithTime creates and writes the genesis configuration to disk.
|
||||
// An error is returned if building or writing the configuration to file fails.
|
||||
func WriteGenesisFileWithTime(
|
||||
func ExportGenesisFileWithTime(
|
||||
genFile, chainID string, validators []types.GenesisValidator,
|
||||
appState json.RawMessage, genTime time.Time,
|
||||
) error {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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"})
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)})
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
const stakingToken = "steak"
|
||||
const stakingToken = "stake"
|
||||
|
||||
const moduleName = "simplestake"
|
||||
|
||||
|
|
|
@ -75,10 +75,10 @@ func TestBonding(t *testing.T) {
|
|||
_, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr)
|
||||
require.Equal(t, err, ErrInvalidUnbond(DefaultCodespace))
|
||||
|
||||
_, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("steak", 10))
|
||||
_, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("stake", 10))
|
||||
require.Nil(t, err)
|
||||
|
||||
power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("steak", 10))
|
||||
power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("stake", 10))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(20), power)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ echo "Using temporary log directory: $tmpdir"
|
|||
sim() {
|
||||
seed=$1
|
||||
echo "Running full Gaia simulation with seed $seed. This may take awhile!"
|
||||
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -Iseconds -u).stdout"
|
||||
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout"
|
||||
echo "Writing stdout to $file..."
|
||||
go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=$blocks \
|
||||
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -v -timeout 24h > $file
|
||||
|
|
|
@ -63,17 +63,17 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
func ShowAddressCmd(ctx *Context) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "show-address",
|
||||
Short: "Shows this node's tendermint validator address",
|
||||
Short: "Shows this node's tendermint validator consensus address",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg := ctx.Config
|
||||
privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile())
|
||||
valAddr := (sdk.ValAddress)(privValidator.Address)
|
||||
valConsAddr := (sdk.ConsAddress)(privValidator.Address)
|
||||
|
||||
if viper.GetBool(client.FlagJson) {
|
||||
return printlnJSON(valAddr)
|
||||
return printlnJSON(valConsAddr)
|
||||
}
|
||||
|
||||
fmt.Println(valAddr.String())
|
||||
fmt.Println(valConsAddr.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -92,7 +93,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
|
|||
conf.P2P.RecvRate = 5120000
|
||||
conf.P2P.SendRate = 5120000
|
||||
conf.TxIndex.IndexAllTags = true
|
||||
conf.Consensus.TimeoutCommit = 5000
|
||||
conf.Consensus.TimeoutCommit = 5 * time.Second
|
||||
cfg.WriteConfigFile(configFilePath, conf)
|
||||
// Fall through, just so that its parsed into memory.
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ func TestSameDenomAsCoin(t *testing.T) {
|
|||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
||||
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true},
|
||||
{NewInt64Coin("steak", -11), NewInt64Coin("steak", 10), true},
|
||||
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), true},
|
||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), true},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
|
@ -107,8 +107,8 @@ func TestIsEqualCoin(t *testing.T) {
|
|||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
||||
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false},
|
||||
{NewInt64Coin("steak", -11), NewInt64Coin("steak", 10), false},
|
||||
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), false},
|
||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), false},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
|
@ -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.
|
||||
|
|
|
@ -21,8 +21,8 @@ func TestSortJSON(t *testing.T) {
|
|||
want: "",
|
||||
wantErr: true},
|
||||
// genesis.json
|
||||
{unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`,
|
||||
want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`,
|
||||
{unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"stake","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"stake"},"candidates":null,"bonds":null}}}`,
|
||||
want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"stake"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"stake","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`,
|
||||
wantErr: false},
|
||||
// from the TXSpec:
|
||||
{unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`,
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -46,7 +47,7 @@ func TestTxBuilderBuild(t *testing.T) {
|
|||
SimulateGas: false,
|
||||
ChainID: "test-chain",
|
||||
Memo: "hello",
|
||||
Fee: "1steak",
|
||||
Fee: "1" + stakeTypes.DefaultBondDenom,
|
||||
},
|
||||
defaultMsg,
|
||||
StdSignMsg{
|
||||
|
@ -55,7 +56,7 @@ func TestTxBuilderBuild(t *testing.T) {
|
|||
Sequence: 1,
|
||||
Memo: "hello",
|
||||
Msgs: defaultMsg,
|
||||
Fee: auth.NewStdFee(100, sdk.NewCoin("steak", sdk.NewInt(1))),
|
||||
Fee: auth.NewStdFee(100, sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(1))),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
|
@ -20,7 +21,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
|
|||
require.False(t, inactiveQueue.Valid())
|
||||
inactiveQueue.Close()
|
||||
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
|
||||
res := govHandler(ctx, newProposalMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
@ -62,7 +63,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
|||
require.False(t, inactiveQueue.Valid())
|
||||
inactiveQueue.Close()
|
||||
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
|
||||
res := govHandler(ctx, newProposalMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
@ -79,7 +80,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
|||
require.False(t, inactiveQueue.Valid())
|
||||
inactiveQueue.Close()
|
||||
|
||||
newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
res = govHandler(ctx, newProposalMsg2)
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
|
@ -121,7 +122,7 @@ func TestTickPassedDepositPeriod(t *testing.T) {
|
|||
require.False(t, activeQueue.Valid())
|
||||
activeQueue.Close()
|
||||
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
|
||||
res := govHandler(ctx, newProposalMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
@ -140,7 +141,7 @@ func TestTickPassedDepositPeriod(t *testing.T) {
|
|||
require.False(t, inactiveQueue.Valid())
|
||||
inactiveQueue.Close()
|
||||
|
||||
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
res = govHandler(ctx, newDepositMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
|
@ -163,7 +164,7 @@ func TestTickPassedVotingPeriod(t *testing.T) {
|
|||
require.False(t, activeQueue.Valid())
|
||||
activeQueue.Close()
|
||||
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
|
||||
res := govHandler(ctx, newProposalMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
@ -174,7 +175,7 @@ func TestTickPassedVotingPeriod(t *testing.T) {
|
|||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
|
||||
ctx = ctx.WithBlockHeader(newHeader)
|
||||
|
||||
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)})
|
||||
res = govHandler(ctx, newDepositMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
|
|
|
@ -4,14 +4,30 @@ import (
|
|||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// GenesisState - all staking state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
StartingProposalID uint64 `json:"starting_proposalID"`
|
||||
DepositParams DepositParams `json:"deposit_params"`
|
||||
VotingParams VotingParams `json:"voting_params"`
|
||||
TallyParams TallyParams `json:"tally_params"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
@ -28,7 +44,7 @@ func DefaultGenesisState() GenesisState {
|
|||
return GenesisState{
|
||||
StartingProposalID: 1,
|
||||
DepositParams: DepositParams{
|
||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)},
|
||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)},
|
||||
MaxDepositPeriod: time.Duration(172800) * time.Second,
|
||||
},
|
||||
VotingParams: VotingParams{
|
||||
|
@ -52,17 +68,47 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
|||
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)
|
||||
// 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,
|
||||
Deposits: deposits,
|
||||
Votes: votes,
|
||||
Proposals: proposals,
|
||||
DepositParams: depositParams,
|
||||
VotingParams: votingParams,
|
||||
TallyParams: tallyParams,
|
||||
|
|
|
@ -107,8 +107,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
|||
var proposalID uint64
|
||||
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
|
||||
inactiveProposal := keeper.GetProposal(ctx, proposalID)
|
||||
keeper.RefundDeposits(ctx, proposalID)
|
||||
keeper.DeleteProposal(ctx, proposalID)
|
||||
keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
|
||||
|
||||
resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
|
||||
resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
func TestGetSetProposal(t *testing.T) {
|
||||
|
@ -69,14 +70,14 @@ func TestDeposits(t *testing.T) {
|
|||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
|
||||
fourSteak := sdk.Coins{sdk.NewInt64Coin("steak", 4)}
|
||||
fiveSteak := sdk.Coins{sdk.NewInt64Coin("steak", 5)}
|
||||
fourSteak := sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 4)}
|
||||
fiveSteak := sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}
|
||||
|
||||
addr0Initial := keeper.ck.GetCoins(ctx, addrs[0])
|
||||
addr1Initial := keeper.ck.GetCoins(ctx, addrs[1])
|
||||
|
||||
// require.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 42)}))
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin("steak", 42)}, addr0Initial)
|
||||
// require.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)}))
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)}, addr0Initial)
|
||||
|
||||
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{}))
|
||||
|
||||
|
|
|
@ -7,16 +7,21 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
coinsPos = sdk.Coins{sdk.NewInt64Coin("steak", 1000)}
|
||||
coinsPos = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1000)}
|
||||
coinsZero = sdk.Coins{}
|
||||
coinsNeg = sdk.Coins{sdk.NewInt64Coin("steak", -10000)}
|
||||
coinsNeg = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, -10000)}
|
||||
coinsPosNotAtoms = sdk.Coins{sdk.NewInt64Coin("foo", 10000)}
|
||||
coinsMulti = sdk.Coins{sdk.NewInt64Coin("foo", 10000), sdk.NewInt64Coin("steak", 1000)}
|
||||
coinsMulti = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1000), sdk.NewInt64Coin("foo", 10000)}
|
||||
)
|
||||
|
||||
func init() {
|
||||
coinsMulti.Sort()
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgCreateValidator
|
||||
func TestMsgSubmitProposal(t *testing.T) {
|
||||
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
|
||||
|
@ -42,9 +47,9 @@ func TestMsgSubmitProposal(t *testing.T) {
|
|||
for i, tc := range tests {
|
||||
msg := NewMsgSubmitProposal(tc.title, tc.description, tc.proposalType, tc.proposerAddr, tc.initialDeposit)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.Error(t, msg.ValidateBasic(), "test: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,9 +73,9 @@ func TestMsgDeposit(t *testing.T) {
|
|||
for i, tc := range tests {
|
||||
msg := NewMsgDeposit(tc.depositerAddr, tc.proposalID, tc.depositAmount)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.Error(t, msg.ValidateBasic(), "test: %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,11 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
const (
|
||||
denom = "steak"
|
||||
denom = stakeTypes.DefaultBondDenom
|
||||
)
|
||||
|
||||
// SimulateSubmittingVotingAndSlashingForProposal simulates creating a msg Submit Proposal
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -25,7 +26,7 @@ func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, a
|
|||
|
||||
for i := 0; i < len(addrs); i++ {
|
||||
valCreateMsg := stake.NewMsgCreateValidator(
|
||||
addrs[i], pubkeys[i], sdk.NewInt64Coin("steak", coinAmt[i]), testDescription, testCommissionMsg,
|
||||
addrs[i], pubkeys[i], sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, coinAmt[i]), testDescription, testCommissionMsg,
|
||||
)
|
||||
|
||||
res := stakeHandler(ctx, valCreateMsg)
|
||||
|
@ -289,7 +290,7 @@ func TestTallyDelgatorOverride(t *testing.T) {
|
|||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 30))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
@ -326,7 +327,7 @@ func TestTallyDelgatorInherit(t *testing.T) {
|
|||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 30))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
@ -361,9 +362,9 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
|
|||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg2)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
@ -393,24 +394,24 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
|
|||
stakeHandler := stake.NewHandler(sk)
|
||||
|
||||
val1CreateMsg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), testDescription, testCommissionMsg,
|
||||
sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 25), testDescription, testCommissionMsg,
|
||||
)
|
||||
stakeHandler(ctx, val1CreateMsg)
|
||||
|
||||
val2CreateMsg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), testDescription, testCommissionMsg,
|
||||
sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 6), testDescription, testCommissionMsg,
|
||||
)
|
||||
stakeHandler(ctx, val2CreateMsg)
|
||||
|
||||
val3CreateMsg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), testDescription, testCommissionMsg,
|
||||
sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 7), testDescription, testCommissionMsg,
|
||||
)
|
||||
stakeHandler(ctx, val3CreateMsg)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg2)
|
||||
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
@ -447,10 +448,10 @@ func TestTallyJailedValidator(t *testing.T) {
|
|||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10))
|
||||
stakeHandler(ctx, delegator1Msg2)
|
||||
|
||||
val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1]))
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// initialize the mock application for this module
|
||||
|
@ -44,7 +45,7 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper,
|
|||
|
||||
require.NoError(t, mapp.CompleteSetup(keyStake, tkeyStake, keyGov, keyGlobalParams, tkeyGlobalParams))
|
||||
|
||||
genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin("steak", 42)})
|
||||
genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)})
|
||||
|
||||
mock.SetGenesis(mapp, genAccs)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,6 +2,7 @@ package mint
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -18,7 +19,7 @@ type Params struct {
|
|||
// default minting module parameters
|
||||
func DefaultParams() Params {
|
||||
return Params{
|
||||
MintDenom: "steak",
|
||||
MintDenom: stakeTypes.DefaultBondDenom,
|
||||
InflationRateChange: sdk.NewDecWithPrec(13, 2),
|
||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Account contains a privkey, pubkey, address tuple
|
||||
// eventually more useful data can be placed in here.
|
||||
// (e.g. number of coins)
|
||||
type Account struct {
|
||||
PrivKey crypto.PrivKey
|
||||
PubKey crypto.PubKey
|
||||
Address sdk.AccAddress
|
||||
}
|
||||
|
||||
// are two accounts equal
|
||||
func (acc Account) Equals(acc2 Account) bool {
|
||||
return acc.Address.Equals(acc2.Address)
|
||||
}
|
||||
|
||||
// RandomAcc pick a random account from an array
|
||||
func RandomAcc(r *rand.Rand, accs []Account) Account {
|
||||
return accs[r.Intn(
|
||||
len(accs),
|
||||
)]
|
||||
}
|
||||
|
||||
// RandomAccounts generates n random accounts
|
||||
func RandomAccounts(r *rand.Rand, n int) []Account {
|
||||
accs := make([]Account, n)
|
||||
for i := 0; i < n; i++ {
|
||||
// don't need that much entropy for simulation
|
||||
privkeySeed := make([]byte, 15)
|
||||
r.Read(privkeySeed)
|
||||
useSecp := r.Int63()%2 == 0
|
||||
if useSecp {
|
||||
accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed)
|
||||
} else {
|
||||
accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||
}
|
||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||
}
|
||||
return accs
|
||||
}
|
|
@ -2,26 +2,24 @@
|
|||
Package simulation implements a simulation framework for any state machine
|
||||
built on the SDK which utilizes auth.
|
||||
|
||||
It is primarily intended for fuzz testing the integration of modules.
|
||||
It will test that the provided operations are interoperable,
|
||||
and that the desired invariants hold.
|
||||
It can additionally be used to detect what the performance benchmarks in the
|
||||
system are, by using benchmarking mode and cpu / mem profiling.
|
||||
If it detects a failure, it provides the entire log of what was ran,
|
||||
It is primarily intended for fuzz testing the integration of modules. It will
|
||||
test that the provided operations are interoperable, and that the desired
|
||||
invariants hold. It can additionally be used to detect what the performance
|
||||
benchmarks in the system are, by using benchmarking mode and cpu / mem
|
||||
profiling. If it detects a failure, it provides the entire log of what was ran.
|
||||
|
||||
The simulator takes as input: a random seed, the set of operations to run,
|
||||
the invariants to test, and additional parameters to configure how long to run,
|
||||
and misc. parameters that affect simulation speed.
|
||||
The simulator takes as input: a random seed, the set of operations to run, the
|
||||
invariants to test, and additional parameters to configure how long to run, and
|
||||
misc. parameters that affect simulation speed.
|
||||
|
||||
It is intended that every module provides a list of Operations which will randomly
|
||||
create and run a message / tx in a manner that is interesting to fuzz, and verify that
|
||||
the state transition was executed as expected.
|
||||
Each module should additionally provide methods to assert that the desired invariants hold.
|
||||
It is intended that every module provides a list of Operations which will
|
||||
randomly create and run a message / tx in a manner that is interesting to fuzz,
|
||||
and verify that the state transition was executed as expected. Each module
|
||||
should additionally provide methods to assert that the desired invariants hold.
|
||||
|
||||
Then to perform a randomized simulation, select the set of desired operations,
|
||||
the weightings for each, the invariants you want to test, and how long to run it for.
|
||||
Then run simulation.Simulate!
|
||||
The simulator will handle things like ensuring that validators periodically double signing,
|
||||
or go offline.
|
||||
the weightings for each, the invariants you want to test, and how long to run
|
||||
it for. Then run simulation.Simulate! The simulator will handle things like
|
||||
ensuring that validators periodically double signing, or go offline.
|
||||
*/
|
||||
package simulation
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type eventStats map[string]uint
|
||||
|
||||
func newEventStats() eventStats {
|
||||
events := make(map[string]uint)
|
||||
return events
|
||||
}
|
||||
|
||||
func (es eventStats) tally(eventDesc string) {
|
||||
es[eventDesc]++
|
||||
}
|
||||
|
||||
// Pretty-print events as a table
|
||||
func (es eventStats) Print() {
|
||||
var keys []string
|
||||
for key := range es {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
fmt.Printf("Event statistics: \n")
|
||||
for _, key := range keys {
|
||||
fmt.Printf(" % 60s => %d\n", key, es[key])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
)
|
||||
|
||||
// An Invariant is a function which tests a particular invariant.
|
||||
// If the invariant has been broken, it should return an error
|
||||
// containing a descriptive message about what happened.
|
||||
// The simulator will then halt and print the logs.
|
||||
type Invariant func(app *baseapp.BaseApp) error
|
||||
|
||||
// group of Invarient
|
||||
type Invariants []Invariant
|
||||
|
||||
// assertAll asserts the all invariants against application state
|
||||
func (invs Invariants) assertAll(t *testing.T, app *baseapp.BaseApp,
|
||||
event string, displayLogs func()) {
|
||||
|
||||
for i := 0; i < len(invs); i++ {
|
||||
if err := invs[i](app); err != nil {
|
||||
fmt.Printf("Invariants broken after %s\n%s\n", event, err.Error())
|
||||
displayLogs()
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
type mockValidator struct {
|
||||
val abci.ValidatorUpdate
|
||||
livenessState int
|
||||
}
|
||||
|
||||
type mockValidators map[string]mockValidator
|
||||
|
||||
// get mockValidators from abci validators
|
||||
func newMockValidators(r *rand.Rand, abciVals []abci.ValidatorUpdate,
|
||||
params Params) mockValidators {
|
||||
|
||||
validators := make(mockValidators)
|
||||
for _, validator := range abciVals {
|
||||
str := fmt.Sprintf("%v", validator.PubKey)
|
||||
liveliness := GetMemberOfInitialState(r,
|
||||
params.InitialLivenessWeightings)
|
||||
|
||||
validators[str] = mockValidator{
|
||||
val: validator,
|
||||
livenessState: liveliness,
|
||||
}
|
||||
}
|
||||
|
||||
return validators
|
||||
}
|
||||
|
||||
// TODO describe usage
|
||||
func (vals mockValidators) getKeys() []string {
|
||||
keys := make([]string, len(vals))
|
||||
i := 0
|
||||
for key := range vals {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________
|
||||
|
||||
// randomProposer picks a random proposer from the current validator set
|
||||
func (vals mockValidators) randomProposer(r *rand.Rand) cmn.HexBytes {
|
||||
keys := vals.getKeys()
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
proposer := vals[key].val
|
||||
pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pk.Address()
|
||||
}
|
||||
|
||||
// updateValidators mimicks Tendermint's update logic
|
||||
// nolint: unparam
|
||||
func updateValidators(tb testing.TB, r *rand.Rand, params Params,
|
||||
current map[string]mockValidator, updates []abci.ValidatorUpdate,
|
||||
event func(string)) map[string]mockValidator {
|
||||
|
||||
for _, update := range updates {
|
||||
str := fmt.Sprintf("%v", update.PubKey)
|
||||
|
||||
if update.Power == 0 {
|
||||
if _, ok := current[str]; !ok {
|
||||
tb.Fatalf("tried to delete a nonexistent validator")
|
||||
}
|
||||
event("endblock/validatorupdates/kicked")
|
||||
delete(current, str)
|
||||
|
||||
} else if mVal, ok := current[str]; ok {
|
||||
// validator already exists
|
||||
mVal.val = update
|
||||
event("endblock/validatorupdates/updated")
|
||||
|
||||
} else {
|
||||
// Set this new validator
|
||||
current[str] = mockValidator{
|
||||
update,
|
||||
GetMemberOfInitialState(r, params.InitialLivenessWeightings),
|
||||
}
|
||||
event("endblock/validatorupdates/added")
|
||||
}
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
// RandomRequestBeginBlock generates a list of signing validators according to
|
||||
// the provided list of validators, signing fraction, and evidence fraction
|
||||
func RandomRequestBeginBlock(r *rand.Rand, params Params,
|
||||
validators mockValidators, pastTimes []time.Time,
|
||||
pastVoteInfos [][]abci.VoteInfo,
|
||||
event func(string), header abci.Header) abci.RequestBeginBlock {
|
||||
|
||||
if len(validators) == 0 {
|
||||
return abci.RequestBeginBlock{
|
||||
Header: header,
|
||||
}
|
||||
}
|
||||
|
||||
voteInfos := make([]abci.VoteInfo, len(validators))
|
||||
for i, key := range validators.getKeys() {
|
||||
mVal := validators[key]
|
||||
mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState)
|
||||
signed := true
|
||||
|
||||
if mVal.livenessState == 1 {
|
||||
// spotty connection, 50% probability of success
|
||||
// See https://github.com/golang/go/issues/23804#issuecomment-365370418
|
||||
// for reasoning behind computing like this
|
||||
signed = r.Int63()%2 == 0
|
||||
} else if mVal.livenessState == 2 {
|
||||
// offline
|
||||
signed = false
|
||||
}
|
||||
|
||||
if signed {
|
||||
event("beginblock/signing/signed")
|
||||
} else {
|
||||
event("beginblock/signing/missed")
|
||||
}
|
||||
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(mVal.val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
voteInfos[i] = abci.VoteInfo{
|
||||
Validator: abci.Validator{
|
||||
Address: pubkey.Address(),
|
||||
Power: mVal.val.Power,
|
||||
},
|
||||
SignedLastBlock: signed,
|
||||
}
|
||||
}
|
||||
|
||||
// return if no past times
|
||||
if len(pastTimes) <= 0 {
|
||||
return abci.RequestBeginBlock{
|
||||
Header: header,
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Votes: voteInfos,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Determine capacity before allocation
|
||||
evidence := make([]abci.Evidence, 0)
|
||||
for r.Float64() < params.EvidenceFraction {
|
||||
|
||||
height := header.Height
|
||||
time := header.Time
|
||||
vals := voteInfos
|
||||
|
||||
if r.Float64() < params.PastEvidenceFraction {
|
||||
height = int64(r.Intn(int(header.Height) - 1))
|
||||
time = pastTimes[height]
|
||||
vals = pastVoteInfos[height]
|
||||
}
|
||||
validator := vals[r.Intn(len(vals))].Validator
|
||||
|
||||
var totalVotingPower int64
|
||||
for _, val := range vals {
|
||||
totalVotingPower += val.Validator.Power
|
||||
}
|
||||
|
||||
evidence = append(evidence,
|
||||
abci.Evidence{
|
||||
Type: tmtypes.ABCIEvidenceTypeDuplicateVote,
|
||||
Validator: validator,
|
||||
Height: height,
|
||||
Time: time,
|
||||
TotalVotingPower: totalVotingPower,
|
||||
},
|
||||
)
|
||||
event("beginblock/evidence")
|
||||
}
|
||||
|
||||
return abci.RequestBeginBlock{
|
||||
Header: header,
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Votes: voteInfos,
|
||||
},
|
||||
ByzantineValidators: evidence,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Operation runs a state machine transition, and ensures the transition
|
||||
// happened as expected. The operation could be running and testing a fuzzed
|
||||
// transaction, or doing the same for a message.
|
||||
//
|
||||
// For ease of debugging, an operation returns a descriptive message "action",
|
||||
// which details what this fuzzed state machine transition actually did.
|
||||
//
|
||||
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||
// These will be ran at the beginning of the corresponding block.
|
||||
type Operation func(r *rand.Rand, app *baseapp.BaseApp,
|
||||
ctx sdk.Context, accounts []Account, event func(string)) (
|
||||
action string, futureOps []FutureOperation, err error)
|
||||
|
||||
// queue of operations
|
||||
type OperationQueue map[int][]Operation
|
||||
|
||||
func newOperationQueue() OperationQueue {
|
||||
operationQueue := make(OperationQueue)
|
||||
return operationQueue
|
||||
}
|
||||
|
||||
// adds all future operations into the operation queue.
|
||||
func queueOperations(queuedOps OperationQueue,
|
||||
queuedTimeOps []FutureOperation, futureOps []FutureOperation) {
|
||||
|
||||
if futureOps == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, futureOp := range futureOps {
|
||||
if futureOp.BlockHeight != 0 {
|
||||
if val, ok := queuedOps[futureOp.BlockHeight]; ok {
|
||||
queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op)
|
||||
} else {
|
||||
queuedOps[futureOp.BlockHeight] = []Operation{futureOp.Op}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Replace with proper sorted data structure, so don't have the
|
||||
// copy entire slice
|
||||
index := sort.Search(
|
||||
len(queuedTimeOps),
|
||||
func(i int) bool {
|
||||
return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime)
|
||||
},
|
||||
)
|
||||
queuedTimeOps = append(queuedTimeOps, FutureOperation{})
|
||||
copy(queuedTimeOps[index+1:], queuedTimeOps[index:])
|
||||
queuedTimeOps[index] = futureOp
|
||||
}
|
||||
}
|
||||
|
||||
//________________________________________________________________________
|
||||
|
||||
// FutureOperation is an operation which will be ran at the beginning of the
|
||||
// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it
|
||||
// will use the BlockHeight. In the (likely) event that multiple operations
|
||||
// are queued at the same block height, they will execute in a FIFO pattern.
|
||||
type FutureOperation struct {
|
||||
BlockHeight int
|
||||
BlockTime time.Time
|
||||
Op Operation
|
||||
}
|
||||
|
||||
//________________________________________________________________________
|
||||
|
||||
// WeightedOperation is an operation with associated weight.
|
||||
// This is used to bias the selection operation within the simulator.
|
||||
type WeightedOperation struct {
|
||||
Weight int
|
||||
Op Operation
|
||||
}
|
||||
|
||||
// WeightedOperations is the group of all weighted operations to simulate.
|
||||
type WeightedOperations []WeightedOperation
|
||||
|
||||
func (ops WeightedOperations) totalWeight() int {
|
||||
totalOpWeight := 0
|
||||
for _, op := range ops {
|
||||
totalOpWeight += op.Weight
|
||||
}
|
||||
return totalOpWeight
|
||||
}
|
||||
|
||||
type selectOpFn func(r *rand.Rand) Operation
|
||||
|
||||
func (ops WeightedOperations) getSelectOpFn() selectOpFn {
|
||||
totalOpWeight := ops.totalWeight()
|
||||
return func(r *rand.Rand) Operation {
|
||||
x := r.Intn(totalOpWeight)
|
||||
for i := 0; i < len(ops); i++ {
|
||||
if x <= ops[i].Weight {
|
||||
return ops[i].Op
|
||||
}
|
||||
x -= ops[i].Weight
|
||||
}
|
||||
// shouldn't happen
|
||||
return ops[0].Op
|
||||
}
|
||||
}
|
|
@ -15,15 +15,18 @@ const (
|
|||
onOperation bool = false
|
||||
)
|
||||
|
||||
// TODO explain transitional matrix usage
|
||||
var (
|
||||
// Currently there are 3 different liveness types, fully online, spotty connection, offline.
|
||||
// Currently there are 3 different liveness types,
|
||||
// fully online, spotty connection, offline.
|
||||
defaultLivenessTransitionMatrix, _ = CreateTransitionMatrix([][]int{
|
||||
{90, 20, 1},
|
||||
{10, 50, 5},
|
||||
{0, 10, 1000},
|
||||
})
|
||||
|
||||
// 3 states: rand in range [0, 4*provided blocksize], rand in range [0, 2 * provided blocksize], 0
|
||||
// 3 states: rand in range [0, 4*provided blocksize],
|
||||
// rand in range [0, 2 * provided blocksize], 0
|
||||
defaultBlockSizeTransitionMatrix, _ = CreateTransitionMatrix([][]int{
|
||||
{85, 5, 0},
|
||||
{15, 92, 1},
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
// shamelessly copied from
|
||||
// https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326
|
||||
// Generate a random string of a particular length
|
||||
func RandStringOfLength(r *rand.Rand, n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, r.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = r.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Generate a random amount
|
||||
func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
|
||||
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
|
||||
}
|
||||
|
||||
// RandomDecAmount generates a random decimal amount
|
||||
func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec {
|
||||
randInt := big.NewInt(0).Rand(r, max.Int)
|
||||
return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision)
|
||||
}
|
||||
|
||||
// RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts
|
||||
func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) {
|
||||
addrs := make([]sdk.AccAddress, len(accs))
|
||||
for i := 0; i < len(accs); i++ {
|
||||
addrs[i] = accs[i].Address
|
||||
}
|
||||
mock.RandomSetGenesis(r, app, addrs, denoms)
|
||||
}
|
||||
|
||||
// RandTimestamp generates a random timestamp
|
||||
func RandTimestamp(r *rand.Rand) time.Time {
|
||||
// json.Marshal breaks for timestamps greater with year greater than 9999
|
||||
unixTime := r.Int63n(253373529600)
|
||||
return time.Unix(unixTime, 0)
|
||||
}
|
|
@ -1,488 +0,0 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Simulate tests application by sending random messages.
|
||||
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
||||
ops []WeightedOperation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool) error {
|
||||
|
||||
time := time.Now().UnixNano()
|
||||
return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
||||
}
|
||||
|
||||
func initChain(r *rand.Rand, params Params, accounts []Account, setups []RandSetup, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) (validators map[string]mockValidator) {
|
||||
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)})
|
||||
validators = make(map[string]mockValidator)
|
||||
for _, validator := range res.Validators {
|
||||
str := fmt.Sprintf("%v", validator.PubKey)
|
||||
validators[str] = mockValidator{validator, GetMemberOfInitialState(r, params.InitialLivenessWeightings)}
|
||||
}
|
||||
|
||||
for i := 0; i < len(setups); i++ {
|
||||
setups[i](r, accounts)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func randTimestamp(r *rand.Rand) time.Time {
|
||||
// json.Marshal breaks for timestamps greater with year greater than 9999
|
||||
unixTime := r.Int63n(253373529600)
|
||||
return time.Unix(unixTime, 0)
|
||||
}
|
||||
|
||||
// SimulateFromSeed tests an application by running the provided
|
||||
// operations, testing the provided invariants, but using the provided seed.
|
||||
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
|
||||
seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant,
|
||||
numBlocks int, blockSize int, commit bool) (simError error) {
|
||||
|
||||
// in case we have to end early, don't os.Exit so that we can run cleanup code.
|
||||
stopEarly := false
|
||||
testingMode, t, b := getTestingMode(tb)
|
||||
fmt.Printf("Starting SimulateFromSeed with randomness created with seed %d\n", int(seed))
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
params := RandomParams(r) // := DefaultParams()
|
||||
fmt.Printf("Randomized simulation params: %+v\n", params)
|
||||
timestamp := randTimestamp(r)
|
||||
fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||
|
||||
accs := RandomAccounts(r, params.NumKeys)
|
||||
|
||||
// Setup event stats
|
||||
events := make(map[string]uint)
|
||||
event := func(what string) {
|
||||
events[what]++
|
||||
}
|
||||
|
||||
validators := initChain(r, params, accs, setups, app, appStateFn)
|
||||
// Second variable to keep pending validator set (delayed one block since TM 0.24)
|
||||
// Initially this is the same as the initial validator set
|
||||
nextValidators := validators
|
||||
|
||||
header := abci.Header{Height: 1, Time: timestamp, ProposerAddress: randomProposer(r, validators)}
|
||||
opCount := 0
|
||||
|
||||
// Setup code to catch SIGTERM's
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
receivedSignal := <-c
|
||||
fmt.Printf("\nExiting early due to %s, on block %d, operation %d\n", receivedSignal, header.Height, opCount)
|
||||
simError = fmt.Errorf("Exited due to %s", receivedSignal)
|
||||
stopEarly = true
|
||||
}()
|
||||
|
||||
var pastTimes []time.Time
|
||||
var pastVoteInfos [][]abci.VoteInfo
|
||||
|
||||
request := RandomRequestBeginBlock(r, params, validators, pastTimes, pastVoteInfos, event, header)
|
||||
// These are operations which have been queued by previous operations
|
||||
operationQueue := make(map[int][]Operation)
|
||||
timeOperationQueue := []FutureOperation{}
|
||||
var blockLogBuilders []*strings.Builder
|
||||
|
||||
if testingMode {
|
||||
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
||||
}
|
||||
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
||||
blockSimulator := createBlockSimulator(testingMode, tb, t, params, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, blockSize, displayLogs)
|
||||
if !testingMode {
|
||||
b.ResetTimer()
|
||||
} else {
|
||||
// Recover logs in case of panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Panic with err\n", r)
|
||||
stackTrace := string(debug.Stack())
|
||||
fmt.Println(stackTrace)
|
||||
displayLogs()
|
||||
simError = fmt.Errorf("Simulation halted due to panic on block %d", header.Height)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < numBlocks && !stopEarly; i++ {
|
||||
// Log the header time for future lookup
|
||||
pastTimes = append(pastTimes, header.Time)
|
||||
pastVoteInfos = append(pastVoteInfos, request.LastCommitInfo.Votes)
|
||||
|
||||
// Construct log writer
|
||||
logWriter := addLogMessage(testingMode, blockLogBuilders, i)
|
||||
|
||||
// Run the BeginBlock handler
|
||||
logWriter("BeginBlock")
|
||||
app.BeginBlock(request)
|
||||
|
||||
if testingMode {
|
||||
// Make sure invariants hold at beginning of block
|
||||
assertAllInvariants(t, app, invariants, "BeginBlock", displayLogs)
|
||||
}
|
||||
|
||||
ctx := app.NewContext(false, header)
|
||||
|
||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||
logWriter("Queued operations")
|
||||
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, accs, logWriter, displayLogs, event)
|
||||
numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, accs, logWriter, displayLogs, event)
|
||||
if testingMode && onOperation {
|
||||
// Make sure invariants hold at end of queued operations
|
||||
assertAllInvariants(t, app, invariants, "QueuedOperations", displayLogs)
|
||||
}
|
||||
|
||||
logWriter("Standard operations")
|
||||
operations := blockSimulator(r, app, ctx, accs, header, logWriter)
|
||||
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
||||
if testingMode {
|
||||
// Make sure invariants hold at end of block
|
||||
assertAllInvariants(t, app, invariants, "StandardOperations", displayLogs)
|
||||
}
|
||||
|
||||
res := app.EndBlock(abci.RequestEndBlock{})
|
||||
header.Height++
|
||||
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||
header.ProposerAddress = randomProposer(r, validators)
|
||||
logWriter("EndBlock")
|
||||
|
||||
if testingMode {
|
||||
// Make sure invariants hold at end of block
|
||||
assertAllInvariants(t, app, invariants, "EndBlock", displayLogs)
|
||||
}
|
||||
if commit {
|
||||
app.Commit()
|
||||
}
|
||||
|
||||
if header.ProposerAddress == nil {
|
||||
fmt.Printf("\nSimulation stopped early as all validators have been unbonded, there is nobody left propose a block!\n")
|
||||
stopEarly = true
|
||||
break
|
||||
}
|
||||
|
||||
// Generate a random RequestBeginBlock with the current validator set for the next block
|
||||
request = RandomRequestBeginBlock(r, params, validators, pastTimes, pastVoteInfos, event, header)
|
||||
|
||||
// Update the validator set, which will be reflected in the application on the next block
|
||||
validators = nextValidators
|
||||
nextValidators = updateValidators(tb, r, params, validators, res.ValidatorUpdates, event)
|
||||
}
|
||||
if stopEarly {
|
||||
DisplayEvents(events)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount)
|
||||
DisplayEvents(events)
|
||||
return nil
|
||||
}
|
||||
|
||||
type blockSimFn func(
|
||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, header abci.Header, logWriter func(string),
|
||||
) (opCount int)
|
||||
|
||||
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
||||
// memory overhead
|
||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params,
|
||||
event func(string), invariants []Invariant,
|
||||
ops []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation,
|
||||
totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn {
|
||||
|
||||
var (
|
||||
lastBlocksizeState = 0 // state for [4 * uniform distribution]
|
||||
totalOpWeight = 0
|
||||
blocksize int
|
||||
)
|
||||
|
||||
for i := 0; i < len(ops); i++ {
|
||||
totalOpWeight += ops[i].Weight
|
||||
}
|
||||
selectOp := func(r *rand.Rand) Operation {
|
||||
x := r.Intn(totalOpWeight)
|
||||
for i := 0; i < len(ops); i++ {
|
||||
if x <= ops[i].Weight {
|
||||
return ops[i].Op
|
||||
}
|
||||
x -= ops[i].Weight
|
||||
}
|
||||
// shouldn't happen
|
||||
return ops[0].Op
|
||||
}
|
||||
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize)
|
||||
lastBlocksizeState, blocksize = getBlockSize(r, params, lastBlocksizeState, avgBlockSize)
|
||||
for j := 0; j < blocksize; j++ {
|
||||
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err)
|
||||
}
|
||||
|
||||
queueOperations(operationQueue, timeOperationQueue, futureOps)
|
||||
if testingMode {
|
||||
if onOperation {
|
||||
assertAllInvariants(t, app, invariants, fmt.Sprintf("operation: %v", logUpdate), displayLogs)
|
||||
}
|
||||
if opCount%50 == 0 {
|
||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize)
|
||||
}
|
||||
}
|
||||
opCount++
|
||||
}
|
||||
return opCount
|
||||
}
|
||||
}
|
||||
|
||||
func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) {
|
||||
testingMode = false
|
||||
if _t, ok := tb.(*testing.T); ok {
|
||||
t = _t
|
||||
testingMode = true
|
||||
} else {
|
||||
b = tb.(*testing.B)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getBlockSize returns a block size as determined from the transition matrix.
|
||||
// It targets making average block size the provided parameter. The three
|
||||
// states it moves between are:
|
||||
// "over stuffed" blocks with average size of 2 * avgblocksize,
|
||||
// normal sized blocks, hitting avgBlocksize on average,
|
||||
// and empty blocks, with no txs / only txs scheduled from the past.
|
||||
func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize int) (state, blocksize int) {
|
||||
// TODO: Make default blocksize transition matrix actually make the average
|
||||
// blocksize equal to avgBlockSize.
|
||||
state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState)
|
||||
if state == 0 {
|
||||
blocksize = r.Intn(avgBlockSize * 4)
|
||||
} else if state == 1 {
|
||||
blocksize = r.Intn(avgBlockSize * 2)
|
||||
} else {
|
||||
blocksize = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// adds all future operations into the operation queue.
|
||||
func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations []FutureOperation, futureOperations []FutureOperation) {
|
||||
if futureOperations == nil {
|
||||
return
|
||||
}
|
||||
for _, futureOp := range futureOperations {
|
||||
if futureOp.BlockHeight != 0 {
|
||||
if val, ok := queuedOperations[futureOp.BlockHeight]; ok {
|
||||
queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op)
|
||||
} else {
|
||||
queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op}
|
||||
}
|
||||
} else {
|
||||
// TODO: Replace with proper sorted data structure, so don't have the copy entire slice
|
||||
index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) })
|
||||
queuedTimeOperations = append(queuedTimeOperations, FutureOperation{})
|
||||
copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:])
|
||||
queuedTimeOperations[index] = futureOp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
|
||||
if queuedOps, ok := queueOperations[height]; ok {
|
||||
numOps := len(queuedOps)
|
||||
for i := 0; i < numOps; i++ {
|
||||
// For now, queued operations cannot queue more operations.
|
||||
// If a need arises for us to support queued messages to queue more messages, this can
|
||||
// be changed.
|
||||
logUpdate, _, err := queuedOps[i](r, app, ctx, accounts, event)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
delete(queueOperations, height)
|
||||
return numOps
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func runQueuedTimeOperations(queueOperations []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
|
||||
|
||||
numOpsRan = 0
|
||||
for len(queueOperations) > 0 && currentTime.After(queueOperations[0].BlockTime) {
|
||||
// For now, queued operations cannot queue more operations.
|
||||
// If a need arises for us to support queued messages to queue more messages, this can
|
||||
// be changed.
|
||||
logUpdate, _, err := queueOperations[0].Op(r, app, ctx, accounts, event)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.FailNow()
|
||||
}
|
||||
queueOperations = queueOperations[1:]
|
||||
numOpsRan++
|
||||
}
|
||||
return numOpsRan
|
||||
}
|
||||
|
||||
func getKeys(validators map[string]mockValidator) []string {
|
||||
keys := make([]string, len(validators))
|
||||
i := 0
|
||||
for key := range validators {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// randomProposer picks a random proposer from the current validator set
|
||||
func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes {
|
||||
keys := getKeys(validators)
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
proposer := validators[key].val
|
||||
pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pk.Address()
|
||||
}
|
||||
|
||||
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
||||
// nolint: unparam
|
||||
func RandomRequestBeginBlock(r *rand.Rand, params Params, validators map[string]mockValidator,
|
||||
pastTimes []time.Time, pastVoteInfos [][]abci.VoteInfo, event func(string), header abci.Header) abci.RequestBeginBlock {
|
||||
if len(validators) == 0 {
|
||||
return abci.RequestBeginBlock{Header: header}
|
||||
}
|
||||
voteInfos := make([]abci.VoteInfo, len(validators))
|
||||
i := 0
|
||||
for _, key := range getKeys(validators) {
|
||||
mVal := validators[key]
|
||||
mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState)
|
||||
signed := true
|
||||
|
||||
if mVal.livenessState == 1 {
|
||||
// spotty connection, 50% probability of success
|
||||
// See https://github.com/golang/go/issues/23804#issuecomment-365370418
|
||||
// for reasoning behind computing like this
|
||||
signed = r.Int63()%2 == 0
|
||||
} else if mVal.livenessState == 2 {
|
||||
// offline
|
||||
signed = false
|
||||
}
|
||||
if signed {
|
||||
event("beginblock/signing/signed")
|
||||
} else {
|
||||
event("beginblock/signing/missed")
|
||||
}
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(mVal.val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
voteInfos[i] = abci.VoteInfo{
|
||||
Validator: abci.Validator{
|
||||
Address: pubkey.Address(),
|
||||
Power: mVal.val.Power,
|
||||
},
|
||||
SignedLastBlock: signed,
|
||||
}
|
||||
i++
|
||||
}
|
||||
// TODO: Determine capacity before allocation
|
||||
evidence := make([]abci.Evidence, 0)
|
||||
// Anything but the first block
|
||||
if len(pastTimes) > 0 {
|
||||
for r.Float64() < params.EvidenceFraction {
|
||||
height := header.Height
|
||||
time := header.Time
|
||||
vals := voteInfos
|
||||
if r.Float64() < params.PastEvidenceFraction {
|
||||
height = int64(r.Intn(int(header.Height) - 1))
|
||||
time = pastTimes[height]
|
||||
vals = pastVoteInfos[height]
|
||||
}
|
||||
validator := vals[r.Intn(len(vals))].Validator
|
||||
var totalVotingPower int64
|
||||
for _, val := range vals {
|
||||
totalVotingPower += val.Validator.Power
|
||||
}
|
||||
evidence = append(evidence, abci.Evidence{
|
||||
Type: tmtypes.ABCIEvidenceTypeDuplicateVote,
|
||||
Validator: validator,
|
||||
Height: height,
|
||||
Time: time,
|
||||
TotalVotingPower: totalVotingPower,
|
||||
})
|
||||
event("beginblock/evidence")
|
||||
}
|
||||
}
|
||||
return abci.RequestBeginBlock{
|
||||
Header: header,
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Votes: voteInfos,
|
||||
},
|
||||
ByzantineValidators: evidence,
|
||||
}
|
||||
}
|
||||
|
||||
// updateValidators mimicks Tendermint's update logic
|
||||
// nolint: unparam
|
||||
func updateValidators(tb testing.TB, r *rand.Rand, params Params, current map[string]mockValidator, updates []abci.ValidatorUpdate, event func(string)) map[string]mockValidator {
|
||||
|
||||
for _, update := range updates {
|
||||
str := fmt.Sprintf("%v", update.PubKey)
|
||||
switch {
|
||||
case update.Power == 0:
|
||||
if _, ok := current[str]; !ok {
|
||||
tb.Fatalf("tried to delete a nonexistent validator")
|
||||
}
|
||||
|
||||
event("endblock/validatorupdates/kicked")
|
||||
delete(current, str)
|
||||
default:
|
||||
// Does validator already exist?
|
||||
if mVal, ok := current[str]; ok {
|
||||
mVal.val = update
|
||||
event("endblock/validatorupdates/updated")
|
||||
} else {
|
||||
// Set this new validator
|
||||
current[str] = mockValidator{update, GetMemberOfInitialState(r, params.InitialLivenessWeightings)}
|
||||
event("endblock/validatorupdates/added")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// RandSetup performs the random setup the mock module needs.
|
||||
type RandSetup func(r *rand.Rand, accounts []Account)
|
||||
|
||||
// AppStateFn returns the app state json bytes
|
||||
type AppStateFn func(r *rand.Rand, accs []Account) json.RawMessage
|
||||
|
||||
// Simulate tests application by sending random messages.
|
||||
func Simulate(t *testing.T, app *baseapp.BaseApp,
|
||||
appStateFn AppStateFn, ops WeightedOperations, setups []RandSetup,
|
||||
invariants Invariants, numBlocks int, blockSize int, commit bool) error {
|
||||
|
||||
time := time.Now().UnixNano()
|
||||
return SimulateFromSeed(t, app, appStateFn, time, ops,
|
||||
setups, invariants, numBlocks, blockSize, commit)
|
||||
}
|
||||
|
||||
// initialize the chain for the simulation
|
||||
func initChain(r *rand.Rand, params Params, accounts []Account,
|
||||
setups []RandSetup, app *baseapp.BaseApp,
|
||||
appStateFn AppStateFn) mockValidators {
|
||||
|
||||
req := abci.RequestInitChain{
|
||||
AppStateBytes: appStateFn(r, accounts),
|
||||
}
|
||||
res := app.InitChain(req)
|
||||
validators := newMockValidators(r, res.Validators, params)
|
||||
|
||||
for i := 0; i < len(setups); i++ {
|
||||
setups[i](r, accounts)
|
||||
}
|
||||
return validators
|
||||
}
|
||||
|
||||
// SimulateFromSeed tests an application by running the provided
|
||||
// operations, testing the provided invariants, but using the provided seed.
|
||||
// TODO split this monster function up
|
||||
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
||||
appStateFn AppStateFn, seed int64, ops WeightedOperations,
|
||||
setups []RandSetup, invariants Invariants,
|
||||
numBlocks int, blockSize int, commit bool) (simError error) {
|
||||
|
||||
// in case we have to end early, don't os.Exit so that we can run cleanup code.
|
||||
stopEarly := false
|
||||
testingMode, t, b := getTestingMode(tb)
|
||||
fmt.Printf("Starting SimulateFromSeed with randomness "+
|
||||
"created with seed %d\n", int(seed))
|
||||
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
params := RandomParams(r) // := DefaultParams()
|
||||
fmt.Printf("Randomized simulation params: %+v\n", params)
|
||||
|
||||
timestamp := RandTimestamp(r)
|
||||
fmt.Printf("Starting the simulation from time %v, unixtime %v\n",
|
||||
timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||
|
||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||
accs := RandomAccounts(r, params.NumKeys)
|
||||
eventStats := newEventStats()
|
||||
|
||||
// Second variable to keep pending validator set (delayed one block since
|
||||
// TM 0.24) Initially this is the same as the initial validator set
|
||||
validators := initChain(r, params, accs, setups, app, appStateFn)
|
||||
nextValidators := validators
|
||||
|
||||
header := abci.Header{
|
||||
Height: 1,
|
||||
Time: timestamp,
|
||||
ProposerAddress: validators.randomProposer(r),
|
||||
}
|
||||
opCount := 0
|
||||
|
||||
// Setup code to catch SIGTERM's
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
receivedSignal := <-c
|
||||
fmt.Printf("\nExiting early due to %s, on block %d, operation %d\n",
|
||||
receivedSignal, header.Height, opCount)
|
||||
simError = fmt.Errorf("Exited due to %s", receivedSignal)
|
||||
stopEarly = true
|
||||
}()
|
||||
|
||||
var pastTimes []time.Time
|
||||
var pastVoteInfos [][]abci.VoteInfo
|
||||
|
||||
request := RandomRequestBeginBlock(r, params,
|
||||
validators, pastTimes, pastVoteInfos, eventStats.tally, header)
|
||||
|
||||
// These are operations which have been queued by previous operations
|
||||
operationQueue := newOperationQueue()
|
||||
timeOperationQueue := []FutureOperation{}
|
||||
var blockLogBuilders []*strings.Builder
|
||||
|
||||
if testingMode {
|
||||
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
||||
}
|
||||
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
||||
blockSimulator := createBlockSimulator(
|
||||
testingMode, tb, t, params, eventStats.tally, invariants,
|
||||
ops, operationQueue, timeOperationQueue,
|
||||
numBlocks, blockSize, displayLogs)
|
||||
|
||||
if !testingMode {
|
||||
b.ResetTimer()
|
||||
} else {
|
||||
// Recover logs in case of panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Panic with err\n", r)
|
||||
stackTrace := string(debug.Stack())
|
||||
fmt.Println(stackTrace)
|
||||
displayLogs()
|
||||
simError = fmt.Errorf(
|
||||
"Simulation halted due to panic on block %d",
|
||||
header.Height)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// TODO split up the contents of this for loop into new functions
|
||||
for i := 0; i < numBlocks && !stopEarly; i++ {
|
||||
|
||||
// Log the header time for future lookup
|
||||
pastTimes = append(pastTimes, header.Time)
|
||||
pastVoteInfos = append(pastVoteInfos, request.LastCommitInfo.Votes)
|
||||
|
||||
// Construct log writer
|
||||
logWriter := addLogMessage(testingMode, blockLogBuilders, i)
|
||||
|
||||
// Run the BeginBlock handler
|
||||
logWriter("BeginBlock")
|
||||
app.BeginBlock(request)
|
||||
|
||||
if testingMode {
|
||||
invariants.assertAll(t, app, "BeginBlock", displayLogs)
|
||||
}
|
||||
|
||||
ctx := app.NewContext(false, header)
|
||||
|
||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||
logWriter("Queued operations")
|
||||
numQueuedOpsRan := runQueuedOperations(
|
||||
operationQueue, int(header.Height),
|
||||
tb, r, app, ctx, accs, logWriter,
|
||||
displayLogs, eventStats.tally)
|
||||
|
||||
numQueuedTimeOpsRan := runQueuedTimeOperations(
|
||||
timeOperationQueue, header.Time,
|
||||
tb, r, app, ctx, accs,
|
||||
logWriter, displayLogs, eventStats.tally)
|
||||
|
||||
if testingMode && onOperation {
|
||||
invariants.assertAll(t, app, "QueuedOperations", displayLogs)
|
||||
}
|
||||
|
||||
logWriter("Standard operations")
|
||||
operations := blockSimulator(r, app, ctx, accs, header, logWriter)
|
||||
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
|
||||
if testingMode {
|
||||
invariants.assertAll(t, app, "StandardOperations", displayLogs)
|
||||
}
|
||||
|
||||
res := app.EndBlock(abci.RequestEndBlock{})
|
||||
header.Height++
|
||||
header.Time = header.Time.Add(
|
||||
time.Duration(minTimePerBlock) * time.Second)
|
||||
header.Time = header.Time.Add(
|
||||
time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||
header.ProposerAddress = validators.randomProposer(r)
|
||||
logWriter("EndBlock")
|
||||
|
||||
if testingMode {
|
||||
invariants.assertAll(t, app, "EndBlock", displayLogs)
|
||||
}
|
||||
if commit {
|
||||
app.Commit()
|
||||
}
|
||||
|
||||
if header.ProposerAddress == nil {
|
||||
fmt.Printf("\nSimulation stopped early as all validators " +
|
||||
"have been unbonded, there is nobody left propose a block!\n")
|
||||
stopEarly = true
|
||||
break
|
||||
}
|
||||
|
||||
// Generate a random RequestBeginBlock with the current validator set
|
||||
// for the next block
|
||||
request = RandomRequestBeginBlock(r, params, validators,
|
||||
pastTimes, pastVoteInfos, eventStats.tally, header)
|
||||
|
||||
// Update the validator set, which will be reflected in the application
|
||||
// on the next block
|
||||
validators = nextValidators
|
||||
nextValidators = updateValidators(tb, r, params,
|
||||
validators, res.ValidatorUpdates, eventStats.tally)
|
||||
}
|
||||
|
||||
if stopEarly {
|
||||
eventStats.Print()
|
||||
return simError
|
||||
}
|
||||
fmt.Printf("\nSimulation complete. Final height (blocks): %d, "+
|
||||
"final time (seconds), : %v, operations ran %d\n",
|
||||
header.Height, header.Time, opCount)
|
||||
|
||||
eventStats.Print()
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________________
|
||||
|
||||
type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, header abci.Header, logWriter func(string)) (opCount int)
|
||||
|
||||
// Returns a function to simulate blocks. Written like this to avoid constant
|
||||
// parameters being passed everytime, to minimize memory overhead.
|
||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params,
|
||||
event func(string), invariants Invariants, ops WeightedOperations,
|
||||
operationQueue OperationQueue, timeOperationQueue []FutureOperation,
|
||||
totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn {
|
||||
|
||||
var lastBlocksizeState = 0 // state for [4 * uniform distribution]
|
||||
var blocksize int
|
||||
selectOp := ops.getSelectOpFn()
|
||||
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
|
||||
|
||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ",
|
||||
header.Height, totalNumBlocks, opCount, blocksize)
|
||||
lastBlocksizeState, blocksize = getBlockSize(r, params, lastBlocksizeState, avgBlockSize)
|
||||
|
||||
for i := 0; i < blocksize; i++ {
|
||||
|
||||
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.Fatalf("error on operation %d within block %d, %v",
|
||||
header.Height, opCount, err)
|
||||
}
|
||||
|
||||
queueOperations(operationQueue, timeOperationQueue, futureOps)
|
||||
if testingMode {
|
||||
if onOperation {
|
||||
eventStr := fmt.Sprintf("operation: %v", logUpdate)
|
||||
invariants.assertAll(t, app, eventStr, displayLogs)
|
||||
}
|
||||
if opCount%50 == 0 {
|
||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ",
|
||||
header.Height, totalNumBlocks, opCount, blocksize)
|
||||
}
|
||||
}
|
||||
opCount++
|
||||
}
|
||||
return opCount
|
||||
}
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func runQueuedOperations(queueOps map[int][]Operation,
|
||||
height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp,
|
||||
ctx sdk.Context, accounts []Account, logWriter func(string),
|
||||
displayLogs func(), tallyEvent func(string)) (numOpsRan int) {
|
||||
|
||||
queuedOp, ok := queueOps[height]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
numOpsRan = len(queuedOp)
|
||||
for i := 0; i < numOpsRan; i++ {
|
||||
|
||||
// For now, queued operations cannot queue more operations.
|
||||
// If a need arises for us to support queued messages to queue more messages, this can
|
||||
// be changed.
|
||||
logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, tallyEvent)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
delete(queueOps, height)
|
||||
return numOpsRan
|
||||
}
|
||||
|
||||
func runQueuedTimeOperations(queueOps []FutureOperation,
|
||||
currentTime time.Time, tb testing.TB, r *rand.Rand,
|
||||
app *baseapp.BaseApp, ctx sdk.Context, accounts []Account,
|
||||
logWriter func(string), displayLogs func(), tallyEvent func(string)) (numOpsRan int) {
|
||||
|
||||
numOpsRan = 0
|
||||
for len(queueOps) > 0 && currentTime.After(queueOps[0].BlockTime) {
|
||||
|
||||
// For now, queued operations cannot queue more operations.
|
||||
// If a need arises for us to support queued messages to queue more messages, this can
|
||||
// be changed.
|
||||
logUpdate, _, err := queueOps[0].Op(r, app, ctx, accounts, tallyEvent)
|
||||
logWriter(logUpdate)
|
||||
if err != nil {
|
||||
displayLogs()
|
||||
tb.FailNow()
|
||||
}
|
||||
|
||||
queueOps = queueOps[1:]
|
||||
numOpsRan++
|
||||
}
|
||||
return numOpsRan
|
||||
}
|
|
@ -5,12 +5,11 @@ import (
|
|||
"math/rand"
|
||||
)
|
||||
|
||||
// TransitionMatrix is _almost_ a left stochastic matrix.
|
||||
// It is technically not one due to not normalizing the column values.
|
||||
// In the future, if we want to find the steady state distribution,
|
||||
// it will be quite easy to normalize these values to get a stochastic matrix.
|
||||
// Floats aren't currently used as the default due to non-determinism across
|
||||
// architectures
|
||||
// TransitionMatrix is _almost_ a left stochastic matrix. It is technically
|
||||
// not one due to not normalizing the column values. In the future, if we want
|
||||
// to find the steady state distribution, it will be quite easy to normalize
|
||||
// these values to get a stochastic matrix. Floats aren't currently used as
|
||||
// the default due to non-determinism across architectures
|
||||
type TransitionMatrix struct {
|
||||
weights [][]int
|
||||
// total in each column
|
||||
|
@ -24,7 +23,8 @@ func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) {
|
|||
n := len(weights)
|
||||
for i := 0; i < n; i++ {
|
||||
if len(weights[i]) != n {
|
||||
return TransitionMatrix{}, fmt.Errorf("Transition Matrix: Non-square matrix provided, error on row %d", i)
|
||||
return TransitionMatrix{},
|
||||
fmt.Errorf("Transition Matrix: Non-square matrix provided, error on row %d", i)
|
||||
}
|
||||
}
|
||||
totals := make([]int, n)
|
||||
|
@ -36,8 +36,8 @@ func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) {
|
|||
return TransitionMatrix{weights, totals, n}, nil
|
||||
}
|
||||
|
||||
// NextState returns the next state randomly chosen using r, and the weightings provided
|
||||
// in the transition matrix.
|
||||
// NextState returns the next state randomly chosen using r, and the weightings
|
||||
// provided in the transition matrix.
|
||||
func (t TransitionMatrix) NextState(r *rand.Rand, i int) int {
|
||||
randNum := r.Intn(t.totals[i])
|
||||
for row := 0; row < t.n; row++ {
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
type (
|
||||
// Operation runs a state machine transition,
|
||||
// and ensures the transition happened as expected.
|
||||
// The operation could be running and testing a fuzzed transaction,
|
||||
// or doing the same for a message.
|
||||
//
|
||||
// For ease of debugging,
|
||||
// an operation returns a descriptive message "action",
|
||||
// which details what this fuzzed state machine transition actually did.
|
||||
//
|
||||
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||
// These will be ran at the beginning of the corresponding block.
|
||||
Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accounts []Account, event func(string),
|
||||
) (action string, futureOperations []FutureOperation, err error)
|
||||
|
||||
// RandSetup performs the random setup the mock module needs.
|
||||
RandSetup func(r *rand.Rand, accounts []Account)
|
||||
|
||||
// An Invariant is a function which tests a particular invariant.
|
||||
// If the invariant has been broken, it should return an error
|
||||
// containing a descriptive message about what happened.
|
||||
// The simulator will then halt and print the logs.
|
||||
Invariant func(app *baseapp.BaseApp) error
|
||||
|
||||
// Account contains a privkey, pubkey, address tuple
|
||||
// eventually more useful data can be placed in here.
|
||||
// (e.g. number of coins)
|
||||
Account struct {
|
||||
PrivKey crypto.PrivKey
|
||||
PubKey crypto.PubKey
|
||||
Address sdk.AccAddress
|
||||
}
|
||||
|
||||
mockValidator struct {
|
||||
val abci.ValidatorUpdate
|
||||
livenessState int
|
||||
}
|
||||
|
||||
// FutureOperation is an operation which will be ran at the
|
||||
// beginning of the provided BlockHeight.
|
||||
// If both a BlockHeight and BlockTime are specified, it will use the BlockHeight.
|
||||
// In the (likely) event that multiple operations are queued at the same
|
||||
// block height, they will execute in a FIFO pattern.
|
||||
FutureOperation struct {
|
||||
BlockHeight int
|
||||
BlockTime time.Time
|
||||
Op Operation
|
||||
}
|
||||
|
||||
// WeightedOperation is an operation with associated weight.
|
||||
// This is used to bias the selection operation within the simulator.
|
||||
WeightedOperation struct {
|
||||
Weight int
|
||||
Op Operation
|
||||
}
|
||||
)
|
||||
|
||||
// TODO remove? not being called anywhere
|
||||
// PeriodicInvariant returns an Invariant function closure that asserts
|
||||
// a given invariant if the mock application's last block modulo the given
|
||||
// period is congruent to the given offset.
|
||||
func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
|
||||
return func(app *baseapp.BaseApp) error {
|
||||
if int(app.LastBlockHeight())%period == offset {
|
||||
return invariant(app)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (acc Account) Equals(acc2 Account) bool {
|
||||
return acc.Address.Equals(acc2.Address)
|
||||
}
|
|
@ -2,170 +2,121 @@ package simulation
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
)
|
||||
|
||||
// shamelessly copied from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326
|
||||
// TODO we should probably move this to tendermint/libs/common/random.go
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const (
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
// Generate a random string of a particular length
|
||||
func RandStringOfLength(r *rand.Rand, n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, r.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = r.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) {
|
||||
testingMode = false
|
||||
if _t, ok := tb.(*testing.T); ok {
|
||||
t = _t
|
||||
testingMode = true
|
||||
} else {
|
||||
b = tb.(*testing.B)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Pretty-print events as a table
|
||||
func DisplayEvents(events map[string]uint) {
|
||||
var keys []string
|
||||
for key := range events {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
fmt.Printf("Event statistics: \n")
|
||||
for _, key := range keys {
|
||||
fmt.Printf(" % 60s => %d\n", key, events[key])
|
||||
}
|
||||
}
|
||||
|
||||
// RandomAcc pick a random account from an array
|
||||
func RandomAcc(r *rand.Rand, accs []Account) Account {
|
||||
return accs[r.Intn(
|
||||
len(accs),
|
||||
)]
|
||||
}
|
||||
|
||||
// Generate a random amount
|
||||
func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
|
||||
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
|
||||
}
|
||||
|
||||
// RandomDecAmount generates a random decimal amount
|
||||
func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec {
|
||||
randInt := big.NewInt(0).Rand(r, max.Int)
|
||||
return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision)
|
||||
}
|
||||
|
||||
// RandomAccounts generates n random accounts
|
||||
func RandomAccounts(r *rand.Rand, n int) []Account {
|
||||
accs := make([]Account, n)
|
||||
for i := 0; i < n; i++ {
|
||||
// don't need that much entropy for simulation
|
||||
privkeySeed := make([]byte, 15)
|
||||
r.Read(privkeySeed)
|
||||
useSecp := r.Int63()%2 == 0
|
||||
if useSecp {
|
||||
accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed)
|
||||
} else {
|
||||
accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||
}
|
||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||
}
|
||||
return accs
|
||||
return
|
||||
}
|
||||
|
||||
// Builds a function to add logs for this particular block
|
||||
func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) {
|
||||
if testingmode {
|
||||
blockLogBuilders[height] = &strings.Builder{}
|
||||
return func(x string) {
|
||||
(*blockLogBuilders[height]).WriteString(x)
|
||||
(*blockLogBuilders[height]).WriteString("\n")
|
||||
}
|
||||
}
|
||||
return func(x string) {}
|
||||
}
|
||||
func addLogMessage(testingmode bool,
|
||||
blockLogBuilders []*strings.Builder, height int) func(string) {
|
||||
|
||||
// assertAllInvariants asserts a list of provided invariants against application state
|
||||
func assertAllInvariants(t *testing.T, app *baseapp.BaseApp,
|
||||
invariants []Invariant, where string, displayLogs func()) {
|
||||
|
||||
for i := 0; i < len(invariants); i++ {
|
||||
err := invariants[i](app)
|
||||
if err != nil {
|
||||
fmt.Printf("Invariants broken after %s\n", where)
|
||||
fmt.Println(err.Error())
|
||||
displayLogs()
|
||||
t.Fatal()
|
||||
}
|
||||
if !testingmode {
|
||||
return func(_ string) {}
|
||||
}
|
||||
}
|
||||
|
||||
// RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts
|
||||
func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) {
|
||||
addrs := make([]sdk.AccAddress, len(accs))
|
||||
for i := 0; i < len(accs); i++ {
|
||||
addrs[i] = accs[i].Address
|
||||
blockLogBuilders[height] = &strings.Builder{}
|
||||
return func(x string) {
|
||||
(*blockLogBuilders[height]).WriteString(x)
|
||||
(*blockLogBuilders[height]).WriteString("\n")
|
||||
}
|
||||
mock.RandomSetGenesis(r, app, addrs, denoms)
|
||||
}
|
||||
|
||||
// Creates a function to print out the logs
|
||||
func logPrinter(testingmode bool, logs []*strings.Builder) func() {
|
||||
if testingmode {
|
||||
return func() {
|
||||
numLoggers := 0
|
||||
for i := 0; i < len(logs); i++ {
|
||||
// We're passed the last created block
|
||||
if logs[i] == nil {
|
||||
numLoggers = i
|
||||
break
|
||||
}
|
||||
if !testingmode {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
return func() {
|
||||
numLoggers := 0
|
||||
for i := 0; i < len(logs); i++ {
|
||||
// We're passed the last created block
|
||||
if logs[i] == nil {
|
||||
numLoggers = i
|
||||
break
|
||||
}
|
||||
var f *os.File
|
||||
if numLoggers > 10 {
|
||||
fileName := fmt.Sprintf("simulation_log_%s.txt", time.Now().Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf("Too many logs to display, instead writing to %s\n", fileName)
|
||||
f, _ = os.Create(fileName)
|
||||
}
|
||||
|
||||
var f *os.File
|
||||
if numLoggers > 10 {
|
||||
fileName := fmt.Sprintf("simulation_log_%s.txt",
|
||||
time.Now().Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf("Too many logs to display, instead writing to %s\n",
|
||||
fileName)
|
||||
f, _ = os.Create(fileName)
|
||||
}
|
||||
|
||||
for i := 0; i < numLoggers; i++ {
|
||||
if f == nil {
|
||||
fmt.Printf("Begin block %d\n", i+1)
|
||||
fmt.Println((*logs[i]).String())
|
||||
continue
|
||||
}
|
||||
for i := 0; i < numLoggers; i++ {
|
||||
if f != nil {
|
||||
_, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i+1))
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
_, err = f.WriteString((*logs[i]).String())
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Begin block %d\n", i+1)
|
||||
fmt.Println((*logs[i]).String())
|
||||
}
|
||||
|
||||
_, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i+1))
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
|
||||
_, err = f.WriteString((*logs[i]).String())
|
||||
if err != nil {
|
||||
panic("Failed to write logs to file")
|
||||
}
|
||||
}
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
||||
// getBlockSize returns a block size as determined from the transition matrix.
|
||||
// It targets making average block size the provided parameter. The three
|
||||
// states it moves between are:
|
||||
// - "over stuffed" blocks with average size of 2 * avgblocksize,
|
||||
// - normal sized blocks, hitting avgBlocksize on average,
|
||||
// - and empty blocks, with no txs / only txs scheduled from the past.
|
||||
func getBlockSize(r *rand.Rand, params Params,
|
||||
lastBlockSizeState, avgBlockSize int) (state, blocksize int) {
|
||||
|
||||
// TODO: Make default blocksize transition matrix actually make the average
|
||||
// blocksize equal to avgBlockSize.
|
||||
state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState)
|
||||
switch state {
|
||||
case 0:
|
||||
blocksize = r.Intn(avgBlockSize * 4)
|
||||
case 1:
|
||||
blocksize = r.Intn(avgBlockSize * 2)
|
||||
default:
|
||||
blocksize = 0
|
||||
}
|
||||
return state, blocksize
|
||||
}
|
||||
|
||||
// PeriodicInvariant returns an Invariant function closure that asserts a given
|
||||
// invariant if the mock application's last block modulo the given period is
|
||||
// congruent to the given offset.
|
||||
//
|
||||
// NOTE this function is intended to be used manually used while running
|
||||
// computationally heavy simulations.
|
||||
// TODO reference this function in the codebase probably through use of a switch
|
||||
func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
|
||||
return func(app *baseapp.BaseApp) error {
|
||||
if int(app.LastBlockHeight())%period == offset {
|
||||
return invariant(app)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,17 @@ package slashing
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -93,8 +95,8 @@ func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper,
|
|||
func TestSlashingMsgs(t *testing.T) {
|
||||
mapp, stakeKeeper, keeper := getMockApp(t)
|
||||
|
||||
genCoin := sdk.NewInt64Coin("steak", 42)
|
||||
bondCoin := sdk.NewInt64Coin("steak", 10)
|
||||
genCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)
|
||||
bondCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)
|
||||
|
||||
acc1 := &auth.BaseAccount{
|
||||
Address: addr1,
|
||||
|
|
|
@ -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, ¶ms)
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()...)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// TODO remove dependencies on staking (should only refer to validator set type from sdk)
|
||||
|
@ -91,7 +92,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
|
||||
|
@ -120,7 +121,7 @@ func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt
|
|||
DelegatorAddr: sdk.AccAddress(address),
|
||||
ValidatorAddr: address,
|
||||
PubKey: pubKey,
|
||||
Delegation: sdk.NewCoin("steak", amt),
|
||||
Delegation: sdk.NewCoin(stakeTypes.DefaultBondDenom, amt),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,6 +129,6 @@ func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, delAmoun
|
|||
return stake.MsgDelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
Delegation: sdk.NewCoin("steak", delAmount),
|
||||
Delegation: sdk.NewCoin(stakeTypes.DefaultBondDenom, delAmount),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
||||
|
|
|
@ -3,13 +3,15 @@ package stake
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// getMockApp returns an initialized mock application for this module.
|
||||
|
@ -100,8 +102,8 @@ func checkDelegation(
|
|||
func TestStakeMsgs(t *testing.T) {
|
||||
mApp, keeper := getMockApp(t)
|
||||
|
||||
genCoin := sdk.NewInt64Coin("steak", 42)
|
||||
bondCoin := sdk.NewInt64Coin("steak", 10)
|
||||
genCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)
|
||||
bondCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)
|
||||
|
||||
acc1 := &auth.BaseAccount{
|
||||
Address: addr1,
|
||||
|
|
|
@ -2,6 +2,7 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
|
@ -284,22 +285,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "unbond",
|
||||
Short: "begin or complete unbonding shares from a validator",
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
client.PostCommands(
|
||||
GetCmdBeginUnbonding(storeName, cdc),
|
||||
)...)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdBeginUnbonding implements the begin unbonding validator command.
|
||||
func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "begin",
|
||||
Short: "begin unbonding",
|
||||
Short: "unbond shares from a validator",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -283,6 +283,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)
|
||||
|
|
|
@ -139,7 +139,7 @@ func TestUnbondingDelegation(t *testing.T) {
|
|||
ValidatorAddr: addrVals[0],
|
||||
CreationHeight: 0,
|
||||
MinTime: time.Unix(0, 0),
|
||||
Balance: sdk.NewInt64Coin("steak", 5),
|
||||
Balance: sdk.NewInt64Coin(types.DefaultBondDenom, 5),
|
||||
}
|
||||
|
||||
// set and retrieve a record
|
||||
|
@ -149,7 +149,7 @@ func TestUnbondingDelegation(t *testing.T) {
|
|||
require.True(t, ubd.Equal(resUnbond))
|
||||
|
||||
// modify a records, save, and retrieve
|
||||
ubd.Balance = sdk.NewInt64Coin("steak", 21)
|
||||
ubd.Balance = sdk.NewInt64Coin(types.DefaultBondDenom, 21)
|
||||
keeper.SetUnbondingDelegation(ctx, ubd)
|
||||
|
||||
resUnbonds := keeper.GetUnbondingDelegations(ctx, addrDels[0], 5)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(), ×lice)
|
||||
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)
|
||||
|
|
|
@ -189,7 +189,7 @@ func TestQueryDelegation(t *testing.T) {
|
|||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidatorByPowerIndex(ctx, val1, pool)
|
||||
|
||||
keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true)
|
||||
keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(20)), val1, true)
|
||||
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
@ -346,7 +346,7 @@ func TestQueryRedelegations(t *testing.T) {
|
|||
keeper.SetValidator(ctx, val1)
|
||||
keeper.SetValidator(ctx, val2)
|
||||
|
||||
keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(100)), val1, true)
|
||||
keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(100)), val1, true)
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), sdk.NewDec(20))
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
|
@ -48,7 +49,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper,
|
|||
loose := sdk.ZeroDec()
|
||||
bonded := sdk.ZeroDec()
|
||||
am.IterateAccounts(ctx, func(acc auth.Account) bool {
|
||||
loose = loose.Add(sdk.NewDecFromInt(acc.GetCoins().AmountOf("steak")))
|
||||
loose = loose.Add(sdk.NewDecFromInt(acc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom)))
|
||||
return false
|
||||
})
|
||||
k.IterateUnbondingDelegations(ctx, func(_ int64, ubd stake.UnbondingDelegation) bool {
|
||||
|
@ -70,19 +71,19 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper,
|
|||
feePool := d.GetFeePool(ctx)
|
||||
|
||||
// add outstanding fees
|
||||
loose = loose.Add(sdk.NewDecFromInt(f.GetCollectedFees(ctx).AmountOf("steak")))
|
||||
loose = loose.Add(sdk.NewDecFromInt(f.GetCollectedFees(ctx).AmountOf(stakeTypes.DefaultBondDenom)))
|
||||
|
||||
// add community pool
|
||||
loose = loose.Add(feePool.CommunityPool.AmountOf("steak"))
|
||||
loose = loose.Add(feePool.CommunityPool.AmountOf(stakeTypes.DefaultBondDenom))
|
||||
|
||||
// add validator distribution pool
|
||||
loose = loose.Add(feePool.ValPool.AmountOf("steak"))
|
||||
loose = loose.Add(feePool.ValPool.AmountOf(stakeTypes.DefaultBondDenom))
|
||||
|
||||
// add validator distribution commission and yet-to-be-withdrawn-by-delegators
|
||||
d.IterateValidatorDistInfos(ctx,
|
||||
func(_ int64, distInfo distribution.ValidatorDistInfo) (stop bool) {
|
||||
loose = loose.Add(distInfo.DelPool.AmountOf("steak"))
|
||||
loose = loose.Add(distInfo.ValCommission.AmountOf("steak"))
|
||||
loose = loose.Add(distInfo.DelPool.AmountOf(stakeTypes.DefaultBondDenom))
|
||||
loose = loose.Add(distInfo.ValCommission.AmountOf(stakeTypes.DefaultBondDenom))
|
||||
return false
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -28,7 +28,7 @@ var (
|
|||
|
||||
func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return types.NewMsgCreateValidator(
|
||||
address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commissionMsg,
|
||||
address, pubKey, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), Description{}, commissionMsg,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ func NewTestMsgCreateValidatorWithCommission(address sdk.ValAddress, pubKey cryp
|
|||
commission := NewCommissionMsg(commissionRate, sdk.OneDec(), sdk.ZeroDec())
|
||||
|
||||
return types.NewMsgCreateValidator(
|
||||
address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commission,
|
||||
address, pubKey, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), Description{}, commission,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int6
|
|||
return MsgDelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
Delegation: sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,6 @@ func NewTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.Val
|
|||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
PubKey: valPubKey,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
Delegation: sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
coinPos = sdk.NewInt64Coin("steak", 1000)
|
||||
coinZero = sdk.NewInt64Coin("steak", 0)
|
||||
coinNeg = sdk.NewInt64Coin("steak", -10000)
|
||||
coinPos = sdk.NewInt64Coin(DefaultBondDenom, 1000)
|
||||
coinZero = sdk.NewInt64Coin(DefaultBondDenom, 0)
|
||||
coinNeg = sdk.NewInt64Coin(DefaultBondDenom, -10000)
|
||||
)
|
||||
|
||||
// test ValidateBasic for MsgCreateValidator
|
||||
|
|
|
@ -19,6 +19,9 @@ const (
|
|||
// if this is 1, the validator set at the end of a block will sign the block after the next.
|
||||
// Constant as this should not change without a hard fork.
|
||||
ValidatorUpdateDelay int64 = 1
|
||||
|
||||
// Default bondable coin denomination
|
||||
DefaultBondDenom = "STAKE"
|
||||
)
|
||||
|
||||
// nolint - Keys for parameter access
|
||||
|
@ -59,7 +62,7 @@ func DefaultParams() Params {
|
|||
return Params{
|
||||
UnbondingTime: defaultUnbondingTime,
|
||||
MaxValidators: 100,
|
||||
BondDenom: "steak",
|
||||
BondDenom: DefaultBondDenom,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue