Merge branch 'develop' into release/v0.34.2

This commit is contained in:
Aleksandr Bezobchuk 2019-04-25 21:40:33 -04:00
commit e7ca82d808
No known key found for this signature in database
GPG Key ID: 7DAC30FBD99879B0
193 changed files with 2659 additions and 871 deletions

View File

@ -196,7 +196,8 @@ jobs:
command: |
export PATH="$GOBIN:$PATH"
export GO111MODULE=on
scripts/multisim.sh 500 50 TestFullGaiaSimulation
make runsim
runsim 500 50 TestFullGaiaSimulation
test_sim_gaia_multi_seed:
<<: *linux_defaults
@ -214,7 +215,8 @@ jobs:
command: |
export PATH="$GOBIN:$PATH"
export GO111MODULE=on
scripts/multisim.sh 50 10 TestFullGaiaSimulation
make runsim
runsim 50 10 TestFullGaiaSimulation
test_cover:
<<: *linux_defaults

2
.github/CODEOWNERS vendored
View File

@ -1,4 +1,4 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Primary repo maintainers
* @alessio @alexanderbez @cwgoes @jackzampolin
* @rigelrozanski @alexanderbez @jackzampolin @alessio @cwgoes

View File

@ -8,17 +8,25 @@ about: Create a report to help us squash bugs!
v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Please also ensure that this is not a duplicate issue :)
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
## Summary of Bug
<!-- Concisely describe the issue -->
## Summary of Bug
<!-- Concisely describe the issue -->
## Version
<!-- Output from `gaiad version --long` and `gaiacli version --long` -->
## Steps to Reproduce
<!-- What commands in order should someone run to reproduce your problem -->
<!-- What commands in order should someone run to reproduce your problem -->
____
#### For Admin Use
- [ ] Not duplicate issue
- [ ] Appropriate labels applied
- [ ] Appropriate contributors tagged
- [ ] Contributor assigned/self-assigned
- [ ] Not duplicate issue
- [ ] Appropriate labels applied
- [ ] Appropriate contributors tagged
- [ ] Contributor assigned/self-assigned

View File

@ -9,23 +9,28 @@ v ✰ Thanks for opening an issue! ✰
v Before smashing the submit button please review the template.
v Word of caution: poorly thought-out proposals may be rejected
v without deliberation
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
## Summary
<!-- Short, concise description of the proposed feature -->
<!-- Short, concise description of the proposed feature -->
## Problem Definition
<!-- Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does the SDK stand to gain by including this feature?
Are there any disadvantages of including this feature? -->
## Proposal
<!-- Detailed description of requirements of implementation -->
<!-- Detailed description of requirements of implementation -->
____
#### For Admin Use
- [ ] Not duplicate issue
- [ ] Appropriate labels applied
- [ ] Appropriate contributors tagged
- [ ] Contributor assigned/self-assigned
- [ ] Not duplicate issue
- [ ] Appropriate labels applied
- [ ] Appropriate contributors tagged
- [ ] Contributor assigned/self-assigned

View File

@ -0,0 +1,2 @@
#3715 query distr rewards returns per-validator
rewards along with rewards total amount.

View File

@ -0,0 +1,2 @@
#4142 Turn gaiacli tx send's --from into a required argument.
New shorter syntax: `gaiacli tx send FROM TO AMOUNT`

View File

@ -0,0 +1,3 @@
#3715 Update /distribution/delegators/{delegatorAddr}/rewards GET endpoint
as per new specs. For a given delegation, the endpoint now returns the
comprehensive list of validator-reward tuples along with the grand total.

View File

@ -0,0 +1 @@
#4049 update tag MsgWithdrawValidatorCommission to match type

View File

@ -0,0 +1 @@
#3775 unify sender transaction tag for ease of querying

View File

@ -0,0 +1 @@
#4113 Fix incorrect `$GOBIN` in `Install Go`

View File

@ -0,0 +1 @@
#3945 There's no check for chain-id in TxBuilder.SignStdTx

View File

@ -0,0 +1 @@
#3705 Return `[]` instead of `null` when querying delegator rewards.

View File

@ -0,0 +1,2 @@
#3966 fixed multiple assigns to action tags
#3793 add delegator tag for MsgCreateValidator and deleted unused moniker and identity tags

View File

@ -0,0 +1,2 @@
#3981 Add support to gracefully halt a node at a given height
via the node's `halt-height` config or CLI value.

View File

@ -0,0 +1 @@
#4042 Update docs and scripts to include the correct `GO111MODULE=on` environment variable.

View File

@ -0,0 +1 @@
#4066 Fix 'ExportGenesisFile() incorrectly overwrites genesis'

View File

@ -0,0 +1 @@
#4064 Remove `dep` and `vendor` from `doc` and `version`.

View File

@ -0,0 +1 @@
#4080 add missing invariants during simulations

View File

@ -0,0 +1 @@
#4068 Remove redundant account check on `gaiacli`

View File

@ -0,0 +1 @@
#2007 Return 200 status code on empty results

View File

@ -0,0 +1 @@
#4123 Fix typo, url error and outdated command description of doc clients.

View File

@ -0,0 +1 @@
#4129 Translate doc clients to chinese.

View File

@ -0,0 +1 @@
#3774 add category tag to transactions for ease of filtering

View File

@ -0,0 +1 @@
#3914 Implement invariant benchmarks and add target to makefile.

View File

@ -0,0 +1,2 @@
#3978 Return ErrUnknownRequest in message handlers for unknown
or invalid routed messages.

View File

@ -0,0 +1 @@
#4138 Upgrade tendermint to v0.31.5

View File

@ -18,7 +18,7 @@ contributors, the general procedure for contributing has been established:
make a comment on the issue to inform the community of your intentions
to begin work,
4. follow standard github best practices: fork the repo, branch from the
tip of `develop`, make some commits, and submit a PR to `develop`,
top of `develop`, make some commits, and submit a PR to `develop`,
5. include `WIP:` in the PR-title to and submit your PR early, even if it's
incomplete, this indicates to the community you're working on something and
allows them to provide comments early in the development process. When the code
@ -32,12 +32,11 @@ taken place in a github issue, that PR runs a high likelihood of being rejected.
Take a peek at our [coding repo](https://github.com/tendermint/coding) for
overall information on repository workflow and standards. Note, we use `make
get_dev_tools` and `make update_dev_tools` for installing the linting tools.
tools` for installing the linting tools.
Other notes:
- Looking for a good place to start contributing? How about checking out some
[good first
issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
[good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
- Please make sure to use `gofmt` before every commit - the easiest way to do
this is have your editor run it for you upon saving a file. Additionally
please ensure that your code is lint compliant by running `make lint`
@ -67,9 +66,9 @@ All PRs require two Reviews before merge (except docs changes, or variable name-
If you open a PR on the Cosmos SDK, it is mandatory to update the relevant documentation in /docs.
* If your change relates to the core SDK (baseapp, store, ...), please update the docs/gaia folder, the docs/examples folder and possibly the docs/spec folder.
* If your changes relate specifically to the gaia application (not including modules), please modify the docs/gaia folder.
* If your changes relate to a module, please update the module's spec in docs/spec. If the module is used by gaia, you might also need to modify docs/gaia and/or docs/examples.
* If your change relates to the core SDK (baseapp, store, ...), please update the docs/cosmos-hub folder and possibly the docs/spec folder.
* If your changes relate specifically to the gaia application (not including modules), please modify the docs/cosmos-hub folder.
* If your changes relate to a module, please update the module's spec in docs/spec. If the module is used by gaia, you might also need to modify docs/cosmos-hub.
* If your changes relate to the core of the CLI or Light-client (not specifically to module's CLI/Rest), please modify the docs/clients folder.
## Forking
@ -85,11 +84,11 @@ For instance, to create a fork and work on a branch of it, I would:
- Create the fork on github, using the fork button.
- Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmos/cosmos-sdk`)
- `git remote rename origin upstream`
- `git remote add origin git@github.com:ebuchman/cosmos-sdk.git`
- `git remote add origin git@github.com:rigeyrigerige/cosmos-sdk.git`
Now `origin` refers to my fork and `upstream` refers to the Cosmos-SDK version.
So I can `git push -u origin master` to update my fork, and make pull requests to Cosmos-SDK from there.
Of course, replace `ebuchman` with your git handle.
Of course, replace `rigeyrigerige` with your git handle.
To pull in updates from the origin repo, run
@ -132,7 +131,7 @@ The idea is you should be able to see the
error message and figure out exactly what failed.
Here is an example check:
```
```go
<some table>
for tcIndex, tc := range cases {
<some code>
@ -140,7 +139,7 @@ for tcIndex, tc := range cases {
<some code>
require.Equal(t, expectedTx[:32], calculatedTx[:32],
"First 32 bytes of the txs differed. tc #%d, i #%d", tcIndex, i)
```
```
## Branching Model and Release

View File

@ -1,8 +1,9 @@
#!/usr/bin/make -f
PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation')
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
COMMIT := $(shell git log -1 --format='%H')
CAT := $(if $(filter $(OS),Windows_NT),type,cat)
LEDGER_ENABLED ?= true
GOBIN ?= $(GOPATH)/bin
GOSUM := $(shell which gosum)
@ -48,7 +49,7 @@ ldflags = -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags)"
ifneq ($(GOSUM),)
ldflags += -X github.com/cosmos/cosmos-sdk/version.VendorDirHash=$(shell $(GOSUM) go.sum)
ldflags += -X github.com/cosmos/cosmos-sdk/version.GoSumHash=$(shell $(GOSUM) go.sum)
endif
ifeq ($(WITH_CLEVELDB),yes)
@ -62,7 +63,7 @@ BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
all: tools install lint test
# The below include contains the tools target.
include scripts/Makefile
include contrib/devtools/Makefile
########################################
### CI
@ -121,8 +122,6 @@ draw_deps: tools
clean:
rm -rf snapcraft-local.yaml build/
distclean: clean
rm -rf vendor/
########################################
### Documentation
@ -166,22 +165,33 @@ test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test -mod=readonly ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
test_sim_gaia_import_export:
test_sim_gaia_import_export: runsim
@echo "Running Gaia import/export simulation. This may take several minutes..."
@bash scripts/multisim.sh 50 5 TestGaiaImportExport
$(GOBIN)/runsim 50 5 TestGaiaImportExport
test_sim_gaia_simulation_after_import:
test_sim_gaia_simulation_after_import: runsim
@echo "Running Gaia simulation-after-import. This may take several minutes..."
@bash scripts/multisim.sh 50 5 TestGaiaSimulationAfterImport
$(GOBIN)/runsim 50 5 TestGaiaSimulationAfterImport
test_sim_gaia_custom_genesis_multi_seed:
test_sim_gaia_custom_genesis_multi_seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation ${HOME}/.gaiad/config/genesis.json
$(GOBIN)/runsim -g ${HOME}/.gaiad/config/genesis.json 400 5 TestFullGaiaSimulation
test_sim_gaia_multi_seed:
test_sim_gaia_multi_seed: runsim
@echo "Running multi-seed Gaia simulation. This may take awhile!"
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation
$(GOBIN)/runsim 400 5 TestFullGaiaSimulation
test_sim_benchmark_invariants:
@echo "Running simulation invariant benchmarks..."
@go test -mod=readonly ./cmd/gaia/app -benchmem -bench=BenchmarkInvariants -run=^$ \
-SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationBlockSize=200 \
-SimulationCommit=true -SimulationSeed=57 -v -timeout 24h
# Don't move it into tools - this will be gone once gaia has moved into the new repo
runsim: $(GOBIN)/runsim
$(GOBIN)/runsim: cmd/gaia/contrib/runsim/main.go
go install github.com/cosmos/cosmos-sdk/cmd/gaia/contrib/runsim
SIM_NUM_BLOCKS ?= 500
SIM_BLOCK_SIZE ?= 200
@ -264,11 +274,11 @@ snapcraft-local.yaml: snapcraft-local.yaml.in
# To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: install install_debug dist clean distclean \
.PHONY: install install_debug dist clean \
draw_deps test test_cli test_unit \
test_cover 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_custom_genesis_fast test_sim_gaia_custom_genesis_multi_seed \
test_sim_gaia_multi_seed test_sim_gaia_import_export \
test_sim_gaia_multi_seed test_sim_gaia_import_export test_sim_benchmark_invariants \
go-mod-cache

View File

@ -3,6 +3,7 @@ package baseapp
import (
"fmt"
"io"
"os"
"reflect"
"runtime/debug"
"strings"
@ -81,6 +82,9 @@ type BaseApp struct {
// flag for sealing options and parameters to a BaseApp
sealed bool
// height at which to halt the chain and gracefully shutdown
haltHeight uint64
}
var _ abci.Application = (*BaseApp)(nil)
@ -230,6 +234,10 @@ func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) {
app.minGasPrices = gasPrices
}
func (app *BaseApp) setHaltHeight(height uint64) {
app.haltHeight = height
}
// Router returns the router of the BaseApp.
func (app *BaseApp) Router() Router {
if app.sealed {
@ -885,7 +893,13 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc
return
}
// Commit implements the ABCI interface.
// Commit implements the ABCI interface. It will commit all state that exists in
// the deliver state's multi-store and includes the resulting commit ID in the
// returned abci.ResponseCommit. Commit will set the check state based on the
// latest header and reset the deliver state. Also, if a non-zero halt height is
// defined in config, Commit will execute a deferred function call to check
// against that height and gracefully halt if it matches the latest committed
// height.
func (app *BaseApp) Commit() (res abci.ResponseCommit) {
header := app.deliverState.ctx.BlockHeader()
@ -896,13 +910,20 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {
// Reset the Check state to the latest committed.
//
// NOTE: safe because Tendermint holds a lock on the mempool for Commit.
// Use the header from this latest block.
// NOTE: This is safe because Tendermint holds a lock on the mempool for
// Commit. Use the header from this latest block.
app.setCheckState(header)
// empty/reset the deliver state
app.deliverState = nil
defer func() {
if app.haltHeight > 0 && uint64(header.Height) == app.haltHeight {
app.logger.Info("halting node per configuration", "height", app.haltHeight)
os.Exit(0)
}
}()
return abci.ResponseCommit{
Data: commitID.Hash,
}

View File

@ -28,6 +28,11 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) {
return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) }
}
// SetHaltHeight returns a BaseApp option function that sets the halt height.
func SetHaltHeight(height uint64) func(*BaseApp) {
return func(bap *BaseApp) { bap.setHaltHeight(height) }
}
func (app *BaseApp) SetName(name string) {
if app.sealed {
panic("SetName() on sealed BaseApp")

View File

@ -16,6 +16,9 @@ import (
const (
flagGet = "get"
// DefaultKeyPass contains the default key password for genesis transactions
DefaultKeyPass = "12345678"
)
var configDefaults = map[string]string{

View File

@ -1,14 +1,15 @@
package client
import (
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/cli"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/cli"
)
// For https://github.com/cosmos/cosmos-sdk/issues/3899

View File

@ -58,9 +58,10 @@ type CLIContext struct {
SkipConfirm bool
}
// NewCLIContext returns a new initialized CLIContext with parameters from the
// command line using Viper.
func NewCLIContext() CLIContext {
// NewCLIContextWithFrom returns a new initialized CLIContext with parameters from the
// command line using Viper. It takes a key name or address and populates the FromName and
// FromAddress field accordingly.
func NewCLIContextWithFrom(from string) CLIContext {
var rpc rpcclient.Client
nodeURI := viper.GetString(client.FlagNode)
@ -68,7 +69,6 @@ func NewCLIContext() CLIContext {
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
}
from := viper.GetString(client.FlagFrom)
genOnly := viper.GetBool(client.FlagGenerateOnly)
fromAddress, fromName, err := GetFromFields(from, genOnly)
if err != nil {
@ -104,6 +104,10 @@ func NewCLIContext() CLIContext {
}
}
// NewCLIContext returns a new initialized CLIContext with parameters from the
// command line using Viper.
func NewCLIContext() CLIContext { return NewCLIContextWithFrom(viper.GetString(client.FlagFrom)) }
func createVerifier() tmlite.Verifier {
trustNodeDefined := viper.IsSet(client.FlagTrustNode)
if !trustNodeDefined {

View File

@ -7,7 +7,6 @@ import (
"sort"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -102,7 +101,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
// we throw this away, so don't enforce args,
// we want to get a new random seed phrase quickly
kb = keys.NewInMemory()
encryptPassword = app.DefaultKeyPass
encryptPassword = client.DefaultKeyPass
} else {
kb, err = NewKeyBaseFromHomeFlag()
if err != nil {

View File

@ -7,11 +7,12 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/tests"
)
func Test_runDeleteCmd(t *testing.T) {

View File

@ -1,8 +1,9 @@
package keys
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
)
func listKeysCmd() *cobra.Command {

View File

@ -3,9 +3,10 @@ package keys
import (
"testing"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/stretchr/testify/assert"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"

View File

@ -3,6 +3,7 @@ package keys
import (
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto"

View File

@ -7,10 +7,11 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/stretchr/testify/assert"
)

View File

@ -3,6 +3,7 @@ package lcd
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"os"
@ -18,7 +19,6 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -28,6 +28,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank"
dclcommon "github.com/cosmos/cosmos-sdk/x/distribution/client/common"
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
@ -38,7 +39,7 @@ const (
name2 = "test2"
name3 = "test3"
memo = "LCD test tx"
pw = app.DefaultKeyPass
pw = client.DefaultKeyPass
altPw = "12345678901"
)
@ -115,7 +116,7 @@ func TestCoinSend(t *testing.T) {
// query empty
res, body := Request(t, port, "GET", fmt.Sprintf("/auth/accounts/%s", someFakeAddr), nil)
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
require.Equal(t, http.StatusOK, res.StatusCode, body)
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
@ -337,7 +338,7 @@ func TestTxs(t *testing.T) {
txs = getTransactions(t, port, fmt.Sprintf("sender=%s", addr.String()))
require.Equal(t, emptyTxs, txs)
txs = getTransactions(t, port, fmt.Sprintf("action=submit%%20proposal&proposer=%s", addr.String()))
txs = getTransactions(t, port, fmt.Sprintf("action=submit%%20proposal&sender=%s", addr.String()))
require.Equal(t, emptyTxs, txs)
// create tx
@ -456,7 +457,7 @@ func TestBonding(t *testing.T) {
// query tx
txs := getTransactions(t, port,
fmt.Sprintf("action=delegate&delegator=%s", addr),
fmt.Sprintf("action=delegate&sender=%s", addr),
fmt.Sprintf("destination-validator=%s", operAddrs[0]),
)
require.Len(t, txs, 1)
@ -509,7 +510,7 @@ func TestBonding(t *testing.T) {
// query tx
txs = getTransactions(t, port,
fmt.Sprintf("action=begin_unbonding&delegator=%s", addr),
fmt.Sprintf("action=begin_unbonding&sender=%s", addr),
fmt.Sprintf("source-validator=%s", operAddrs[0]),
)
require.Len(t, txs, 1)
@ -546,7 +547,7 @@ func TestBonding(t *testing.T) {
// query tx
txs = getTransactions(t, port,
fmt.Sprintf("action=begin_redelegate&delegator=%s", addr),
fmt.Sprintf("action=begin_redelegate&sender=%s", addr),
fmt.Sprintf("source-validator=%s", operAddrs[0]),
fmt.Sprintf("destination-validator=%s", operAddrs[1]),
)
@ -674,7 +675,7 @@ func TestDeposit(t *testing.T) {
require.Equal(t, expectedBalance.Amount.Sub(depositTokens), acc.GetCoins().AmountOf(sdk.DefaultBondDenom))
// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=deposit&depositor=%s", addr))
txs := getTransactions(t, port, fmt.Sprintf("action=deposit&sender=%s", addr))
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
@ -735,7 +736,7 @@ func TestVote(t *testing.T) {
expectedBalance = coins[0]
// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=vote&voter=%s", addr))
txs := getTransactions(t, port, fmt.Sprintf("action=vote&sender=%s", addr))
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
@ -1004,9 +1005,10 @@ func TestDistributionFlow(t *testing.T) {
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
// Query delegator's rewards total
var delRewards disttypes.QueryDelegatorTotalRewardsResponse
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards", operAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.NoError(t, json.Unmarshal([]byte(body), &delRewards))
// Query delegator's withdrawal address
var withdrawAddr string
@ -1045,3 +1047,26 @@ func TestMintingQueries(t *testing.T) {
var annualProvisions sdk.Dec
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &annualProvisions))
}
func TestAccountBalanceQuery(t *testing.T) {
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
require.NoError(t, err)
addr, _ := CreateAddr(t, name1, pw, kb)
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
defer cleanup()
bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
require.NoError(t, err)
someFakeAddr := sdk.AccAddress(bz)
// empty account
res, body := Request(t, port, "GET", fmt.Sprintf("/auth/accounts/%s", someFakeAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Contains(t, body, `"type":"auth/Account"`)
// empty account balance
res, body = Request(t, port, "GET", fmt.Sprintf("/bank/balances/%s", someFakeAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Contains(t, body, "[]")
}

View File

@ -236,7 +236,7 @@ paths:
- in: query
name: tag
type: string
description: "transaction tags such as 'action=submit-proposal' and 'proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'"
description: "transaction tags such as 'action=submit-proposal' and 'sender=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&sender=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'"
required: true
x-example: 'TODO'
- in: query
@ -1486,9 +1486,7 @@ paths:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/Coin"
$ref: "#/definitions/DelegatorTotalRewards"
400:
description: Invalid delegator address
500:
@ -2112,6 +2110,26 @@ definitions:
$ref: "#/definitions/BlockID"
block:
$ref: "#/definitions/Block"
DelegationDelegatorReward:
type: object
properties:
validator_address:
$ref: "#/definitions/ValidatorAddress"
reward:
type: array
items:
$ref: "#/definitions/Coin"
DelegatorTotalRewards:
type: object
properties:
rewards:
type: array
items:
$ref: "#/definitions/DelegationDelegatorReward"
total:
type: array
items:
$ref: "#/definitions/Coin"
BaseReq:
type: object
properties:

View File

@ -695,7 +695,7 @@ func doTransferWithGas(
kb := crkeys.NewInMemory()
receiveInfo, _, err := kb.CreateMnemonic(
"receive_address", crkeys.English, gapp.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
"receive_address", crkeys.English, client.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
)
require.Nil(t, err)
@ -742,7 +742,7 @@ func doTransferWithGasAccAuto(
acc := getAccount(t, port, addr)
receiveInfo, _, err := kb.CreateMnemonic(
"receive_address", crkeys.English, gapp.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
"receive_address", crkeys.English, client.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
)
require.Nil(t, err)

View File

@ -6,11 +6,12 @@ import (
"strings"
"time"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
// SearchTxs performs a search for transactions for a given set of tags via

154
cmd/gaia/Makefile Normal file
View File

@ -0,0 +1,154 @@
#!/usr/bin/make -f
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
COMMIT := $(shell git log -1 --format='%H')
LEDGER_ENABLED ?= true
GOBIN ?= $(GOPATH)/bin
GOSUM := $(shell which gosum)
export GO111MODULE = on
# process build tags
build_tags = netgo
ifeq ($(LEDGER_ENABLED),true)
ifeq ($(OS),Windows_NT)
GCCEXE = $(shell where gcc.exe 2> NUL)
ifeq ($(GCCEXE),)
$(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
else
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S),OpenBSD)
$(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988))
else
GCC = $(shell command -v gcc 2> /dev/null)
ifeq ($(GCC),)
$(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
endif
endif
endif
ifeq ($(WITH_CLEVELDB),yes)
build_tags += gcc
endif
build_tags += $(BUILD_TAGS)
build_tags := $(strip $(build_tags))
# process linker flags
ldflags = -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags)"
ifneq ($(GOSUM),)
ldflags += -X github.com/cosmos/cosmos-sdk/version.GoSumHash=$(shell $(GOSUM) ../../go.sum)
endif
ifeq ($(WITH_CLEVELDB),yes)
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
endif
ldflags += $(LDFLAGS)
ldflags := $(strip $(ldflags))
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
# The below include contains the tools target.
include ../../contrib/devtools/Makefile
all: install lint check
build: ../../go.sum
ifeq ($(OS),Windows_NT)
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad.exe ../../cmd/gaia/cmd/gaiad
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli.exe ../../cmd/gaia/cmd/gaiacli
else
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad ../../cmd/gaia/cmd/gaiad
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli ../../cmd/gaia/cmd/gaiacli
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiareplay ../../cmd/gaia/cmd/gaiareplay
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiakeyutil ../../cmd/gaia/cmd/gaiakeyutil
endif
build-linux: ../../go.sum
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
install: ../../go.sum check-ledger
go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiad
go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiacli
go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiareplay
go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiakeyutil
install-debug: ../../go.sum
go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiadebug
########################################
### Tools & dependencies
go-mod-cache: go.sum
@echo "--> Download go modules to local cache"
@go mod download
go.sum: go.mod
@echo "--> Ensure dependencies have not been modified"
@go mod verify
draw-deps:
@# requires brew install graphviz or apt-get install graphviz
go get github.com/RobotsAndPencils/goviz
@goviz -i ./cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png
clean:
rm -rf snapcraft-local.yaml build/
distclean: clean
rm -rf vendor/
########################################
### Testing
check: check-unit
check-unit:
@VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' ./...
check-race:
@VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' -race ./...
check-cover:
@go test -mod=readonly -timeout 30m -race -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' ./...
check-build: build
@go test -mod=readonly -p 4 `go list ./cli_test/...` -tags=cli_test
check-all: check-unit check-race check-cover check-build
lint: ci-lint
ci-lint:
golangci-lint run
go vet -composites=false -tests=false ./...
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
go mod verify
format:
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofmt -w -s
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk
benchmark:
@go test -mod=readonly -bench=. ./...
# include simulations
include sims.mk
.PHONY: all build-linux install install-debug \
go-mod-cache draw-deps clean \
check check-all check-build check-cover check-ledger check-unit check-race

View File

@ -27,8 +27,6 @@ import (
const (
appName = "GaiaApp"
// DefaultKeyPass contains the default key password for genesis transactions
DefaultKeyPass = "12345678"
)
// default home directories for expected binaries

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"math/rand"
"os"
@ -61,11 +62,11 @@ func init() {
}
// helper function for populating input for SimulateFromSeed
func getSimulateFromSeedInput(tb testing.TB, app *GaiaApp) (
testing.TB, *baseapp.BaseApp, simulation.AppStateFn, int64,
func getSimulateFromSeedInput(tb testing.TB, w io.Writer, app *GaiaApp) (
testing.TB, io.Writer, *baseapp.BaseApp, simulation.AppStateFn, int64,
simulation.WeightedOperations, sdk.Invariants, int, int, bool, bool) {
return tb, app.BaseApp, appStateFn, seed,
return tb, w, app.BaseApp, appStateFn, seed,
testAndRunTxs(app), invariants(app), numBlocks, blockSize, commit, lean
}
@ -119,7 +120,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
if int64(i) > numInitiallyBonded && r.Intn(100) < 50 {
var (
vacc auth.VestingAccount
endTime int
endTime int64
)
startTime := genesisTimestamp.Unix()
@ -127,15 +128,19 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
// Allow for some vesting accounts to vest very quickly while others very
// slowly.
if r.Intn(100) < 50 {
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*24*30)))
endTime = int64(simulation.RandIntBetween(r, int(startTime), int(startTime+(60*60*24*30))))
} else {
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*12)))
endTime = int64(simulation.RandIntBetween(r, int(startTime), int(startTime+(60*60*12))))
}
if startTime == endTime {
endTime += 1
}
if r.Intn(100) < 50 {
vacc = auth.NewContinuousVestingAccount(&bacc, startTime, int64(endTime))
vacc = auth.NewContinuousVestingAccount(&bacc, startTime, endTime)
} else {
vacc = auth.NewDelayedVestingAccount(&bacc, int64(endTime))
vacc = auth.NewDelayedVestingAccount(&bacc, endTime)
}
gacc = NewGenesisAccountI(vacc)
@ -148,11 +153,11 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
authGenesis := auth.GenesisState{
Params: auth.Params{
MaxMemoCharacters: uint64(randIntBetween(r, 100, 200)),
MaxMemoCharacters: uint64(simulation.RandIntBetween(r, 100, 200)),
TxSigLimit: uint64(r.Intn(7) + 1),
TxSizeCostPerByte: uint64(randIntBetween(r, 5, 15)),
SigVerifyCostED25519: uint64(randIntBetween(r, 500, 1000)),
SigVerifyCostSecp256k1: uint64(randIntBetween(r, 500, 1000)),
TxSizeCostPerByte: uint64(simulation.RandIntBetween(r, 5, 15)),
SigVerifyCostED25519: uint64(simulation.RandIntBetween(r, 500, 1000)),
SigVerifyCostSecp256k1: uint64(simulation.RandIntBetween(r, 500, 1000)),
},
}
fmt.Printf("Selected randomly generated auth parameters:\n\t%+v\n", authGenesis)
@ -182,7 +187,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
stakingGenesis := staking.GenesisState{
Pool: staking.InitialPool(),
Params: staking.Params{
UnbondingTime: time.Duration(randIntBetween(r, 60, 60*60*24*3*2)) * time.Second,
UnbondingTime: time.Duration(simulation.RandIntBetween(r, 60, 60*60*24*3*2)) * time.Second,
MaxValidators: uint16(r.Intn(250) + 1),
BondDenom: sdk.DefaultBondDenom,
},
@ -192,9 +197,9 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
slashingGenesis := slashing.GenesisState{
Params: slashing.Params{
MaxEvidenceAge: stakingGenesis.Params.UnbondingTime,
SignedBlocksWindow: int64(randIntBetween(r, 10, 1000)),
SignedBlocksWindow: int64(simulation.RandIntBetween(r, 10, 1000)),
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
DowntimeJailDuration: time.Duration(randIntBetween(r, 60, 60*60*24)) * time.Second,
DowntimeJailDuration: time.Duration(simulation.RandIntBetween(r, 60, 60*60*24)) * time.Second,
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
},
@ -269,10 +274,6 @@ func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.T
return appStateRandomizedFn(r, accs, genesisTimestamp)
}
func randIntBetween(r *rand.Rand, min, max int) int {
return r.Intn(max-min) + min
}
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
@ -293,12 +294,7 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
}
func invariants(app *GaiaApp) []sdk.Invariant {
return []sdk.Invariant{
simulation.PeriodicInvariant(bank.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(distr.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(staking.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
app.distrKeeper, app.accountKeeper), period, 0),
}
return simulation.PeriodicInvariants(app.crisisKeeper.Invariants(), period, 0)
}
// Pass this in as an option to use a dbStoreAdapter instead of an IAVLStore for simulation speed.
@ -323,7 +319,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, app))
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, os.Stdout, app))
if err != nil {
fmt.Println(err)
b.Fail()
@ -358,7 +354,7 @@ func TestFullGaiaSimulation(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, os.Stdout, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
@ -392,7 +388,7 @@ func TestGaiaImportExport(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, os.Stdout, app))
if commit {
// for memdb:
@ -482,7 +478,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, os.Stdout, app))
if commit {
// for memdb:
@ -521,7 +517,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
})
// Run randomized simulation on imported app
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, newApp))
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, os.Stdout, newApp))
require.Nil(t, err)
}
@ -546,7 +542,7 @@ func TestAppStateDeterminism(t *testing.T) {
// Run randomized simulation
simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
t, os.Stdout, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]sdk.Invariant{},
50,
@ -562,3 +558,42 @@ func TestAppStateDeterminism(t *testing.T) {
}
}
}
func BenchmarkInvariants(b *testing.B) {
// 1. Setup a simulated Gaia application
logger := log.NewNopLogger()
dir, _ := ioutil.TempDir("", "goleveldb-gaia-invariant-bench")
db, _ := sdk.NewLevelDB("simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, 0)
// 2. Run parameterized simulation (w/o invariants)
_, err := simulation.SimulateFromSeed(
b, ioutil.Discard, app.BaseApp, appStateFn, seed, testAndRunTxs(app),
[]sdk.Invariant{}, numBlocks, blockSize, commit, lean,
)
if err != nil {
fmt.Println(err)
b.FailNow()
}
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight() + 1})
// 3. Benchmark each invariant separately
//
// NOTE: We use the crisis keeper as it has all the invariants registered with
// their respective metadata which makes it useful for testing/benchmarking.
for _, cr := range app.crisisKeeper.Routes() {
b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) {
if err := cr.Invar(ctx); err != nil {
fmt.Println(err)
b.FailNow()
}
})
}
}

View File

@ -15,6 +15,7 @@ import (
"time"
"github.com/tendermint/tendermint/crypto/ed25519"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/stretchr/testify/require"
@ -223,6 +224,17 @@ func TestGaiaCLISend(t *testing.T) {
success, _, _ := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--dry-run")
require.True(t, success)
// Test --generate-only
success, stdout, stderr := f.TxSend(
fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only=true",
)
require.Empty(t, stderr)
require.True(t, success)
msg := unmarshalStdTx(f.T, stdout)
require.NotZero(t, msg.Fee.Gas)
require.Len(t, msg.Msgs, 1)
require.Len(t, msg.GetSignatures(), 0)
// Check state didn't change
fooAcc = f.QueryAccount(fooAddr)
require.Equal(t, startTokens.Sub(sendTokens), fooAcc.GetCoins().AmountOf(denom))
@ -415,6 +427,33 @@ func TestGaiaCLICreateValidator(t *testing.T) {
f.Cleanup()
}
func TestGaiaCLIQueryRewards(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
genesisState := f.GenesisState()
inflationMin := sdk.MustNewDecFromStr("10000.0")
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMin = inflationMin
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
genFile := filepath.Join(f.GaiadHome, "config", "genesis.json")
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
require.NoError(t, err)
cdc := app.MakeCodec()
genDoc.AppState, err = cdc.MarshalJSON(genesisState)
require.NoError(t, genDoc.SaveAs(genFile))
// start gaiad server
proc := f.GDStart()
defer proc.Stop(false)
fooAddr := f.KeyAddress(keyFoo)
rewards := f.QueryRewards(fooAddr)
require.Equal(t, 1, len(rewards.Rewards))
f.Cleanup()
}
func TestGaiaCLISubmitProposal(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
@ -456,7 +495,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
tests.WaitForNextNBlocksTM(1, f.Port)
// Ensure transaction tags can be queried
txs := f.QueryTxs(1, 50, "action:submit_proposal", fmt.Sprintf("proposer:%s", fooAddr))
txs := f.QueryTxs(1, 50, "action:submit_proposal", fmt.Sprintf("sender:%s", fooAddr))
require.Len(t, txs, 1)
// Ensure deposit was deducted
@ -500,7 +539,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, proposalTokens.Add(depositTokens), deposit.Amount.AmountOf(denom))
// Ensure tags are set on the transaction
txs = f.QueryTxs(1, 50, "action:deposit", fmt.Sprintf("depositor:%s", fooAddr))
txs = f.QueryTxs(1, 50, "action:deposit", fmt.Sprintf("sender:%s", fooAddr))
require.Len(t, txs, 1)
// Ensure account has expected amount of funds
@ -537,7 +576,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, gov.OptionYes, votes[0].Option)
// Ensure tags are applied to voting transaction properly
txs = f.QueryTxs(1, 50, "action:vote", fmt.Sprintf("voter:%s", fooAddr))
txs = f.QueryTxs(1, 50, "action:vote", fmt.Sprintf("sender:%s", fooAddr))
require.Len(t, txs, 1)
// Ensure no proposals in deposit period
@ -975,7 +1014,7 @@ func TestGaiaCLIConfig(t *testing.T) {
f.CLIConfig("trace", "false")
f.CLIConfig("indent", "true")
config, err := ioutil.ReadFile(path.Join(f.GCLIHome, "config", "config.toml"))
config, err := ioutil.ReadFile(path.Join(f.GaiacliHome, "config", "config.toml"))
require.NoError(t, err)
expectedConfig := fmt.Sprintf(`broadcast-mode = "block"
chain-id = "%s"
@ -992,6 +1031,7 @@ trust-node = true
func TestGaiadCollectGentxs(t *testing.T) {
t.Parallel()
var customMaxBytes, customMaxGas int64 = 99999999, 1234567
f := NewFixtures(t)
// Initialise temporary directories
@ -1011,6 +1051,15 @@ func TestGaiadCollectGentxs(t *testing.T) {
// Run init
f.GDInit(keyFoo)
// Customise genesis.json
genFile := f.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
require.NoError(t, err)
genDoc.ConsensusParams.Block.MaxBytes = customMaxBytes
genDoc.ConsensusParams.Block.MaxGas = customMaxGas
genDoc.SaveAs(genFile)
// Add account to genesis.json
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
@ -1020,6 +1069,11 @@ func TestGaiadCollectGentxs(t *testing.T) {
// Collect gentxs from a custom directory
f.CollectGenTxs(fmt.Sprintf("--gentx-dir=%s", gentxDir))
genDoc, err = tmtypes.GenesisDocFromFile(genFile)
require.NoError(t, err)
require.Equal(t, genDoc.ConsensusParams.Block.MaxBytes, customMaxBytes)
require.Equal(t, genDoc.ConsensusParams.Block.MaxGas, customMaxGas)
f.Cleanup(gentxDir)
}

View File

@ -10,19 +10,22 @@ import (
"testing"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
appInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
@ -58,13 +61,16 @@ var (
// Fixtures is used to setup the testing environment
type Fixtures struct {
ChainID string
RPCAddr string
Port string
GDHome string
GCLIHome string
P2PAddr string
T *testing.T
BuildDir string
GaiadBinary string
GaiacliBinary string
ChainID string
RPCAddr string
Port string
GaiadHome string
GaiacliHome string
P2PAddr string
T *testing.T
}
// NewFixtures creates a new instance of Fixtures with many vars set
@ -78,25 +84,34 @@ func NewFixtures(t *testing.T) *Fixtures {
p2pAddr, _, err := server.FreeTCPAddr()
require.NoError(t, err)
buildDir := os.Getenv("BUILDDIR")
if buildDir == "" {
buildDir, err = filepath.Abs("../../../build/")
require.NoError(t, err)
}
return &Fixtures{
T: t,
GDHome: filepath.Join(tmpDir, ".gaiad"),
GCLIHome: filepath.Join(tmpDir, ".gaiacli"),
RPCAddr: servAddr,
P2PAddr: p2pAddr,
Port: port,
T: t,
BuildDir: buildDir,
GaiadBinary: filepath.Join(buildDir, "gaiad"),
GaiacliBinary: filepath.Join(buildDir, "gaiacli"),
GaiadHome: filepath.Join(tmpDir, ".gaiad"),
GaiacliHome: filepath.Join(tmpDir, ".gaiacli"),
RPCAddr: servAddr,
P2PAddr: p2pAddr,
Port: port,
}
}
// GenesisFile returns the path of the genesis file
func (f Fixtures) GenesisFile() string {
return filepath.Join(f.GDHome, "config", "genesis.json")
return filepath.Join(f.GaiadHome, "config", "genesis.json")
}
// GenesisFile returns the application's genesis state
func (f Fixtures) GenesisState() app.GenesisState {
cdc := codec.New()
genDoc, err := appInit.LoadGenesisDoc(cdc, f.GenesisFile())
genDoc, err := tmtypes.GenesisDocFromFile(f.GenesisFile())
require.NoError(f.T, err)
var appState app.GenesisState
@ -150,7 +165,7 @@ func InitFixtures(t *testing.T) (f *Fixtures) {
// Cleanup is meant to be run at the end of a test to clean up an remaining test state
func (f *Fixtures) Cleanup(dirs ...string) {
clean := append(dirs, f.GDHome, f.GCLIHome)
clean := append(dirs, f.GaiadHome, f.GaiacliHome)
for _, d := range clean {
err := os.RemoveAll(d)
require.NoError(f.T, err)
@ -159,7 +174,7 @@ func (f *Fixtures) Cleanup(dirs ...string) {
// Flags returns the flags necessary for making most CLI calls
func (f *Fixtures) Flags() string {
return fmt.Sprintf("--home=%s --node=%s", f.GCLIHome, f.RPCAddr)
return fmt.Sprintf("--home=%s --node=%s", f.GaiacliHome, f.RPCAddr)
}
//___________________________________________________________________________________
@ -167,17 +182,17 @@ func (f *Fixtures) Flags() string {
// UnsafeResetAll is gaiad unsafe-reset-all
func (f *Fixtures) UnsafeResetAll(flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad --home=%s unsafe-reset-all", f.GDHome)
cmd := fmt.Sprintf("%s --home=%s unsafe-reset-all", f.GaiadBinary, f.GaiadHome)
executeWrite(f.T, addFlags(cmd, flags))
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
err := os.RemoveAll(filepath.Join(f.GaiadHome, "config", "gentx"))
require.NoError(f.T, err)
}
// GDInit is gaiad init
// NOTE: GDInit sets the ChainID for the Fixtures instance
func (f *Fixtures) GDInit(moniker string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad init -o --home=%s %s", f.GDHome, moniker)
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s init -o --home=%s %s", f.GaiadBinary, f.GaiadHome, moniker)
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
var chainID string
var initRes map[string]json.RawMessage
@ -193,25 +208,25 @@ func (f *Fixtures) GDInit(moniker string, flags ...string) {
// AddGenesisAccount is gaiad add-genesis-account
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
cmd := fmt.Sprintf("%s add-genesis-account %s %s --home=%s", f.GaiadBinary, address, coins, f.GaiadHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
// GenTx is gaiad gentx
func (f *Fixtures) GenTx(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad gentx --name=%s --home=%s --home-client=%s", name, f.GDHome, f.GCLIHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s", f.GaiadBinary, name, f.GaiadHome, f.GaiacliHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// CollectGenTxs is gaiad collect-gentxs
func (f *Fixtures) CollectGenTxs(flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad collect-gentxs --home=%s", f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s collect-gentxs --home=%s", f.GaiadBinary, f.GaiadHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// GDStart runs gaiad start with the appropriate flags and returns a process
func (f *Fixtures) GDStart(flags ...string) *tests.Process {
cmd := fmt.Sprintf("../../../build/gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GDHome, f.RPCAddr, f.P2PAddr)
cmd := fmt.Sprintf("%s start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GaiadBinary, f.GaiadHome, f.RPCAddr, f.P2PAddr)
proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags))
tests.WaitForTMStart(f.Port)
tests.WaitForNextNBlocksTM(1, f.Port)
@ -220,7 +235,7 @@ func (f *Fixtures) GDStart(flags ...string) *tests.Process {
// GDTendermint returns the results of gaiad tendermint [query]
func (f *Fixtures) GDTendermint(query string) string {
cmd := fmt.Sprintf("../../../build/gaiad tendermint %s --home=%s", query, f.GDHome)
cmd := fmt.Sprintf("%s tendermint %s --home=%s", f.GaiadBinary, query, f.GaiadHome)
success, stdout, stderr := executeWriteRetStdStreams(f.T, cmd)
require.Empty(f.T, stderr)
require.True(f.T, success)
@ -229,7 +244,7 @@ func (f *Fixtures) GDTendermint(query string) string {
// ValidateGenesis runs gaiad validate-genesis
func (f *Fixtures) ValidateGenesis() {
cmd := fmt.Sprintf("../../../build/gaiad validate-genesis --home=%s", f.GDHome)
cmd := fmt.Sprintf("%s validate-genesis --home=%s", f.GaiadBinary, f.GaiadHome)
executeWriteCheckErr(f.T, cmd)
}
@ -238,31 +253,31 @@ func (f *Fixtures) ValidateGenesis() {
// KeysDelete is gaiacli keys delete
func (f *Fixtures) KeysDelete(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys delete --home=%s %s", f.GCLIHome, name)
cmd := fmt.Sprintf("%s keys delete --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name)
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
}
// KeysAdd is gaiacli keys add
func (f *Fixtures) KeysAdd(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s %s", f.GCLIHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s keys add --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// KeysAddRecover prepares gaiacli keys add --recover
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s", f.GCLIHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
cmd := fmt.Sprintf("%s keys add --home=%s --recover %s", f.GaiacliBinary, f.GaiacliHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass, mnemonic)
}
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
cmd := fmt.Sprintf("%s keys add --home=%s --recover %s --account %d --index %d", f.GaiacliBinary, f.GaiacliHome, name, account, index)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass, mnemonic)
}
// KeysShow is gaiacli keys show
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
cmd := fmt.Sprintf("../../../build/gaiacli keys show --home=%s %s", f.GCLIHome, name)
cmd := fmt.Sprintf("%s keys show --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name)
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ko keys.KeyOutput
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
@ -283,7 +298,7 @@ func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
// CLIConfig is gaiacli config
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
cmd := fmt.Sprintf("%s config --home=%s %s %s", f.GaiacliBinary, f.GaiacliHome, key, value)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
@ -292,41 +307,41 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
// TxSend is gaiacli tx send
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx send %s %s %s %v", f.GaiacliBinary, from, to, amount, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
func (f *Fixtures) txSendWithConfirm(
from string, to sdk.AccAddress, amount sdk.Coin, confirm string, flags ...string,
) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx send %s %s %s %v", f.GaiacliBinary, from, to, amount, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, client.DefaultKeyPass)
}
// TxSign is gaiacli tx sign
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx sign %v --from=%s %v", f.Flags(), signer, fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx sign %v --from=%s %v", f.GaiacliBinary, f.Flags(), signer, fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxBroadcast is gaiacli tx broadcast
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx broadcast %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx broadcast %v %v", f.GaiacliBinary, f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxEncode is gaiacli tx encode
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx encode %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx encode %v %v", f.GaiacliBinary, f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxMultisign is gaiacli tx multisign
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx multisign %v %s %s %s", f.Flags(),
cmd := fmt.Sprintf("%s tx multisign %v %s %s %s", f.GaiacliBinary, f.Flags(),
fileName, name, strings.Join(signaturesFiles, " "),
)
return executeWriteRetStdStreams(f.T, cmd)
@ -337,17 +352,17 @@ func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
// TxStakingCreateValidator is gaiacli tx staking create-validator
func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx staking create-validator %v --from=%s --pubkey=%s", f.Flags(), from, consPubKey)
cmd := fmt.Sprintf("%s tx staking create-validator %v --from=%s --pubkey=%s", f.GaiacliBinary, f.Flags(), from, consPubKey)
cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05")
cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
cmd += fmt.Sprintf(" --min-self-delegation=%v", "1")
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxStakingUnbond is gaiacli tx staking unbond
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
cmd := fmt.Sprintf("../../../build/gaiacli tx staking unbond %s %v --from=%s %v", validator, shares, from, f.Flags())
return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx staking unbond %s %v --from=%s %v", f.GaiacliBinary, validator, shares, from, f.Flags())
return executeWrite(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
//___________________________________________________________________________________
@ -355,21 +370,21 @@ func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov submit-proposal %v --from=%s --type=%s", f.Flags(), from, typ)
cmd := fmt.Sprintf("%s tx gov submit-proposal %v --from=%s --type=%s", f.GaiacliBinary, f.Flags(), from, typ)
cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxGovDeposit is gaiacli tx gov deposit
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov deposit %d %s --from=%s %v", proposalID, amount, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx gov deposit %d %s --from=%s %v", f.GaiacliBinary, proposalID, amount, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
// TxGovVote is gaiacli tx gov vote
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov vote %d %s --from=%s %v", proposalID, option, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
cmd := fmt.Sprintf("%s tx gov vote %d %s --from=%s %v", f.GaiacliBinary, proposalID, option, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
}
//___________________________________________________________________________________
@ -377,7 +392,7 @@ func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string,
// QueryAccount is gaiacli query account
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
cmd := fmt.Sprintf("../../../build/gaiacli query account %s %v", address, f.Flags())
cmd := fmt.Sprintf("%s query account %s %v", f.GaiacliBinary, address, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
@ -396,7 +411,7 @@ func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.Ba
// QueryTxs is gaiacli query txs
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.GaiacliBinary, page, limit, queryTags(tags), f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var txs []sdk.TxResponse
cdc := app.MakeCodec()
@ -407,7 +422,7 @@ func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
// QueryTxsInvalid query txs with wrong parameters and compare expected error
func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.GaiacliBinary, page, limit, queryTags(tags), f.Flags())
_, err := tests.ExecuteT(f.T, cmd, "")
require.EqualError(f.T, expectedErr, err)
}
@ -417,7 +432,7 @@ func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...s
// QueryStakingValidator is gaiacli query staking validator
func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string) staking.Validator {
cmd := fmt.Sprintf("../../../build/gaiacli query staking validator %s %v", valAddr, f.Flags())
cmd := fmt.Sprintf("%s query staking validator %s %v", f.GaiacliBinary, valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var validator staking.Validator
cdc := app.MakeCodec()
@ -428,7 +443,7 @@ func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation {
cmd := fmt.Sprintf("../../../build/gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
cmd := fmt.Sprintf("%s query staking unbonding-delegations-from %s %v", f.GaiacliBinary, valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ubds []staking.UnbondingDelegation
cdc := app.MakeCodec()
@ -439,7 +454,7 @@ func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress,
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
cmd := fmt.Sprintf("../../../build/gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
cmd := fmt.Sprintf("%s query staking delegations-to %s %v", f.GaiacliBinary, valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var delegations []staking.Delegation
cdc := app.MakeCodec()
@ -450,7 +465,7 @@ func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...st
// QueryStakingPool is gaiacli query staking pool
func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
cmd := fmt.Sprintf("../../../build/gaiacli query staking pool %v", f.Flags())
cmd := fmt.Sprintf("%s query staking pool %v", f.GaiacliBinary, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var pool staking.Pool
cdc := app.MakeCodec()
@ -461,7 +476,7 @@ func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
// QueryStakingParameters is gaiacli query staking parameters
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
cmd := fmt.Sprintf("../../../build/gaiacli query staking params %v", f.Flags())
cmd := fmt.Sprintf("%s query staking params %v", f.GaiacliBinary, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var params staking.Params
cdc := app.MakeCodec()
@ -475,7 +490,7 @@ func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
// QueryGovParamDeposit is gaiacli query gov param deposit
func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param deposit %s", f.Flags())
cmd := fmt.Sprintf("%s query gov param deposit %s", f.GaiacliBinary, f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var depositParam gov.DepositParams
cdc := app.MakeCodec()
@ -486,7 +501,7 @@ func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
// QueryGovParamVoting is gaiacli query gov param voting
func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param voting %s", f.Flags())
cmd := fmt.Sprintf("%s query gov param voting %s", f.GaiacliBinary, f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var votingParam gov.VotingParams
cdc := app.MakeCodec()
@ -497,7 +512,7 @@ func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
// QueryGovParamTallying is gaiacli query gov param tallying
func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param tallying %s", f.Flags())
cmd := fmt.Sprintf("%s query gov param tallying %s", f.GaiacliBinary, f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var tallyingParam gov.TallyParams
cdc := app.MakeCodec()
@ -508,7 +523,7 @@ func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
// QueryGovProposals is gaiacli query gov proposals
func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposals %v", f.Flags())
cmd := fmt.Sprintf("%s query gov proposals %v", f.GaiacliBinary, f.Flags())
stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
if strings.Contains(stderr, "No matching proposals found") {
return gov.Proposals{}
@ -523,7 +538,7 @@ func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
// QueryGovProposal is gaiacli query gov proposal
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposal %d %v", proposalID, f.Flags())
cmd := fmt.Sprintf("%s query gov proposal %d %v", f.GaiacliBinary, proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var proposal gov.Proposal
cdc := app.MakeCodec()
@ -534,7 +549,7 @@ func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposa
// QueryGovVote is gaiacli query gov vote
func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) gov.Vote {
cmd := fmt.Sprintf("../../../build/gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
cmd := fmt.Sprintf("%s query gov vote %d %s %v", f.GaiacliBinary, proposalID, voter, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var vote gov.Vote
cdc := app.MakeCodec()
@ -545,7 +560,7 @@ func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...s
// QueryGovVotes is gaiacli query gov votes
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
cmd := fmt.Sprintf("../../../build/gaiacli query gov votes %d %v", proposalID, f.Flags())
cmd := fmt.Sprintf("%s query gov votes %d %v", f.GaiacliBinary, proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var votes []gov.Vote
cdc := app.MakeCodec()
@ -556,7 +571,7 @@ func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
// QueryGovDeposit is gaiacli query gov deposit
func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) gov.Deposit {
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
cmd := fmt.Sprintf("%s query gov deposit %d %s %v", f.GaiacliBinary, proposalID, depositor, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposit gov.Deposit
cdc := app.MakeCodec()
@ -567,7 +582,7 @@ func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, fla
// QueryGovDeposits is gaiacli query gov deposits
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposits %d %v", propsalID, f.Flags())
cmd := fmt.Sprintf("%s query gov deposits %d %v", f.GaiacliBinary, propsalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposits []gov.Deposit
cdc := app.MakeCodec()
@ -581,7 +596,7 @@ func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposi
// QuerySigningInfo returns the signing info for a validator
func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
cmd := fmt.Sprintf("../../../build/gaiacli query slashing signing-info %s %s", val, f.Flags())
cmd := fmt.Sprintf("%s query slashing signing-info %s %s", f.GaiacliBinary, val, f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
@ -593,7 +608,7 @@ func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
// QuerySlashingParams is gaiacli query slashing params
func (f *Fixtures) QuerySlashingParams() slashing.Params {
cmd := fmt.Sprintf("../../../build/gaiacli query slashing params %s", f.Flags())
cmd := fmt.Sprintf("%s query slashing params %s", f.GaiacliBinary, f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
@ -603,6 +618,21 @@ func (f *Fixtures) QuerySlashingParams() slashing.Params {
return params
}
//___________________________________________________________________________________
// query distribution
// QuerySigningInfo returns the signing info for a validator
func (f *Fixtures) QueryRewards(delAddr sdk.AccAddress, flags ...string) distribution.QueryDelegatorTotalRewardsResponse {
cmd := fmt.Sprintf("%s query distr rewards %s %s", f.GaiacliBinary, delAddr, f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
var rewards distribution.QueryDelegatorTotalRewardsResponse
err := cdc.UnmarshalJSON([]byte(res), &rewards)
require.NoError(f.T, err)
return rewards
}
//___________________________________________________________________________________
// executors

View File

@ -70,6 +70,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
logger, db, traceStore, true, invCheckPeriod,
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
baseapp.SetHaltHeight(uint64(viper.GetInt(server.FlagHaltHeight))),
)
}

View File

@ -5,8 +5,9 @@ import (
"fmt"
"os"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/libs/bech32"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var bech32Prefixes = []string{

View File

@ -0,0 +1,228 @@
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
)
var (
// default seeds
seeds = []int{
1, 2, 4, 7, 32, 123, 124, 582, 1893, 2989,
3012, 4728, 37827, 981928, 87821, 891823782,
989182, 89182391, 11, 22, 44, 77, 99, 2020,
3232, 123123, 124124, 582582, 18931893,
29892989, 30123012, 47284728, 37827,
}
// goroutine-safe process map
procs map[int]*os.Process
mutex *sync.Mutex
// results channel
results chan bool
// command line arguments and options
jobs int
blocks string
period string
testname string
genesis string
// logs temporary directory
tempdir string
)
func init() {
log.SetPrefix("")
log.SetFlags(0)
procs = map[int]*os.Process{}
mutex = &sync.Mutex{}
flag.IntVar(&jobs, "j", 10, "Number of parallel processes")
flag.StringVar(&genesis, "g", "", "Genesis file")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(),
`Usage: %s [-j maxprocs] [-g genesis.json] [blocks] [period] [testname]
Run simulations in parallel
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
func main() {
var err error
flag.Parse()
if flag.NArg() != 3 {
log.Fatal("wrong number of arguments")
}
// prepare input channel
queue := make(chan int, len(seeds))
for _, seed := range seeds {
queue <- seed
}
close(queue)
// jobs cannot be > len(seeds)
if jobs > len(seeds) {
jobs = len(seeds)
}
results = make(chan bool, len(seeds))
// setup signal handling
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
_ = <-sigs
fmt.Println()
// drain the queue
log.Printf("Draining seeds queue...")
for seed := range queue {
log.Printf("%d", seed)
}
log.Printf("Kill all remaining processes...")
killAllProcs()
os.Exit(1)
}()
// initialise common test parameters
blocks = flag.Arg(0)
period = flag.Arg(1)
testname = flag.Arg(2)
tempdir, err = ioutil.TempDir("", "")
if err != nil {
log.Fatal(err)
}
// set up worker pool
wg := sync.WaitGroup{}
for workerId := 0; workerId < jobs; workerId++ {
wg.Add(1)
go func(workerId int) {
defer wg.Done()
worker(workerId, queue)
}(workerId)
}
// idiomatic hack required to use wg.Wait() with select
waitCh := make(chan struct{})
go func() {
defer close(waitCh)
wg.Wait()
}()
wait:
for {
select {
case <-waitCh:
break wait
case <-time.After(1 * time.Minute):
fmt.Println(".")
}
}
// analyse results and exit with 1 on first error
close(results)
for rc := range results {
if !rc {
os.Exit(1)
}
}
os.Exit(0)
}
func buildCommand(testname, blocks, period, genesis string, seed int) string {
return fmt.Sprintf("go test github.com/cosmos/cosmos-sdk/cmd/gaia/app -run %s -SimulationEnabled=true "+
"-SimulationNumBlocks=%s -SimulationGenesis=%s "+
"-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=%d -SimulationPeriod=%s -v -timeout 24h",
testname, blocks, genesis, seed, period)
}
func makeCmd(cmdStr string) *exec.Cmd {
cmdSlice := strings.Split(cmdStr, " ")
return exec.Command(cmdSlice[0], cmdSlice[1:]...)
}
func makeFilename(seed int) string {
return fmt.Sprintf("gaia-simulation-seed-%d-date-%s", seed, time.Now().Format("01-02-2006_15:04:05.000000000"))
}
func worker(id int, seeds <-chan int) {
log.Printf("[W%d] Worker is up and running", id)
for seed := range seeds {
if err := spawnProc(id, seed); err != nil {
results <- false
log.Printf("[W%d] Seed %d: FAILED", id, seed)
log.Printf("To reproduce run: %s", buildCommand(testname, blocks, period, genesis, seed))
} else {
log.Printf("[W%d] Seed %d: OK", id, seed)
}
}
log.Printf("[W%d] no seeds left, shutting down", id)
}
func spawnProc(workerId int, seed int) error {
stderrFile, _ := os.Create(filepath.Join(tempdir, makeFilename(seed)+".stderr"))
stdoutFile, _ := os.Create(filepath.Join(tempdir, makeFilename(seed)+".stdout"))
s := buildCommand(testname, blocks, period, genesis, seed)
cmd := makeCmd(s)
cmd.Stdout = stdoutFile
cmd.Stderr = stderrFile
err := cmd.Start()
if err != nil {
log.Printf("couldn't start %q", s)
return err
}
log.Printf("[W%d] Spawned simulation with pid %d [seed=%d stdout=%s stderr=%s]",
workerId, cmd.Process.Pid, seed, stdoutFile.Name(), stderrFile.Name())
pushProcess(cmd.Process)
defer popProcess(cmd.Process)
return cmd.Wait()
}
func pushProcess(proc *os.Process) {
mutex.Lock()
defer mutex.Unlock()
procs[proc.Pid] = proc
}
func popProcess(proc *os.Process) {
mutex.Lock()
defer mutex.Unlock()
if _, ok := procs[proc.Pid]; ok {
delete(procs, proc.Pid)
}
}
func killAllProcs() {
mutex.Lock()
defer mutex.Unlock()
for _, proc := range procs {
checkSignal(proc, syscall.SIGTERM)
checkSignal(proc, syscall.SIGKILL)
}
}
func checkSignal(proc *os.Process, signal syscall.Signal) {
if err := proc.Signal(signal); err != nil {
log.Printf("Failed to send %s to PID %d", signal, proc.Pid)
}
}

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
go mod download
seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391 \
@ -16,33 +18,63 @@ echo "Using genesis file $genesis"
echo "Edit scripts/multisim.sh to add new seeds. Keeping parameters in the file makes failures easy to reproduce."
echo "This script will kill all sub-simulations on SIGINT/SIGTERM (i.e. Ctrl-C)."
trap 'kill $(jobs -pr)' SIGINT SIGTERM
# Symbols prefixes legenda:
# f_ - function
# l_ - local symbols
f_spinner() {
local l_i l_sp
l_i=1
l_chars="/-\|"
echo -n ' '
while true
do
printf "\b${l_chars:l_i++%${#l_chars}:1}"
sleep 1s
done
}
f_cleanup() {
local l_children
l_children=$(pgrep -P $$)
echo "Stopping children ["${l_children}"] ..." >&2
kill -SIGSTOP ${l_children} || true
echo "Terminating children ["${l_children}"] ..." >&2
kill -TERM ${l_children} || true
exit 0
}
trap f_cleanup SIGINT SIGTERM EXIT
tmpdir=$(mktemp -d)
echo "Using temporary log directory: $tmpdir"
sim() {
seed=$1
echo "Running Gaia simulation with seed $seed. This may take awhile!"
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout"
f_sim() {
local l_seed
l_seed=$1
echo "Running Gaia simulation with seed $l_seed. This may take awhile!"
file="$tmpdir/gaia-simulation-seed-$l_seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout"
echo "Writing stdout to $file..."
go test ./cmd/gaia/app -run $testname -SimulationEnabled=true -SimulationNumBlocks=$blocks -SimulationGenesis=$genesis \
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -SimulationPeriod=$period -v -timeout 24h > $file
go test github.com/cosmos/cosmos-sdk/cmd/gaia/app -run $testname -SimulationEnabled=true -SimulationNumBlocks=$blocks -SimulationGenesis=$genesis \
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$l_seed -SimulationPeriod=$period -v -timeout 24h > $file && \
echo "Simulation with seed $l_seed OK" || ( code=1 ; echo "Simulation with seed $seed failed!" ) # > $file
}
echo "Simulation processes spawned, waiting for completion..."
f_spinner &
i=0
pids=()
for seed in ${seeds[@]}; do
sim $seed &
f_sim $seed &
pids[${i}]=$!
i=$(($i+1))
sleep 10 # start in order, nicer logs
done
echo "Simulation processes spawned, waiting for completion..."
code=0
i=0
for pid in ${pids[*]}; do
wait $pid

View File

@ -46,7 +46,7 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
return err
}
genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
if err != nil {
return err
}
@ -59,7 +59,7 @@ func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
toPrint := newPrintInfo(config.Moniker, genDoc.ChainID, nodeID, genTxsDir, json.RawMessage(""))
initCfg := newInitConfig(genDoc.ChainID, genTxsDir, name, nodeID, valPubKey)
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, *genDoc)
if err != nil {
return err
}
@ -82,7 +82,6 @@ func genAppStateFromConfig(
cdc *codec.Codec, config *cfg.Config, initCfg initConfig, genDoc types.GenesisDoc,
) (appState json.RawMessage, err error) {
genFile := config.GenesisFile()
var (
appGenTxs []auth.StdTx
persistentPeers string
@ -116,7 +115,8 @@ func genAppStateFromConfig(
return
}
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
genDoc.AppState = appState
err = ExportGenesisFile(&genDoc, config.GenesisFile())
return
}

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
@ -58,7 +59,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
}
genDoc, err := LoadGenesisDoc(cdc, genFile)
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
if err != nil {
return err
}
@ -78,7 +79,8 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
return err
}
return ExportGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON)
genDoc.AppState = appStateJSON
return ExportGenesisFile(genDoc, genFile)
},
}

View File

@ -17,6 +17,7 @@ import (
"github.com/tendermint/tendermint/crypto"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
@ -79,7 +80,7 @@ following delegation and commission default parameters:
"the tx's memo field will be unset")
}
genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
genDoc, err := tmtypes.GenesisDocFromFile(config.GenesisFile())
if err != nil {
return err
}

View File

@ -3,15 +3,16 @@ package init
import (
"testing"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
)
func Test_prepareFlagsForTxCreateValidator(t *testing.T) {

View File

@ -11,6 +11,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
@ -76,7 +77,22 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { // nolint:
return err
}
if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil {
genDoc := &types.GenesisDoc{}
if _, err := os.Stat(genFile); err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
genDoc, err = types.GenesisDocFromFile(genFile)
if err != nil {
return err
}
}
genDoc.ChainID = chainID
genDoc.Validators = nil
genDoc.AppState = appState
if err = ExportGenesisFile(genDoc, genFile); err != nil {
return err
}

View File

@ -8,16 +8,17 @@ import (
"testing"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/mock"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
abciServer "github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/mock"
)
func TestInitCmd(t *testing.T) {

View File

@ -157,7 +157,7 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
buf := client.BufferStdin()
prompt := fmt.Sprintf(
"Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass,
"Password for account '%s' (default %s):", nodeDirName, client.DefaultKeyPass,
)
keyPass, err := client.GetPassword(prompt, buf)
@ -169,7 +169,7 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
}
if keyPass == "" {
keyPass = app.DefaultKeyPass
keyPass = client.DefaultKeyPass
}
addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true)
@ -217,7 +217,7 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo).WithKeybase(kb)
signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false)
signedTx, err := txBldr.SignStdTx(nodeDirName, client.DefaultKeyPass, tx, false)
if err != nil {
_ = os.RemoveAll(outDir)
return err
@ -236,6 +236,8 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
return err
}
// TODO: Rename config file to server.toml as it's not particular to Gaia
// (REF: https://github.com/cosmos/cosmos-sdk/issues/4125).
gaiaConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml")
srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig)
}
@ -306,12 +308,12 @@ func collectGenFiles(
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
initCfg := newInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey)
genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
if err != nil {
return err
}
nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, *genDoc)
if err != nil {
return err
}

View File

@ -3,11 +3,9 @@ package init
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"time"
amino "github.com/tendermint/go-amino"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/common"
@ -22,16 +20,7 @@ import (
// ExportGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
func ExportGenesisFile(
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
) error {
genDoc := types.GenesisDoc{
ChainID: chainID,
Validators: validators,
AppState: appState,
}
func ExportGenesisFile(genDoc *types.GenesisDoc, genFile string) error {
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
@ -88,20 +77,6 @@ func InitializeNodeValidatorFiles(
return nodeID, valPubKey, nil
}
// LoadGenesisDoc reads and unmarshals GenesisDoc from the given file.
func LoadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
genContents, err := ioutil.ReadFile(genFile)
if err != nil {
return genDoc, err
}
if err := cdc.UnmarshalJSON(genContents, &genDoc); err != nil {
return genDoc, err
}
return genDoc, err
}
func initializeEmptyGenesis(
cdc *codec.Codec, genFile, chainID string, overwrite bool,
) (appState json.RawMessage, err error) {

View File

@ -2,13 +2,10 @@ package init
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/stretchr/testify/require"
@ -22,28 +19,3 @@ func TestExportGenesisFileWithTime(t *testing.T) {
fname := filepath.Join(dir, "genesis.json")
require.NoError(t, ExportGenesisFileWithTime(fname, "test", nil, json.RawMessage(""), time.Now()))
}
func TestLoadGenesisDoc(t *testing.T) {
t.Parallel()
dir, cleanup := tests.NewTestCaseDir(t)
defer cleanup()
fname := filepath.Join(dir, "genesis.json")
require.NoError(t, ExportGenesisFileWithTime(fname, "test", nil, json.RawMessage(""), time.Now()))
_, err := LoadGenesisDoc(codec.Cdc, fname)
require.NoError(t, err)
// Non-existing file
_, err = LoadGenesisDoc(codec.Cdc, "non-existing-file")
require.Error(t, err)
malformedFilename := filepath.Join(dir, "malformed")
malformedFile, err := os.Create(malformedFilename)
require.NoError(t, err)
fmt.Fprint(malformedFile, "invalidjson")
malformedFile.Close()
// Non-existing file
_, err = LoadGenesisDoc(codec.Cdc, malformedFilename)
require.Error(t, err)
}

View File

@ -4,11 +4,12 @@ import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
)
// Validate genesis command takes
@ -30,8 +31,8 @@ func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
//nolint
fmt.Fprintf(os.Stderr, "validating genesis file at %s\n", genesis)
var genDoc types.GenesisDoc
if genDoc, err = LoadGenesisDoc(cdc, genesis); err != nil {
var genDoc *types.GenesisDoc
if genDoc, err = types.GenesisDocFromFile(genesis); err != nil {
return fmt.Errorf("Error loading genesis doc from %s: %s", genesis, err.Error())
}

62
cmd/gaia/sims.mk Normal file
View File

@ -0,0 +1,62 @@
#!/usr/bin/make -f
########################################
### Simulations
runsim: $(GOBIN)/runsim
$(GOBIN)/runsim: contrib/runsim/main.go
go install github.com/cosmos/cosmos-sdk/cmd/gaia/contrib/runsim
sim-gaia-nondeterminism:
@echo "Running nondeterminism test..."
@go test -mod=readonly ./cmd/gaia/app -run TestAppStateDeterminism -SimulationEnabled=true -v -timeout 10m
sim-gaia-custom-genesis-fast:
@echo "Running custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@go test -mod=readonly github.com/cosmos/cosmos-sdk/cmd/gaia/app -run TestFullGaiaSimulation -SimulationGenesis=${HOME}/.gaiad/config/genesis.json \
-SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
sim-gaia-fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test -mod=readonly github.com/cosmos/cosmos-sdk/cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
sim-gaia-import-export: runsim
@echo "Running Gaia import/export simulation. This may take several minutes..."
$(GOBIN)/runsim 50 5 TestGaiaImportExport
sim-gaia-simulation-after-import: runsim
@echo "Running Gaia simulation-after-import. This may take several minutes..."
$(GOBIN)/runsim 50 5 TestGaiaSimulationAfterImport
sim-gaia-custom-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
$(GOBIN)/runsim -g ${HOME}/.gaiad/config/genesis.json 400 5 TestFullGaiaSimulation
sim-gaia-multi-seed: runsim
@echo "Running multi-seed Gaia simulation. This may take awhile!"
$(GOBIN)/runsim 400 5 TestFullGaiaSimulation
sim-benchmark-invariants:
@echo "Running simulation invariant benchmarks..."
@go test -mod=readonly github.com/cosmos/cosmos-sdk/cmd/gaia/app -benchmem -bench=BenchmarkInvariants -run=^$ \
-SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationBlockSize=200 \
-SimulationCommit=true -SimulationSeed=57 -v -timeout 24h
SIM_NUM_BLOCKS ?= 500
SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
sim-gaia-benchmark:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -mod=readonly -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
sim-gaia-profile:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -mod=readonly -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
.PHONY: sim-gaia-nondeterminism sim-gaia-custom-genesis-fast sim-gaia-fast sim-gaia-import-export \
sim-gaia-simulation-after-import sim-gaia-custom-genesis-multi-seed sim-gaia-multi-seed \
sim-benchmark-invariants sim-gaia-benchmark sim-gaia-profile

View File

@ -5,7 +5,7 @@ import (
"encoding/json"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto/encoding/amino"
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
)
// amino codec to marshal/unmarshal

View File

@ -44,11 +44,11 @@ mkfile_dir := $(shell cd $(shell dirname $(mkfile_path)); pwd)
all: tools
tools: tools-stamp
tools-stamp: $(GOBIN)/golangci-lint $(GOBIN)/statik $(GOBIN)/goimports $(GOBIN)/gosum $(GOBIN)/sdkch
tools-stamp: $(GOBIN)/golangci-lint $(GOBIN)/statik $(GOBIN)/goimports $(GOBIN)/gosum $(GOBIN)/clog
touch $@
$(GOBIN)/golangci-lint: contrib/install-golangci-lint.sh $(GOBIN)/gosum
bash contrib/install-golangci-lint.sh $(GOBIN) $(GOLANGCI_LINT_VERSION) $(GOLANGCI_LINT_HASHSUM)
$(GOBIN)/golangci-lint: $(mkfile_dir)/install-golangci-lint.sh $(GOBIN)/gosum
bash $(mkfile_dir)/install-golangci-lint.sh $(GOBIN) $(GOLANGCI_LINT_VERSION) $(GOLANGCI_LINT_HASHSUM)
$(GOBIN)/statik:
$(call go_install,rakyll,statik,v0.1.5)
@ -57,13 +57,13 @@ $(GOBIN)/goimports:
go get golang.org/x/tools/cmd/goimports@v0.0.0-20190114222345-bf090417da8b
$(GOBIN)/gosum:
go install -mod=readonly ./cmd/gosum/
go install -mod=readonly github.com/cosmos/cosmos-sdk/contrib/devtools/gosum/
$(GOBIN)/sdkch:
go install -mod=readonly ./cmd/sdkch/
$(GOBIN)/clog:
go install -mod=readonly github.com/cosmos/cosmos-sdk/contrib/devtools/clog/
tools-clean:
cd $(GOBIN) && rm -f golangci-lint statik goimports gosum sdkch
cd $(GOBIN) && rm -f golangci-lint statik goimports gosum clog
rm -f tools-stamp
.PHONY: all tools tools-clean

View File

@ -7,12 +7,13 @@ import (
"fmt"
"io/ioutil"
"log"
"math"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/spf13/cobra"
)
const (
@ -26,8 +27,9 @@ var (
progName string
verboseLog *log.Logger
entriesDir string
verboseLogging bool
entriesDir string
verboseLogging bool
interactiveMode bool
// sections name-title map
sections = map[string]string{
@ -44,22 +46,91 @@ var (
"sdk": "SDK",
"tendermint": "Tendermint",
}
// RootCmd represents the base command when called without any subcommands
RootCmd = &cobra.Command{
Use: "clog",
Short: "Maintain unreleased changelog entries in a modular fashion.",
}
// command to add a pending log entry
AddCmd = &cobra.Command{
Use: "add [section] [stanza] [message]",
Short: "Add an entry file.",
Long: `Add an entry file. If message is empty, start the editor to edit the message.
Sections Stanzas
--- ---
breaking gaia
features gaiacli
improvements gaiarest
bugfixes sdk
tendermint`,
Args: cobra.MaximumNArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
if interactiveMode {
return addEntryFileFromConsoleInput()
}
if len(args) < 2 {
log.Println("must include at least 2 arguments when not in interactive mode")
return nil
}
sectionDir, stanzaDir := args[0], args[1]
err := validateSectionStanzaDirs(sectionDir, stanzaDir)
if err != nil {
return err
}
if len(args) == 3 {
return addSinglelineEntryFile(sectionDir, stanzaDir, strings.TrimSpace(args[2]))
}
return addEntryFile(sectionDir, stanzaDir)
},
}
// command to generate the changelog
GenerateCmd = &cobra.Command{
Use: "generate",
Short: "Generate a changelog in Markdown format and print it to STDOUT. version defaults to UNRELEASED.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
version := "UNRELEASED"
if flag.NArg() > 1 {
version = strings.Join(flag.Args()[1:], " ")
}
return generateChangelog(version)
},
}
// command to delete empty sub-directories recursively
PruneCmd = &cobra.Command{
Use: "prune",
Short: "Delete empty sub-directories recursively.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return pruneEmptyDirectories()
},
}
)
func init() {
progName = filepath.Base(os.Args[0])
RootCmd.AddCommand(AddCmd)
RootCmd.AddCommand(GenerateCmd)
RootCmd.AddCommand(PruneCmd)
cwd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
flag.StringVar(&entriesDir, "d", filepath.Join(cwd, entriesDirName), "entry files directory")
flag.BoolVar(&verboseLogging, "v", false, "enable verbose logging")
flag.Usage = printUsage
AddCmd.Flags().BoolVarP(&interactiveMode, "interactive", "i", false, "get the section/stanza/message with interactive CLI prompts")
RootCmd.PersistentFlags().BoolVarP(&verboseLogging, "verbose-logging", "v", false, "enable verbose logging")
RootCmd.PersistentFlags().StringVarP(&entriesDir, "entries-dir", "d", filepath.Join(cwd, entriesDirName), "entry files directory")
}
func main() {
logPrefix := fmt.Sprintf("%s: ", filepath.Base(progName))
log.SetFlags(0)
log.SetPrefix(logPrefix)
@ -70,67 +141,65 @@ func main() {
verboseLog.SetPrefix(logPrefix)
}
if flag.NArg() < 1 {
errInsufficientArgs()
}
cmd := flag.Arg(0)
switch cmd {
case "add":
if flag.NArg() < 3 {
errInsufficientArgs()
}
if flag.NArg() > 4 {
errTooManyArgs()
}
sectionDir, stanzaDir := flag.Arg(1), flag.Arg(2)
validateSectionStanzaDirs(sectionDir, stanzaDir)
if flag.NArg() == 4 {
addSinglelineEntryFile(sectionDir, stanzaDir, strings.TrimSpace(flag.Arg(3)))
return
}
addEntryFile(sectionDir, stanzaDir)
case "generate":
version := "UNRELEASED"
if flag.NArg() > 1 {
version = strings.Join(flag.Args()[1:], " ")
}
generateChangelog(version)
case "prune":
pruneEmptyDirectories()
default:
unknownCommand(cmd)
if err := RootCmd.Execute(); err != nil {
log.Fatal(err)
}
}
func addSinglelineEntryFile(sectionDir, stanzaDir, message string) {
func addEntryFileFromConsoleInput() error {
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the section (either: \"breaking\", \"features\", \"improvements\", \"bugfixes\")")
sectionDir, _ := reader.ReadString('\n')
sectionDir = strings.TrimSpace(sectionDir)
if _, ok := sections[sectionDir]; !ok {
return errors.New("invalid section, please try again")
}
fmt.Println("Please enter the stanza (either: \"gaia\", \"gaiacli\", \"gaiarest\", \"sdk\", \"tendermint\")")
stanzaDir, _ := reader.ReadString('\n')
stanzaDir = strings.TrimSpace(stanzaDir)
if _, ok := stanzas[stanzaDir]; !ok {
return errors.New("invalid stanza, please try again")
}
fmt.Println("Please enter the changelog message (or press enter to write in default $EDITOR)")
message, _ := reader.ReadString('\n')
message = strings.TrimSpace(message)
if message == "" {
return addEntryFile(sectionDir, stanzaDir)
}
return addSinglelineEntryFile(sectionDir, stanzaDir, message)
}
func addSinglelineEntryFile(sectionDir, stanzaDir, message string) error {
filename := filepath.Join(
filepath.Join(entriesDir, sectionDir, stanzaDir),
generateFileName(message),
)
writeEntryFile(filename, []byte(message))
return writeEntryFile(filename, []byte(message))
}
func addEntryFile(sectionDir, stanzaDir string) {
bs := readUserInput()
func addEntryFile(sectionDir, stanzaDir string) error {
bs, err := readUserInputFromEditor()
if err != nil {
return err
}
firstLine := strings.TrimSpace(strings.Split(string(bs), "\n")[0])
filename := filepath.Join(
filepath.Join(entriesDir, sectionDir, stanzaDir),
generateFileName(firstLine),
)
writeEntryFile(filename, bs)
return writeEntryFile(filename, bs)
}
var filenameInvalidChars = regexp.MustCompile(`[^a-zA-Z0-9-_]`)
func generateFileName(line string) string {
var chunks []string
filenameInvalidChars := regexp.MustCompile(`[^a-zA-Z0-9-_]`)
subsWithInvalidCharsRemoved := strings.Split(filenameInvalidChars.ReplaceAllString(line, " "), " ")
for _, sub := range subsWithInvalidCharsRemoved {
sub = strings.TrimSpace(sub)
@ -140,17 +209,21 @@ func generateFileName(line string) string {
}
ret := strings.Join(chunks, "-")
return ret[:int(math.Min(float64(len(ret)), float64(maxEntryFilenameLength)))]
if len(ret) > maxEntryFilenameLength {
return ret[:maxEntryFilenameLength]
}
return ret
}
func directoryContents(dirPath string) []os.FileInfo {
func directoryContents(dirPath string) ([]os.FileInfo, error) {
contents, err := ioutil.ReadDir(dirPath)
if err != nil && !os.IsNotExist(err) {
log.Fatalf("couldn't read directory %s: %v", dirPath, err)
return nil, fmt.Errorf("couldn't read directory %s: %v", dirPath, err)
}
if len(contents) == 0 {
return nil
return nil, nil
}
// Filter out hidden files
@ -164,16 +237,19 @@ func directoryContents(dirPath string) []os.FileInfo {
contents[i] = nil
}
return newContents
return newContents, nil
}
func generateChangelog(version string) {
func generateChangelog(version string) error {
fmt.Printf("# %s\n\n", version)
for sectionDir, sectionTitle := range sections {
sectionTitlePrinted := false
for stanzaDir, stanzaTitle := range stanzas {
path := filepath.Join(entriesDir, sectionDir, stanzaDir)
files := directoryContents(path)
files, err := directoryContents(path)
if err != nil {
return err
}
if len(files) == 0 {
continue
}
@ -188,22 +264,27 @@ func generateChangelog(version string) {
verboseLog.Println("processing", f.Name())
filename := filepath.Join(path, f.Name())
if err := indentAndPrintFile(filename); err != nil {
log.Fatal(err)
return err
}
}
fmt.Println()
}
}
return nil
}
func pruneEmptyDirectories() {
for sectionDir, _ := range sections {
for stanzaDir, _ := range stanzas {
mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir, stanzaDir))
func pruneEmptyDirectories() error {
for sectionDir := range sections {
for stanzaDir := range stanzas {
err := mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir, stanzaDir))
if err != nil {
return err
}
}
mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir))
return mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir))
}
return nil
}
// nolint: errcheck
@ -238,45 +319,47 @@ func indentAndPrintFile(filename string) error {
}
// nolint: errcheck
func writeEntryFile(filename string, bs []byte) {
func writeEntryFile(filename string, bs []byte) error {
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
log.Fatal(err)
return err
}
outFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
log.Fatal(err)
return err
}
defer outFile.Close()
if _, err := outFile.Write(bs); err != nil {
log.Fatal(err)
return err
}
log.Printf("Unreleased changelog entry written to: %s\n", filename)
log.Println("To modify this entry please edit or delete the above file directly.")
return nil
}
func validateSectionStanzaDirs(sectionDir, stanzaDir string) {
func validateSectionStanzaDirs(sectionDir, stanzaDir string) error {
if _, ok := sections[sectionDir]; !ok {
log.Fatalf("invalid section -- %s", sectionDir)
return fmt.Errorf("invalid section -- %s", sectionDir)
}
if _, ok := stanzas[stanzaDir]; !ok {
log.Fatalf("invalid stanza -- %s", stanzaDir)
return fmt.Errorf("invalid stanza -- %s", stanzaDir)
}
return nil
}
// nolint: errcheck
func readUserInput() []byte {
func readUserInputFromEditor() ([]byte, error) {
tempfilename, err := launchUserEditor()
if err != nil {
log.Fatalf("couldn't open an editor: %v", err)
return []byte{}, fmt.Errorf("couldn't open an editor: %v", err)
}
defer os.Remove(tempfilename)
bs, err := ioutil.ReadFile(tempfilename)
if err != nil {
log.Fatalf("error: %v", err)
return []byte{}, fmt.Errorf("error: %v", err)
}
return bs
return bs, nil
}
// nolint: errcheck
@ -296,7 +379,7 @@ func launchUserEditor() (string, error) {
"VISUAL or EDITOR variables is set and pointing to a correct editor")
}
tempfile, err := ioutil.TempFile("", "sdkch_*")
tempfile, err := ioutil.TempFile("", "clog_*")
tempfilename := tempfile.Name()
if err != nil {
return "", err
@ -317,62 +400,28 @@ func launchUserEditor() (string, error) {
return "", err
}
if fileInfo.Size() == 0 {
log.Fatal("aborting due to empty message")
return "", errors.New("aborting due to empty message")
}
return tempfilename, nil
}
func mustPruneDirIfEmpty(path string) {
if contents := directoryContents(path); len(contents) == 0 {
if err := os.Remove(path); err != nil {
if !os.IsNotExist(err) {
log.Fatal(err)
}
return
}
log.Println(path, "removed")
func mustPruneDirIfEmpty(path string) error {
contents, err := directoryContents(path)
if err != nil {
return err
}
}
func printUsage() {
usageText := fmt.Sprintf(`usage: %s [-d directory] [-v] command
Maintain unreleased changelog entries in a modular fashion.
Commands:
add [section] [stanza] [message] Add an entry file. If message is empty, start
the editor to edit the message.
generate [version] Generate a changelog in Markdown format and print
it to STDOUT. version defaults to UNRELEASED.
prune Delete empty sub-directories recursively.
Sections Stanzas
--- ---
breaking gaia
features gaiacli
improvements gaiarest
bugfixes sdk
tendermint
`, progName)
fmt.Fprintf(os.Stderr, "%s\nFlags:\n", usageText)
flag.PrintDefaults()
}
func errInsufficientArgs() {
log.Println("insufficient arguments")
printUsage()
os.Exit(1)
}
func errTooManyArgs() {
log.Println("too many arguments")
printUsage()
os.Exit(1)
}
func unknownCommand(cmd string) {
log.Fatalf("unknown command -- '%s'\nTry '%s -help' for more information.", cmd, progName)
if len(contents) != 0 {
return nil
}
if err := os.Remove(path); err != nil {
if !os.IsNotExist(err) {
return err
}
return nil
}
log.Println(path, "removed")
return nil
}
// DONTCOVER

View File

@ -7,11 +7,12 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
)
func init() {

View File

@ -8,7 +8,7 @@ import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/armor"
"github.com/tendermint/tendermint/crypto/encoding/amino"
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
cmn "github.com/tendermint/tendermint/libs/common"

View File

@ -3,11 +3,12 @@ package mintkey_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
"github.com/stretchr/testify/require"
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
)
func TestArmorUnarmorPrivKey(t *testing.T) {

View File

@ -6,12 +6,13 @@ import (
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/tests"
bip39 "github.com/cosmos/go-bip39"
"github.com/pkg/errors"
secp256k1 "github.com/tendermint/btcd/btcec"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/tests"
)
// If ledger support (build tag) has been enabled, which implies a CGO dependency,

View File

@ -5,6 +5,7 @@ import (
"os"
"github.com/btcsuite/btcd/btcec"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/types"

View File

@ -7,11 +7,12 @@ import (
"github.com/cosmos/cosmos-sdk/tests"
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/encoding/amino"
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestLedgerErrorHandling(t *testing.T) {

View File

@ -1,17 +1,13 @@
### `cosmos/cosmos-sdk` Release Process
- [ ] 1. Decide on release designation (are we doing a patch, or minor version bump) and start a branch for the release
- [ ] 2. Add commits/PRs that are desired for this release **that havent already been added to develop**
- [ ] 3. Merge items in `PENDING.md` into the `CHANGELOG.md`. While doing this make sure that each entry contains links to issues/PRs for each item
- [ ] 4. Summarize breaking API changes section under “Breaking Changes” section to the `CHANGELOG.md` to bring attention to any breaking API changes that affect RPC consumers.
- [ ] 5. Tag the commit `git tag -a { .Release.Name }-rcN -m 'Release { .Release.Name }'`
- [ ] 6. Open PRs for both `master` and `develop`. From now onwards ***no additional PRs targeting develop should be merged**. Additional commits can be added on top of the release branch though.
- [ ] 7. Ensure both `master` and `develop` PRs ***pass tests***.
- [ ] 8. Kick off 1 day of automated fuzz testing
- [ ] 9. Release Lead assigns 2 people to perform [buddy testing script](/docs/RELEASE_TEST_SCRIPT.md) and update the relevant documentation
- [ ] 10. If errors are found in either #6 or #7 go back to #2 (*NOTE*: be sure to increment the `rcN`)
- [ ] 11. After #6 and #7 have successfully completed then merge the release PR create the final release annotated tag:
- `git tag -a -m { .Release.Name } 'Release { .Release.Name }'
- Merge **the release tag** to both `master` and `develop` so that both branches sit on top of the same commit: `branches='master develop' ; for b in $branches ; do git checkout $b ; git merge { .Release.Name } ; git push $b`.
Alternatively merge both the aforementioned release PRs.
- Push the final annotated release tag: `git push --tags`
Unless otherwise stated, all of the following tasks will be undertaken by the release manager/coordinator:
- [ ] 1. Decide on release designation (are we doing a patch, or minor version bump)
- [ ] 2. Ensure that all commits/PRs which are destined for this release are merged to the `master` branch
- [ ] 3. Create the release candidate branch `rcN` (please start with `N=1`) (going forward known as **RC**) and ensure it's protected against pushing from anyone except the release manager/coordinator. **no PRs targeting this branch should be merged unless exceptional circumstances arise**
- [ ] 4. On the `RC` branch, use `clog` to prepare the `CHANGELOG.md`.
- [ ] 5. Summarize breaking API changes section under “Breaking Changes” section to the `CHANGELOG.md` to bring attention to any breaking API changes that affect RPC consumers.
- [ ] 6. Kick off a large round of simulation testing (e.g. 400 seeds for 2k blocks)
- [ ] 7. If errors are found in either #6 or #7 go back to #2 (*NOTE*: be sure to increment the `rcN`)
- [ ] 8. After #6 and #7 have successfully completed create the release branch from the `RC` branch (this will trigger the automated relase process which will build binaries, tag the release and push to github)
- [ ] 9. Merge the release branch to `master` and delete the `RC` branch

View File

@ -7,7 +7,6 @@ Once you have finallized your application, install it using `go get`. The follow
```bash
go get github.com/<your_username>/cosmos-sdk
cd $GOPATH/src/github.com/<your_username>/cosmos-sdk
make get_vendor_deps
make install
make install_examples
```

View File

@ -10,7 +10,7 @@ To start a REST server, we need to specify the following parameters:
| trust-node | bool | "false" | true | Whether this LCD is connected to a trusted full node |
| trust-store | DIRECTORY | "$HOME/.lcd" | false | directory for save checkpoints and validator sets |
For example::
For example:
```bash
gaiacli rest-server --chain-id=test \

View File

@ -62,7 +62,7 @@ type KeyExistsProof struct {
}
```
The data structure of exist proof is shown as above. The process to build and verify existance proof
The data structure of exist proof is shown as above. The process to build and verify existence proof
is shown as follows:
![Exist Proof](./pics/existProof.png)

View File

@ -18,9 +18,9 @@ There are three main pieces to consider:
We will describe the steps to run and interract with a full-node for the Cosmos Hub. For other SDK-based blockchain, the process should be similar.
First, you need to [install the software](../getting-started/installation.md).
First, you need to [install the software](../cosmos-hub/installation.md).
Then, you can start [running a full-node](../getting-started/join-testnet.md).
Then, you can start [running a full-node](../cosmos-hub/join-testnet.md).
### Command-Line interface
@ -34,12 +34,13 @@ To generate a new key (default secp256k1 elliptic curve):
gaiacli keys add <your_key_name>
```
You will be asked to create a passwords (at least 8 characters) for this key-pair. The command returns 4 informations:
You will be asked to create a passwords (at least 8 characters) for this key-pair. The command returns 5 informations:
- `NAME`: Name of your key
- `TYPE`: Type of your key, always `local`.
- `ADDRESS`: Your address. Used to receive funds.
- `PUBKEY`: Your public key. Useful for validators.
- `Seed phrase`: 12-words phrase. **Save this seed phrase somewhere safe**. It is used to recover your private key in case you forget the password.
- `MNEMONIC`: 24-words phrase. **Save this mnemonic somewhere safe**. It is used to recover your private key in case you forget the password.
You can see all your available keys by typing:
@ -62,14 +63,20 @@ gaiacli account <YOUR_ADDRESS>
Here is the command to send coins via the CLI:
```bash
gaiacli send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --from=<key_name> --to=<destination_address>
gaiacli tx send <destination_address> <amount> \
--chain-id=<name_of_testnet_chain> \
--from=<key_name>
```
Parameters:
- `<destination_address>`: Address of the recipient.
- `<amount>`: This parameter accepts the format `<value|coinName>`, such as `10faucetToken`.
Flags:
- `--amount`: This flag accepts the format `<value|coinName>`.
- `--chain-id`: This flag allows you to specify the id of the chain. There will be different ids for different testnet chains and main chain.
- `--from`: Name of the key of the sending account.
- `--to`: Address of the recipient.
#### Help
@ -88,12 +95,12 @@ The Rest Server acts as an intermediary between the front-end and the full-node.
To start the Rest server:
```bash
gaiacli advanced rest-server --node=<full_node_address:full_node_port>
gaiacli rest-server --node=<full_node_address:full_node_port>
```
Flags:
- `--trust-node`: A boolean. If `true`, light-client verification is disabled. If `false`, it is disabled. For service providers, this should be set to `true`. By default, it set to `true`.
- `--node`: This is where you indicate the address and the port of your full-node. The format is <full_node_address:full_node_port>. If the full-node is on the same machine, the address should be `tcp://localhost:26657`.
- `--node`: This is where you indicate the address and the port of your full-node. The format is `<full_node_address:full_node_port>`. If the full-node is on the same machine, the address should be `tcp://localhost:26657`.
- `--laddr`: This flag allows you to specify the address and port for the Rest Server (default `1317`). You will mostly use this flag only to specify the port, in which case just input "localhost" for the address. The format is <rest_server_address:port>.
@ -101,7 +108,7 @@ Flags:
The recommended way to listen for incoming transaction is to periodically query the blockchain through the following endpoint of the LCD:
[`/bank/balance/{account}`](https://cosmos.network/rpc/#/ICS20/get_bank_balances__address_)
[`/bank/balance/{address}`](https://cosmos.network/rpc/#/ICS20/get_bank_balances__address_)
## Rest API

View File

@ -201,13 +201,12 @@ When you query an account balance with zero tokens, you will get this error: `No
The following command could be used to send coins from one account to another:
```bash
gaiacli tx send <destination_cosmos> 10faucetToken \
--chain-id=<chain_id> \
--from=<key_name> \
gaiacli tx send <sender_key_name_or_address> <recipient_address> 10faucetToken \
--chain-id=<chain_id>
```
::: warning Note
The `--amount` flag accepts the format `--amount=<value|coin_name>`.
The `amount` argument accepts the format `<value|coin_name>`.
:::
::: tip Note
@ -233,9 +232,8 @@ You can simulate a transaction without actually broadcasting it by appending the
`--dry-run` flag to the command line:
```bash
gaiacli tx send <destination_cosmosaccaddr> 10faucetToken \
gaiacli tx send <sender_key_name_or_address> <destination_cosmosaccaddr> 10faucetToken \
--chain-id=<chain_id> \
--from=<key_name> \
--dry-run
```
@ -243,9 +241,8 @@ Furthermore, you can build a transaction and print its JSON format to STDOUT by
appending `--generate-only` to the list of the command line arguments:
```bash
gaiacli tx send <destination_cosmosaccaddr> 10faucetToken \
gaiacli tx send <sender_address> <recipient_address> 10faucetToken \
--chain-id=<chain_id> \
--from=<key_name> \
--generate-only > unsignedSendTx.json
```
@ -258,6 +255,7 @@ gaiacli tx sign \
::: tip Note
The `--generate-only` flag prevents `gaiacli` from accessing the local keybase.
Thus when such flag is supplied `<sender_key_name_or_address>` must be an address.
:::
You can validate the transaction's signatures by typing the following:

View File

@ -9,8 +9,8 @@ Install `go` by following the [official docs](https://golang.org/doc/install). R
```bash
mkdir -p $HOME/go/bin
echo "export GOPATH=$HOME/go" >> ~/.bash_profile
echo "export GOBIN=$GOPATH/bin" >> ~/.bash_profile
echo "export PATH=$PATH:$GOBIN" >> ~/.bash_profile
echo "export GOBIN=\$GOPATH/bin" >> ~/.bash_profile
echo "export PATH=\$PATH:\$GOBIN" >> ~/.bash_profile
source ~/.bash_profile
```

View File

@ -0,0 +1,34 @@
# KMS - Key Management System
[Tendermint KMS](https://github.com/tendermint/kms) is a key management service that allows separating key management from Tendermint nodes. In addition it provides other advantages such as:
- Improved security and risk management policies
- Unified API and support for various HSM (hardware security modules)
- Double signing protection (software or hardware based)
It is recommended that the KMS service runs in a separate physical hosts.
## Building
Detailed build instructions can be found [here](https://github.com/tendermint/kms#installation).
::: tip
When compiling the KMS, ensure you have enabled the applicable features:
:::
| Backend | Recommended Command line |
|-----------------------|---------------------------------------|
| YubiHSM | ```cargo build --features yubihsm``` |
| Ledger+Tendermint App | ```cargo build --features ledgertm``` |
## Configuration
A KMS can be configured in various ways:
### Using a YubiHSM
Detailed information on how to setup a KMS with YubiHSM2 can be found [here](https://github.com/tendermint/kms/blob/master/README.yubihsm.md)
### Using a Ledger device running the Tendermint app
Detailed information on how to setup a KMS with Ledger Tendermint App can be found [here](kms_ledger.md)

View File

@ -0,0 +1,113 @@
# Setting up Tendermint KMS + Ledger
::: danger Warning
The following instructions are a brief walkthrough and not a comprehensive guideline. You should consider and [research more about the security implications](./security.md) of activating an external KMS.
:::
::: danger Warning
KMS and Ledger Tendermint app are currently work in progress. Details may vary. Use with care under your own risk.
:::
## Tendermint Validator app (for Ledger devices)
You should be able to find the Tendermint app in Ledger Live.
*Note: at the moment, you might need to enable `developer mode` in Ledger Live settings*
## KMS configuration
In this section, we will configure a KMS to use a Ledger device running the Tendermint Validator App.
### Config file
You can find other configuration examples [here](https://github.com/tendermint/kms/blob/master/tmkms.toml.example)
- Create a `~/.tmkms/tmkms.toml` file with the following content (use an adequate `chain_id`)
```toml
# Example KMS configuration file
[[validator]]
addr = "tcp://localhost:26658" # or "unix:///path/to/socket"
chain_id = "gaia-11001"
reconnect = true # true is the default
secret_key = "~/.tmkms/secret_connection.key"
[[providers.ledgertm]]
chain_ids = ["gaia-11001"]
```
- Edit `addr` to point to your `gaiad` instance.
- Adjust `chain-id` to match your `.gaiad/config/config.toml` settings.
- `provider.ledgertm` has not additional parameters at the moment, however, it is important that you keep that header to enable the feature.
*Plug your Ledger device and open the Tendermint validator app.*
### Generate secret key
Now you need to generate secret_key:
```bash
tmkms keygen ~/.tmkms/secret_connection.key
```
### Retrieve validator key
The last step is to retrieve the validator key that you will use in `gaiad`.
Start the KMS:
```bash
tmkms start -c ~/.tmkms/tmkms.toml
```
The output should look similar to:
```text
07:28:24 [INFO] tmkms 0.3.0 starting up...
07:28:24 [INFO] [keyring:ledgertm:ledgertm] added validator key cosmosvalconspub1zcjduepqy53m39prgp9dz3nz96kaav3el5e0th8ltwcf8cpavqdvpxgr5slsd6wz6f
07:28:24 [INFO] KMS node ID: 1BC12314E2E1C29015B66017A397F170C6ECDE4A
```
The KMS may complain that it cannot connect to gaiad. That is fine, we will fix it in the next section.
This output indicates the validator key linked to this particular device is: `cosmosvalconspub1zcjduepqy53m39prgp9dz3nz96kaav3el5e0th8ltwcf8cpavqdvpxgr5slsd6wz6f`
Take note of the validator pubkey that appears in your screen. *We will use it in the next section.*
## Gaia configuration
You need to enable KMS access by editing `.gaiad/config/config.toml`. In this file, modify `priv_validator_laddr` to create a listening address/port or a unix socket in `gaiad`.
For example:
```toml
...
# TCP or UNIX socket address for Tendermint to listen on for
# connections from an external PrivValidator process
priv_validator_laddr = "tcp://127.0.0.1:26658"
...
```
Let's assume that you have set up your validator account and called it `kmsval`. You can tell gaiad the key that we've got in the previous section.
```bash
gaiad gentx --name kmsval --pubkey {.ValidatorKey}
```
Now start `gaiad`. You should see that the KMS connects and receives a signature request.
Once the ledger receives the first message, it will ask for confirmation that the values are adequate.
![](ledger_1.jpg)
Click the right button, if the height and round are correct.
After that, you will see that the KMS will start forwarding all signature requests to the ledger:
![](ledger_2.jpg)
::: danger Warning
The word TEST in the second picture, second line appears because they were taken on a pre-release version.
Once the app as been released in Ledger's app store, this word should NOT appear.
:::

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -25,6 +25,7 @@ Sentry nodes can be quickly spun up or change their IP addresses. Because the li
To setup your sentry node architecture you can follow the instructions below:
Validators nodes should edit their config.toml:
```bash
# Comma separated list of nodes to keep persistent connections to
# Do not add private peers to this list if you don't want them advertised
@ -35,6 +36,7 @@ pex = false
```
Sentry Nodes should edit their config.toml:
```bash
# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
# Example ID: 3e16af0cead27979e1fc3dac57d03df3c7a77acc@3.87.179.235:26656
@ -50,5 +52,5 @@ By default, uppercase environment variables with the following prefixes will rep
- `TM` (for Tendermint flags)
- `BC` (for democli or basecli flags)
For example, the environment variable `GA_CHAIN_ID` will map to the command line flag `--chain-id`. Note that while explicit command-line flags will take precedence over environment variables, environment variables will take precedence over any of your configuration files. For this reason, it's imperative that you lock down your environment such that any critical parameters are defined as flags on the CLI or prevent modification of any environment variables.
For example, the environment variable `GA_CHAIN_ID` will map to the command line flag `--chain-id`. Note that while explicit command-line flags will take precedence over environment variables, environment variables will take precedence over any of your configuration files. For this reason, it's imperative that you lock down your environment such that any critical parameters are defined as flags on the CLI or prevent modification of any environment variables.

View File

@ -6,6 +6,8 @@ Information on how to join the mainnet (`genesis.json` file and seeds) is held [
Before setting up your validator node, make sure you've already gone through the [Full Node Setup](../join-mainnet.md) guide.
If you plan to use a KMS (key management system), you should go through these steps first: [Using a KMS](kms/kms.md).
## What is a Validator?
[Validators](./overview.md) are responsible for committing new blocks to the blockchain through voting. A validator's stake is slashed if they become unavailable or sign blocks at the same height. Please read about [Sentry Node Architecture](./validator-faq.md#how-can-validators-protect-themselves-from-denial-of-service-attacks) to protect your node from DDOS attacks and to ensure high-availability.
@ -165,6 +167,15 @@ You should now see your validator in one of the Cosmos Hub explorers. You are lo
To be in the validator set, you need to have more total voting power than the 100th validator.
:::
## Halting Your Validator
When attempting to perform routine maintenance or planning for an upcoming coordinated
upgrade, it can be useful to have your validator systematically and gracefully halt.
You can achieve this by either setting the `halt-height` to the height at which
you want your node to shutdown or by passing the `--halt-height` flag to `gaiad`.
The node will shutdown with a zero exit code at that given height after committing
the block.
## Common Problems
### Problem #1: My validator has `voting_power: 0`

View File

@ -6,7 +6,18 @@ The bank module emits the following events/tags:
### MsgSend
| Key | Value |
|-----------|---------------------------|
| sender | {senderAccountAddress} |
| recipient | {recipientAccountAddress} |
| Key | Value |
|-------------|---------------------------|
| `action` | `send` |
| `category` | `bank` |
| `sender` | {senderAccountAddress} |
| `recipient` | {recipientAccountAddress} |
### MsgMultiSend
| Key | Value |
|-------------|---------------------------|
| `action` | `multisend` |
| `category` | `bank` |
| `sender` | {senderAccountAddress} |
| `recipient` | {recipientAccountAddress} |

View File

@ -6,8 +6,9 @@ The crisis module emits the following events/tags:
### MsgVerifyInvariance
| Key | Value |
|-----------|---------------------|
| action | verify_invariant |
| sender | {message-sender} |
| invariant | {invariant-route} |
| Key | Value |
|-------------|--------------------|
| `action` | `verify_invariant` |
| `category` | `crisis` |
| `sender` | {message-sender} |
| `invariant` | {invariant-route} |

View File

@ -6,25 +6,25 @@ The distribution module emits the following events/tags:
### MsgSetWithdrawAddress
| Key | Value |
|-----------|---------------------------|
| delegator | {delegatorAccountAddress} |
### MsgWithdrawDelegatorRewardsAll
| Key | Value |
|-----------|---------------------------|
| delegator | {delegatorAccountAddress} |
| Key | Value |
|------------|---------------------------|
| `action` | `set_withdraw_address` |
| `category` | `distribution` |
| `sender` | {delegatorAccountAddress} |
### MsgWithdrawDelegatorReward
| Key | Value |
|------------------|---------------------------|
| delegator | {delegatorAccountAddress} |
| source-validator | {srcOperatorAddress} |
| Key | Value |
|--------------------|-----------------------------|
| `action` | `withdraw_delegator_reward` |
| `category` | `distribution` |
| `sender` | {delegatorAccountAddress} |
| `source-validator` | {srcOperatorAddress} |
### MsgWithdrawValidatorRewardsAll
### MsgWithdrawValidatorCommission
| Key | Value |
|------------------|----------------------|
| source-validator | {srcOperatorAddress} |
| Key | Value |
|------------|---------------------------------|
| `action` | `withdraw_validator_commission` |
| `category` | `distribution` |
| `sender` | {srcOperatorAddress} |

View File

@ -4,35 +4,38 @@ The governance module emits the following events/tags:
## EndBlocker
| Key | Value |
|-----------------|------------------------------------------------------|
| proposal-result | proposal-passed\|proposal-rejected\|proposal-dropped |
| Key | Value |
|-------------------|------------------------------------------------------------|
| `proposal-result` | `proposal-passed`\|`proposal-rejected`\|`proposal-dropped` |
## Handlers
### MsgSubmitProposal
| Key | Value |
|-------------------------|--------------------------|
| action | proposal-vote |
| proposer | {proposerAccountAddress} |
| proposal-id | {proposalID} |
| voting-period-start [0] | {proposalID} |
| Key | Value |
|---------------------------|--------------------------|
| `action` | `submit_proposal` |
| `category` | `governance` |
| `sender` | {proposerAccountAddress} |
| `proposal-id` | {proposalID} |
| `voting-period-start` [0] | {proposalID} |
* [0] Tag only emitted if the voting period starts during the submission.
### MsgVote
| Key | Value |
|-------------|-----------------------|
| action | proposal-vote |
| voter | {voterAccountAddress} |
| proposal-id | {proposalID} |
| Key | Value |
|---------------|-----------------------|
| `action` | `vote` |
| `category` | `governance` |
| `sender` | {voterAccountAddress} |
| `proposal-id` | {proposalID} |
### MsgDeposit
| Key | Value |
|-------------|---------------------------|
| action | proposal-vote |
| depositor | {depositorAccountAddress} |
| proposal-id | {proposalID} |
| Key | Value |
|---------------|---------------------------|
| `action` | `deposit` |
| `category` | `governance` |
| `sender` | {depositorAccountAddress} |
| `proposal-id` | {proposalID} |

View File

@ -8,7 +8,7 @@ The IBC protocol creates a mechanism by which two replicated fault-tolerant stat
The IBC protocol assumes that multiple applications are running on their own blockchain with their own state and own logic. Communication is achieved over an ordered message queue primitive, allowing the creation of complex inter-chain processes without trusted third parties.
The message packets are not signed by one psuedonymous account, or even multiple, as in multi-signature sidechain implementations. Rather, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains.
The message packets are not signed by one pseudonymous account, or even multiple, as in multi-signature sidechain implementations. Rather, IBC assigns authorization of the packets to the source blockchain's consensus algorithm, performing light-client style verification on the destination chain. The Byzantine-fault-tolerant properties of the underlying blockchains are preserved: a user transferring assets between two chains using IBC must trust only the consensus algorithms of both chains.
In this paper, we define a process of posting block headers and Merkle tree proofs to enable secure verification of individual packets. We then describe how to combine these packets into a messaging queue to guarantee ordered delivery. We then explain how to handle packet receipts (response/error) on the source chain, which enables the creation of asynchronous RPC-like protocols on top of IBC. Finally, we detail some optimizations and how to handle Byzantine blockchains.

View File

@ -6,7 +6,8 @@ The slashing module emits the following events/tags:
### MsgUnjail
| Key | Value |
|-----------|----------------------------|
| action | validator-unjailed |
| validator | {validatorOperatorAddress} |
| Key | Value |
|------------|----------------------------|
| `action` | `unjail` |
| `category` | `slashing` |
| `sender` | {validatorOperatorAddress} |

View File

@ -4,55 +4,62 @@ The staking module emits the following events/tags:
## EndBlocker
| Key | Value |
|-----------------------|-------------------------------------------|
| action | complete-unbonding\|complete-redelegation |
| delegator | {delegatorAccountAddress} |
| source-validator | {srcOperatorAddress} |
| destination-validator | {dstOperatorAddress} |
| Key | Value |
|-------------------------|-----------------------------------------------|
| `action` | `complete-unbonding`\|`complete-redelegation` |
| `category` | `staking` |
| `delegator` | {delegatorAccountAddress} |
| `source-validator` | {srcOperatorAddress} |
| `destination-validator` | {dstOperatorAddress} |
## Handlers
### MsgCreateValidator
| Key | Value |
|-----------------------|----------------------|
| destination-validator | {dstOperatorAddress} |
| moniker | {validatorMoniker} |
| identity | {validatorIdentity} |
| Key | Value |
|------------|----------------------|
| `action` | `create_validator` |
| `category` | `staking` |
| `sender` | {dstOperatorAddress} |
### MsgEditValidator
| Key | Value |
|-----------------------|----------------------|
| destination-validator | {dstOperatorAddress} |
| moniker | {validatorMoniker} |
| identity | {validatorIdentity} |
| Key | Value |
|------------|----------------------|
| `action` | `edit_validator` |
| `category` | `staking` |
| `sender` | {dstOperatorAddress} |
### MsgDelegate
| Key | Value |
|-----------------------|-------------------------------------------|
| delegator | {delegatorAccountAddress} |
| destination-validator | {dstOperatorAddress} |
| Key | Value |
|-------------------------|---------------------------|
| `action` | `delegate` |
| `category` | `staking` |
| `sender` | {delegatorAccountAddress} |
| `destination-validator` | {dstOperatorAddress} |
### MsgBeginRedelegate
| Key | Value |
|-----------------------|-------------------------------------------|
| delegator | {delegatorAccountAddress} |
| source-validator | {srcOperatorAddress} |
| destination-validator | {dstOperatorAddress} |
| end-time [0] | {delegationFinishTime} |
| Key | Value |
|-------------------------|---------------------------|
| `action` | `begin_redelegate` |
| `category` | `staking` |
| `sender` | {delegatorAccountAddress} |
| `source-validator` | {srcOperatorAddress} |
| `destination-validator` | {dstOperatorAddress} |
| `end-time` [0] | {delegationFinishTime} |
* [0] Time is formatted in the RFC3339 standard
### MsgUndelegate
| Key | Value |
|------------------|---------------------------|
| delegator | {delegatorAccountAddress} |
| source-validator | {srcOperatorAddress} |
| end-time [0] | {delegationFinishTime} |
| Key | Value |
|--------------------|---------------------------|
| `action` | `begin_unbonding` |
| `category` | `staking` |
| `sender` | {delegatorAccountAddress} |
| `source-validator` | {srcOperatorAddress} |
| `end-time` [0] | {delegationFinishTime} |
* [0] Time is formatted in the RFC3339 standard

View File

@ -0,0 +1,19 @@
# 客户端
本节说明包含区块链 SDK 的客户端的信息。
> *注*:此部分仍在开发中。
##轻客户端
轻客户端使用户能够与您的应用程序进行交互,且无需下载整个状态历史记录,但具有良好的安全性。
- [轻客户端概述](./lite/README.md)
- [启动轻客户端服务器](./lite/getting_started.md)
- [轻客户端规范](./lite/specification.md)
##其他客户端
- [区块链 SDK 的 CLI](./cli.md)
- [服务提供商文档](./service-providers.md)

View File

@ -0,0 +1,4 @@
# CLI
> TODO: Rewrite this section to explain how CLI works for a generic SDK app.

View File

@ -0,0 +1,60 @@
# 轻客户端概览
**点击[这里](https://cosmos.network/rpc/)查看Cosmos SDK 轻客户端 RPC 文档**
## 简介
轻客户端允许客户端(例如移动电话)从任何全节点接收区块链状态的证明。 轻客户端不必信任任何全节点,因为他们能够验证他们收到的任何证明,因此全节点不能对网络状态撒谎。
轻客户端可以用最低的带宽、计算和存储资源提供与全节点相同的安全性。 同时,它还可以根据用户的配置提供模块化功能。 这些出色的功能允许开发人员构建完全安全、高效且可用的移动应用、网站或任何其他应用程序,而无需部署或维护任何完整的区块链节点。
### 什么是轻节点
Cosmos SDK 轻节点Gaia-lite分为两个独立的组件。 第一个组件对于任何基于 Tendermint 的应用程序都是通用的,它处理区块头相关的安全性和连接性,并验证来自全节点的证明与本地可信验证人集合的对比。 此外它暴露与任何Tendermint 核心节点完全相同的API。 第二个组件专用于 Cosmos Hub`gaiad`),它作为查询端点工作,并公开特定于应用程序的功能,这些功能可以是任意的。 针对应用程序状态的所有查询都必须通过查询端点。 查询端点的优点是它可以验证应用程序返回的证据。
### 高层体系结构
想要为 Cosmos Hub或任何其他 zone构建第三方客户端应用程序的应用程序开发人员应根据其规范 API 构建。 该API 是多个部分的组合。 所有 zone 都必须暴露ICS0TendermintAPI。 除此之外,任何 zone 都可以自由选择模块 API的任意组合具体取决于状态机使用的模块。 Cosmos Hub最初将支持[ICS0](https://cosmos.network/rpc/#/ICS0) (TendermintAPI)、 [ICS1](https://cosmos.network/rpc/#/ICS1) (KeyAPI)、 [ICS20](https://cosmos.network/rpc/#/ICS20) (TokenAPI)、 [ICS21](https://cosmos.network/rpc/#/ICS21) (StakingAPI)、 [ICS22](https://cosmos.network/rpc/#/ICS22) (GovernanceAPI) 和 [ICS23](https://cosmos.network/rpc/#/ICS23) (SlashingAPI)。
![high-level](../../../../clients/lite/pics/high-level.png)
预计所有应用程序仅依赖于 Gaia-lite 运行。 Gaia-lite 是唯一一款围绕 zone API 提供稳定性保证的软件。
### 对比
ABCI 的全节点与其轻客户端的区别在于以下方面:
| | Full Node | 轻客户端 | Description |
| ------------------------------- | --------------- | ------------- | ------------------------------------------------------------ |
| 执行并验证交易 | Yes | No | 全节点将执行并验证所有交易而Gaia-lite则不会 |
| 验证和存储区块 | Yes | No | 全节点将验证并保存所有块而Gaia-lite则不会 |
| 参与共识 | Yes | No | 只有当全节点是验证人时,它才会参与共识。 Lite节点永远不会参与共识。 |
| 带宽开销 | 巨大 | 很小 | 全节点将接收所有块。 如果带宽有限,它将落后于主网络。 更重要的是,如果碰巧是验证人,它将减缓共识过程。 轻客户端需要很少的带宽, 只有在提供本地请求时,才会占用带宽。 |
| 计算资源 | 巨大 | 很小 | 全节点将执行所有交易并验证所有块,这需要大量的计算资源 |
| 存储资源 | 巨大 | 很小 | 全节点将保存所有块和 ABCI 状态而Gaia-lite只保存验证人集合和一些检查点。 |
| 电力资源 | 巨大 | 很小 | 全节点必须在具有高性能并能一直运行的机器上部署,因此功耗将是巨大的。 Gaia-lite可以部署在与用户应用程序相同的机器上也可以部署在独立但性能较差的机器上。 此外Lite客户端可以在必要时随时关闭。所以Gaia-lite只消耗很少的功率即使移动设备也能满足功率需求。 |
| 提供的 APIs | 所有cosmos APIs | 部分模块 APIs | 全节点支持所有cosmos API。 Gaia-lite 根据用户的配置提供模块化API。 |
| 安全等级 | 高 | 高 | 全节点将自行验证所有交易和块。 轻型客户端无法执行此操作,但它可以查询来自其他全节点的任何数据并独立验证数据。 因此,全节点和轻型客户端都不需要信任任何第三方节点,它们都可以实现高安全性。 |
根据上表Gaia-lite 可以满足所有用户的功能和安全需求,但只需要很少的带宽、计算、存储和电力资源。
## 安全实现
### 可信验证人集合
Gaia-lite的基本设计理念遵循两个规则
1. **不信任任何区块链节点,包括验证人节点和其他全节点**
2. **只信任整个验证人集合**
原始的可信验证人集应该预先放置到其信任库中,通常这个验证人集来自 genesis 文件。 在运行时期间,如果 Gaia-lite 检测到不同的验证人集,它将验证它并将可信的验证人集保存到信任库中。
![validator-set-change](../../../../clients/lite/pics/validatorSetChange.png)
### 信任传播
从上面的小节中,我们了解了如何获得可信验证器集以及 LCD 如何跟踪验证人集演化。 验证人集是信任的基础,信任可以传播到其他区块链数据,例如块和交易。 传播架构如下所示:
![change-process](../../../../clients/lite/pics/trustPropagate.png)
通常,通过可信验证人集,轻客户端可以验证包含所有预提交数据和块头数据的每个提交块。 此时块哈希、数据哈希和应用哈希是可信的。 基于此和默克尔证明,所有交易数据和 ABCI 状态也可以被验证。

View File

@ -0,0 +1,23 @@
# 入门
要启动 REST 服务器,我们需要指定以下参数:
| 参数 | 类型 | 默认值 | 必填 | 描述 |
| ----------- | --------- | ----------------------- | ----- | ---------------------------- |
| chain-id | string | null | true | 要链接全节点的 chain id |
| node | URL | "tcp://localhost:46657" | true | 要链接全节点的地址和端口号 |
| laddr | URL | "tcp://localhost:1317" | true | 提供 REST 服务的地址和端口号 |
| trust-node | bool | "false" | true | 是否信任 LCD 连接的全节点 |
| trust-store | DIRECTORY | "$HOME/.lcd" | false | 保存检查点和验证人集的目录 |
示例:
```bash
gaiacli rest-server --chain-id=test \
--laddr=tcp://localhost:1317 \
--node tcp://localhost:26657 \
--trust-node=false
```
有关Gaia-Lite RPC的更多信息请参阅 [swagger documentation](https://cosmos.network/rpc/)

View File

@ -0,0 +1,183 @@
# 规范
该规范描述了如何实现 LCD。 LCD 支持模块化 API。 目前仅支持ICS0TendermintAPIICS1密钥API和ICS20Key API。 如有必要后续可以包含更多API。
## 构建并验证 ABCI 状态的证明
众所周知,基于 cosmos-sdk 的应用程序的存储包含多个子库。 每个子目录由 IAVL 存储实现。 这些子组件由简单的 Merkle 树组成。 创建树时,我们需要从这些子库中提取名字、高度和存储根哈希以构建一组简单的 Merkle 叶节点,然后计算从叶节点到根的哈希。 简单 Merkle 树的根哈希是 AppHash它将包含在块头中。
![Simple Merkle Tree](../../../../clients/lite/pics/simpleMerkleTree.png)
正如我们在[LCD信任传播](https://github.com/irisnet/cosmos-sdk/tree/bianjie/lcd_spec/docs/spec/lcd#trust-propagation)中所讨论的那样,可以通过检查针对可信验证人集的投票权来验证 AppHash。 这里我们只需要建立从 ABCI 状态到 AppHash 的证明。 证据包含两部分:
* IAVL 证明
* 子库到 AppHash 的证明
### IAVL 证明
证明有两种类型:存在证明和缺席证明。 如果查询密钥存在于 IAVL 存储中,则它返回键值及其存在证明。 另一方面,如果密钥不存在,那么它只返回缺席证明,这可以证明密钥肯定不存在。
### IAVL 存在证明
```go
type CommitID struct {
Version int64
Hash []byte
}
type storeCore struct {
CommitID CommitID
}
type MultiStoreCommitID struct {
Name string
Core storeCore
}
type proofInnerNode struct {
Height int8
Size int64
Version int64
Left []byte
Right []byte
}
type KeyExistsProof struct {
MultiStoreCommitInfo []MultiStoreCommitID // 所有子库提交id
StoreName string // 当前子库名字
Height int64 // 当前子库提交高度
RootHash cmn.HexBytes // 此 IAVL 树的根哈希
Version int64 // 此 IAVL 树中 key-value 的版本号
InnerNodes []proofInnerNode // 从根节点到 key-value 叶子节点的路径
}
```
存在证据的数据结构如上所示。 构建和验证存在证明的过程如下所示:
![Exist Proof](../../../../clients/lite/pics/existProof.png)
构建证明的步骤:
* 从根节点访问IAVL树
* 记录 InnerNodes 中的访问节点
* 找到目标叶节点后,将叶节点版本赋值给证明版本
* 将当前 IAVL 树高赋值给证明高度
* 将当前 IAVL 树根哈希赋值给证明根哈希
* 将当前的子目录名称赋值给证明 StoreName
* 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
验证证明的步骤:
* 使用证明版本中的键、值构建叶节点
* 计算叶节点哈希
* 将哈希值分配给第一个 innerNode 的 rightHash然后计算第一个 innerNode 哈希值
* 传播哈希计算过程。 如果先前的 innerNode 是下一个 innerNode 的左子节点,则将先前的 innerNode 散列分配给下一个 innerNode 的左散列。否则,将先前的 innerNode 散列分配给下一个innerNode的右散列
* 最后 innerNode 的哈希应该等于此证明的根哈希, 否则证明无效。
### IAVL 缺席证明
众所周知,所有 IAVL 叶节点都按每个叶节点的密钥排序。 因此,我们可以在 IAVL 树的整个密钥集中计算出目标密钥的位置。 如下图所示,我们可以找到左键和右键。 如果我们可以证明左键和右键肯定存在,并且它们是相邻的节点,那么目标密钥肯定不存在。
![Absence Proof1](../../../../clients/lite/pics/absence1.png)
如果目标密钥大于最右边的叶节点或小于最左边的叶子节点,则目标密钥肯定不存在。
![Absence Proof2](../../../../clients/lite/pics/absence2.png)![Absence Proof3](../../../../clients/lite/pics/absence3.png)
```go
type proofLeafNode struct {
KeyBytes cmn.HexBytes
ValueBytes cmn.HexBytes
Version int64
}
type pathWithNode struct {
InnerNodes []proofInnerNode
Node proofLeafNode
}
type KeyAbsentProof struct {
MultiStoreCommitInfo []MultiStoreCommitID
StoreName string
Height int64
RootHash cmn.HexBytes
Left *pathWithNode // Proof the left key exist
Right *pathWithNode //Proof the right key exist
}
```
以上是缺席证明的数据结构。 构建证据的步骤:
* 从根节点访问IAVL树
* 获取整个密钥集中密钥的对应索引标记为INDEX
* 如果返回的索引等于0则右索引应为0且左节点不存在
* 如果返回的索引等于整个密钥集的大小则左节点索引应为INDEX-1且右节点不存在
* 否则右节点索引应为INDEX左节点索引应为INDEX-1
* 将当前 IAVL 树高赋值给证明高度
* 将当前 IAVL 树根哈希赋值给证明根哈希
* 将当前的子目录名称赋值给证明 StoreName
* 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
验证证明的步骤:
* 如果只存在右节点,请验证其存在的证明,并验证它是否是最左侧的节点
* 如果仅存在左节点,请验证其存在的证据,并验证它是否是最右侧的节点
* 如果右节点和左节点都存在,请验证它们是否相邻
### Substores 到 AppHash 的证明
在验证了 IAVL 证明之后,我们就可以开始验证针对 AppHash 的 substore 证明。 首先,迭代 MultiStoreCommitInfo 并通过证明 StoreName 找到 substore commitID。 验证 commitID 中的哈希是否等于证明根哈希,如果不相等则证明无效。 然后通过 substore name 的哈希对 substore commitInfo 数组进行排序。 最后,使用所有 substore commitInfo 数组构建简单的 Merkle 树,并验证 Merkle 根哈希值是否等于appHash。
![substore proof](../../../../clients/lite/pics/substoreProof.png)
```go
func SimpleHashFromTwoHashes(left []byte, right []byte) []byte {
var hasher = ripemd160.New()
err := encodeByteSlice(hasher, left)
if err != nil {
panic(err)
}
err = encodeByteSlice(hasher, right)
if err != nil {
panic(err)
}
return hasher.Sum(nil)
}
func SimpleHashFromHashes(hashes [][]byte) []byte {
// Recursive impl.
switch len(hashes) {
case 0:
return nil
case 1:
return hashes[0]
default:
left := SimpleHashFromHashes(hashes[:(len(hashes)+1)/2])
right := SimpleHashFromHashes(hashes[(len(hashes)+1)/2:])
return SimpleHashFromTwoHashes(left, right)
}
}
```
## 根据验证人集验证区块头
上面的小节中经常提到 appHash但可信的appHash来自哪里 实际上appHash 存在于区块头中,因此接下来我们需要针对 LCD 可信验证人集验证特定高度的区块头。 验证流程如下所示:
![commit verification](../../../../clients/lite/pics/commitValidation.png)
当可信验证人集与区块头不匹配时,我们需要尝试将验证人集更新为此块的高度。 LCD 有一条规则即每个验证人集的变化不应超过1/3投票权。 如果目标验证人集的投票权变化超过1/3则与可信验证人集进行比较。 我们必须验证,在目标验证人集之前是否存在隐含的验证人集变更。 只有当所有验证人集变更都遵循这条规则时,才能完成验证人集的更新。
例如:
![Update validator set to height](../../../../clients/lite/pics/updateValidatorToHeight.png)
* 更新到 10000失败变更太大
* 更新到 5050失败变更太大
* 更新至 2575成功
* 更新至 5050成功
* 更新到 10000失败变更太大
* 更新至 7525成功
* 更新至 10000成功

Some files were not shown because too many files have changed in this diff Show More