Merge remote-tracking branch 'origin/develop' into rigel/spec-staking

This commit is contained in:
rigelrozanski 2018-06-13 20:50:59 -07:00
commit 14c1ff27f3
144 changed files with 8737 additions and 2323 deletions

View File

@ -27,12 +27,6 @@ jobs:
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- run:
name: linter
command: |
export PATH="$GOBIN:$PATH"
go get -u github.com/tendermint/lint/golint
go get -u github.com/alecthomas/gometalinter
- run:
name: binaries
command: |
@ -63,6 +57,12 @@ jobs:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: Get metalinter
command: |
export PATH="$GOBIN:$PATH"
go get -u github.com/tendermint/lint/golint
go get -u github.com/alecthomas/gometalinter
- run:
name: Lint source
command: |

View File

@ -1,8 +1,12 @@
<!-- Thanks for filing a PR! Before hitting the button, please check the following items.-->
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v ✰ Thanks for creating a PR! ✰
v Before smashing the submit button please review the checkboxes.
v If a checkbox is n/a - please still include it but + a little note why
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
* [ ] Updated all relevant documentation in docs
* [ ] Updated all code comments where relevant
* [ ] Wrote tests
* [ ] Updated CHANGELOG.md
* [ ] Updated Basecoin / other examples
* [ ] Squashed related commits and prefixed with PR number per [coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)
* [ ] Updated Gaia/Examples
* [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))

3
.gitignore vendored
View File

@ -14,6 +14,7 @@ docs/_build
# Data - ideally these don't exist
examples/basecoin/app/data
baseapp/data/*
client/lcd/keys/*
# Testing
coverage.txt
@ -26,4 +27,4 @@ profile.out
vagrant
# Graphviz
dependency-graph.png
dependency-graph.png

View File

@ -1,45 +1,38 @@
# Changelog
## Pending
## 0.20.0
*TBD*
BREAKING CHANGES
* [cli] rearranged commands under subcommands
* [stake] remove Tick and add EndBlocker
* Change default ports from 466xx to 266xx
## 0.19.0
*June 13, 2018*
BREAKING CHANGES
* msg.GetSignBytes() now returns bech32-encoded addresses in all cases
* [lcd] REST end-points now include gas
FEATURES
* [x/auth] Added AccountNumbers to BaseAccount and StdTxs to allow for replay protection with account pruning
IMPROVEMENTS
* bank module uses go-wire codec instead of 'encoding/json'
* auth module uses go-wire codec instead of 'encoding/json'
* revised use of endblock and beginblock
* export command now writes current validator set for Tendermint
* [tests] Application module tests now use a mock application
* [gaiacli] Fix error message when account isn't found when running gaiacli account
* [lcd] refactored to eliminate use of global variables, and interdependent tests
* [x/stake] More stake tests added to test ByPower index
FIXES
* [cli] fixed cli-bash tests
* [ci] added cli-bash tests
* [basecoin] updated basecoin for stake and slashing
* [docs] fixed references to old cli commands
## 0.18.1
BREAKING CHANGES
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
* StdTx (and its related stuff i.e. StdSignDoc, etc)
* StdFee
* StdSignature
* Account interface
* Related to this organization, I also:
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
* Switch to bech32cosmos on all human readable inputs and outputs
BUG FIXES
* auto-sequencing transactions correctly
* query sequence via account store
* fixed duplicate pub_key in stake.Validator
* Fixes consensus fault on testnet - see postmortem [here](https://github.com/cosmos/cosmos-sdk/issues/1197#issuecomment-396823021)
* [x/stake] bonded inflation removed, non-bonded inflation partially implemented
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
* [lcd] fixed tx indexing/querying
* [cli] Added `--gas` flag to specify transaction gas limit
* [gaia] Registered slashing message handler
* [x/slashing] Set signInfo.StartHeight correctly for newly bonded validators
FEATURES
* [docs] Reorganize documentation
@ -47,6 +40,8 @@ FEATURES
## 0.18.0
*June 9, 2018*
BREAKING CHANGES
* [stake] candidate -> validator throughout (details in refactor comment)
@ -64,6 +59,20 @@ BREAKING CHANGES
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
* Introduction of PoolShares type within validators,
replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
* StdTx (and its related stuff i.e. StdSignDoc, etc)
* StdFee
* StdSignature
* Account interface
* Related to this organization, I also:
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
* [cli] rearranged commands under subcommands
* [stake] remove Tick and add EndBlocker
* Switch to bech32cosmos on all human readable inputs and outputs
FEATURES
@ -80,12 +89,60 @@ FEATURES
* [stake] Added REST API
* [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean
BUG FIXES
* Auto-sequencing now works correctly
* [stake] staking delegator shares exchange rate now relative to equivalent-bonded-tokens the validator has instead of bonded tokens
^ this is important for unbonded validators in the power store!
* [cli] fixed cli-bash tests
* [ci] added cli-bash tests
* [basecoin] updated basecoin for stake and slashing
* [docs] fixed references to old cli commands
* [docs] Downgraded Swagger to v2 for downstream compatibility
* auto-sequencing transactions correctly
* query sequence via account store
* fixed duplicate pub_key in stake.Validator
* Auto-sequencing now works correctly
* [gaiacli] Fix error message when account isn't found when running gaiacli account
## 0.17.5
*June 5, 2018*
Update to Tendermint v0.19.9 (Fix evidence reactor, mempool deadlock, WAL panic,
memory leak)
## 0.17.4
*May 31, 2018*
Update to Tendermint v0.19.7 (WAL fixes and more)
## 0.17.3
*May 29, 2018*
Update to Tendermint v0.19.6 (fix fast-sync halt)
## 0.17.5
*June 5, 2018*
Update to Tendermint v0.19.9 (Fix evidence reactor, mempool deadlock, WAL panic,
memory leak)
## 0.17.4
*May 31, 2018*
Update to Tendermint v0.19.7 (WAL fixes and more)
## 0.17.3
*May 29, 2018*
Update to Tendermint v0.19.6 (fix fast-sync halt)
## 0.17.2
@ -125,6 +182,7 @@ BUG FIXES
* Auto-sequencing now works correctly
## 0.16.0 (May 14th, 2018)
BREAKING CHANGES
@ -159,12 +217,14 @@ BUG FIXES
* Gaia now uses stake, ported from github.com/cosmos/gaia
## 0.15.1 (April 29, 2018)
IMPROVEMENTS:
* Update Tendermint to v0.19.1 (includes many rpc fixes)
## 0.15.0 (April 29, 2018)
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use

33
Gopkg.lock generated
View File

@ -170,8 +170,8 @@
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
version = "v1.2.0"
[[projects]]
name = "github.com/pkg/errors"
@ -197,8 +197,8 @@
".",
"mem"
]
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
version = "v1.1.0"
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
version = "v1.1.1"
[[projects]]
name = "github.com/spf13/cast"
@ -236,8 +236,8 @@
"assert",
"require"
]
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
branch = "master"
@ -256,7 +256,7 @@
"leveldb/table",
"leveldb/util"
]
revision = "5d6fca44a948d2be89a9702de7717f0168403d3d"
revision = "e2150783cd35f5b607daca48afd8c57ec54cc995"
[[projects]]
name = "github.com/tendermint/abci"
@ -267,8 +267,8 @@
"server",
"types"
]
revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4"
version = "v0.11.0-rc4"
revision = "198dccf0ddfd1bb176f87657e3286a05a6ed9540"
version = "v0.12.0"
[[projects]]
branch = "master"
@ -330,6 +330,7 @@
"p2p/conn",
"p2p/pex",
"p2p/upnp",
"privval",
"proxy",
"rpc/client",
"rpc/core",
@ -344,11 +345,9 @@
"state/txindex/kv",
"state/txindex/null",
"types",
"types/priv_validator",
"version"
]
revision = "b5baab0238c9ec26e3b2d229b0243f9ff9220bdb"
version = "v0.20.0-rc3"
revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601"
[[projects]]
branch = "develop"
@ -366,7 +365,7 @@
"merkle",
"merkle/tmhash"
]
revision = "44f1bdb0d55cc6527e38d0a7aab406e2580f56a4"
revision = "0c98d10b4ffbd87978d79c160e835b3d3df241ec"
[[projects]]
branch = "master"
@ -382,7 +381,7 @@
"ripemd160",
"salsa20/salsa"
]
revision = "5ba7f63082460102a45837dbd1827e10f9479ac0"
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
[[projects]]
branch = "master"
@ -396,13 +395,13 @@
"internal/timeseries",
"trace"
]
revision = "1e491301e022f8f977054da4c2d852decd59571f"
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
revision = "bff228c7b664c5fce602223a05fb708fd8654986"
[[projects]]
name = "golang.org/x/text"
@ -463,6 +462,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "ccb2ab7644a38c2d0326280582f758256e37fc98c3ef0403581e3b85cff42188"
inputs-digest = "d02a24bcfd8bded901e1b154e19b81ff797d3921046ede19d1d11eed61e871e7"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -54,7 +54,7 @@
[[constraint]]
name = "github.com/tendermint/abci"
version = "=0.11.0-rc4"
version = "=0.12.0"
[[constraint]]
name = "github.com/tendermint/go-crypto"
@ -70,7 +70,7 @@
[[constraint]]
name = "github.com/tendermint/tendermint"
version = "=0.20.0-rc3"
revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601"
[[override]]
name = "github.com/tendermint/tmlibs"

View File

@ -46,6 +46,9 @@ install_examples:
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democoind
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democli
install_debug:
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
dist:
@bash publish/dist.sh
@bash publish/publish.sh
@ -92,6 +95,9 @@ test_cli:
test_unit:
@go test $(PACKAGES_NOCLITEST)
test_race:
@go test -race $(PACKAGES_NOCLITEST)
test_cover:
@bash tests/test_cover.sh
@ -154,4 +160,4 @@ remotenet-status:
# 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: build build_examples install install_examples dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update remotenet-start remotenet-stop remotenet-status
.PHONY: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update remotenet-start remotenet-stop remotenet-status

View File

@ -18,6 +18,14 @@ master | [![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master.s
**Note**: Requires [Go 1.10+](https://golang.org/dl/)
## Testnet
For more information on connecting to the testnet, see
[cmd/gaia/testnets](/cmd/gaia/testnets)
For the latest status of the testnet, see the [status
file](/cmd/gaia/testnets/STATUS.md).
## Overview

View File

@ -193,7 +193,7 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
// TODO: we don't actually need the main store here
main := app.cms.GetKVStore(mainKey)
if main == nil {
return errors.New("BaseApp expects MultiStore with 'main' KVStore")
return errors.New("baseapp expects MultiStore with 'main' KVStore")
}
// XXX: Do we really need the header? What does it have that we want
@ -216,11 +216,11 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
}
err := proto.Unmarshal(headerBytes, &header)
if err != nil {
return errors.Wrap(err, "Failed to parse Header")
return errors.Wrap(err, "failed to parse Header")
}
lastVersion := lastCommitID.Version
if header.Height != lastVersion {
errStr := fmt.Sprintf("Expected db://%s.Height %v but got %v", dbHeaderKey, lastVersion, header.Height)
errStr := fmt.Sprintf("expected db://%s.Height %v but got %v", dbHeaderKey, lastVersion, header.Height)
return errors.New(errStr)
}
}
@ -468,10 +468,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
if r := recover(); r != nil {
switch r.(type) {
case sdk.ErrorOutOfGas:
log := fmt.Sprintf("Out of gas in location: %v", r.(sdk.ErrorOutOfGas).Descriptor)
log := fmt.Sprintf("out of gas in location: %v", r.(sdk.ErrorOutOfGas).Descriptor)
result = sdk.ErrOutOfGas(log).Result()
default:
log := fmt.Sprintf("Recovered: %v\nstack:\n%v", r, string(debug.Stack()))
log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack()))
result = sdk.ErrInternal(log).Result()
}
}

View File

@ -10,7 +10,7 @@ import (
func RunForever(app abci.Application) {
// Start the ABCI server
srv, err := server.NewServer("0.0.0.0:46658", "socket", app)
srv, err := server.NewServer("0.0.0.0:26658", "socket", app)
if err != nil {
cmn.Exit(err.Error())
}

View File

@ -30,12 +30,12 @@ func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit,
}
if res.CheckTx.Code != uint32(0) {
return res, errors.Errorf("CheckTx failed: (%d) %s",
return res, errors.Errorf("checkTx failed: (%d) %s",
res.CheckTx.Code,
res.CheckTx.Log)
}
if res.DeliverTx.Code != uint32(0) {
return res, errors.Errorf("DeliverTx failed: (%d) %s",
return res, errors.Errorf("deliverTx failed: (%d) %s",
res.DeliverTx.Code,
res.DeliverTx.Log)
}
@ -75,7 +75,7 @@ func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res [
}
resp := result.Response
if resp.Code != uint32(0) {
return res, errors.Errorf("Query failed: (%d) %s", resp.Code, resp.Log)
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}
return resp.Value, nil
}
@ -95,7 +95,7 @@ func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) {
info, err := keybase.Get(name)
if err != nil {
return nil, errors.Errorf("No key for: %s", name)
return nil, errors.Errorf("no key for: %s", name)
}
return info.PubKey.Address(), nil
@ -107,14 +107,17 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
// build the Sign Messsage from the Standard Message
chainID := ctx.ChainID
if chainID == "" {
return nil, errors.Errorf("Chain ID required but not specified")
return nil, errors.Errorf("chain ID required but not specified")
}
accnum := ctx.AccountNumber
sequence := ctx.Sequence
signMsg := auth.StdSignMsg{
ChainID: chainID,
Sequences: []int64{sequence},
Msg: msg,
Fee: auth.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas?
ChainID: chainID,
AccountNumbers: []int64{accnum},
Sequences: []int64{sequence},
Msg: msg,
Fee: auth.NewStdFee(ctx.Gas, sdk.Coin{}), // TODO run simulate to estimate gas?
}
keybase, err := keys.GetKeyBase()
@ -130,9 +133,10 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
return nil, err
}
sigs := []auth.StdSignature{{
PubKey: pubkey,
Signature: sig,
Sequence: sequence,
PubKey: pubkey,
Signature: sig,
AccountNumber: accnum,
Sequence: sequence,
}}
// marshal bytes
@ -144,6 +148,10 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
// sign and build the transaction from the msg
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) {
ctx, err = EnsureAccountNumber(ctx)
if err != nil {
return nil, err
}
// default to next sequence number if none provided
ctx, err = EnsureSequence(ctx)
if err != nil {
@ -164,12 +172,36 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *w
}
// get the next sequence for the account address
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
func (ctx CoreContext) GetAccountNumber(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("AccountDecoder required but not provided")
return 0, errors.New("accountDecoder required but not provided")
}
res, err := ctx.Query(address, ctx.AccountStore)
res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore)
if err != nil {
return 0, err
}
if len(res) == 0 {
fmt.Printf("No account found. Returning 0.\n")
return 0, err
}
account, err := ctx.Decoder(res)
if err != nil {
panic(err)
}
return account.GetAccountNumber(), nil
}
// get the next sequence for the account address
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("accountDecoder required but not provided")
}
res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore)
if err != nil {
return 0, err
}
@ -197,7 +229,7 @@ func (ctx CoreContext) GetPassphraseFromStdin(name string) (pass string, err err
// GetNode prepares a simple rpc.Client
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
if ctx.Client == nil {
return nil, errors.New("Must define node URI")
return nil, errors.New("must define node URI")
}
return ctx.Client, nil
}

View File

@ -10,9 +10,11 @@ import (
type CoreContext struct {
ChainID string
Height int64
Gas int64
TrustNode bool
NodeURI string
FromAddressName string
AccountNumber int64
Sequence int64
Client rpcclient.Client
Decoder auth.AccountDecoder
@ -31,6 +33,12 @@ func (c CoreContext) WithHeight(height int64) CoreContext {
return c
}
// WithGas - return a copy of the context with an updated gas
func (c CoreContext) WithGas(gas int64) CoreContext {
c.Gas = gas
return c
}
// WithTrustNode - return a copy of the context with an updated TrustNode flag
func (c CoreContext) WithTrustNode(trustNode bool) CoreContext {
c.TrustNode = trustNode
@ -50,6 +58,12 @@ func (c CoreContext) WithFromAddressName(fromAddressName string) CoreContext {
return c
}
// WithSequence - return a copy of the context with an account number
func (c CoreContext) WithAccountNumber(accnum int64) CoreContext {
c.AccountNumber = accnum
return c
}
// WithSequence - return a copy of the context with an updated sequence number
func (c CoreContext) WithSequence(sequence int64) CoreContext {
c.Sequence = sequence

View File

@ -30,9 +30,11 @@ func NewCoreContextFromViper() CoreContext {
return CoreContext{
ChainID: chainID,
Height: viper.GetInt64(client.FlagHeight),
Gas: viper.GetInt64(client.FlagGas),
TrustNode: viper.GetBool(client.FlagTrustNode),
FromAddressName: viper.GetString(client.FlagName),
NodeURI: nodeURI,
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Sequence: viper.GetInt64(client.FlagSequence),
Client: rpc,
Decoder: nil,
@ -53,6 +55,25 @@ func defaultChainID() (string, error) {
return doc.ChainID, nil
}
// EnsureSequence - automatically set sequence number if none provided
func EnsureAccountNumber(ctx CoreContext) (CoreContext, error) {
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
if viper.GetInt64(client.FlagAccountNumber) != 0 {
return ctx, nil
}
from, err := ctx.GetFromAddress()
if err != nil {
return ctx, err
}
accnum, err := ctx.GetAccountNumber(from)
if err != nil {
return ctx, err
}
fmt.Printf("Defaulting to account number: %d\n", accnum)
ctx = ctx.WithAccountNumber(accnum)
return ctx, nil
}
// EnsureSequence - automatically set sequence number if none provided
func EnsureSequence(ctx CoreContext) (CoreContext, error) {
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331

View File

@ -4,13 +4,15 @@ import "github.com/spf13/cobra"
// nolint
const (
FlagChainID = "chain-id"
FlagNode = "node"
FlagHeight = "height"
FlagTrustNode = "trust-node"
FlagName = "name"
FlagSequence = "sequence"
FlagFee = "fee"
FlagChainID = "chain-id"
FlagNode = "node"
FlagHeight = "height"
FlagGas = "gas"
FlagTrustNode = "trust-node"
FlagName = "name"
FlagAccountNumber = "account-number"
FlagSequence = "sequence"
FlagFee = "fee"
)
// LineBreak can be included in a command list to provide a blank line
@ -23,7 +25,7 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
// TODO: make this default false when we support proofs
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses")
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:46657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
}
return cmds
@ -33,10 +35,12 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
for _, c := range cmds {
c.Flags().String(FlagName, "", "Name of private key with which to sign")
c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:46657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction")
}
return cmds
}

View File

@ -32,7 +32,7 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) {
return "", err
}
if len(pass) < MinPassLength {
return "", errors.Errorf("Password must be at least %d characters", MinPassLength)
return "", errors.Errorf("password must be at least %d characters", MinPassLength)
}
return pass, nil
}
@ -68,7 +68,7 @@ func GetCheckPassword(prompt, prompt2 string, buf *bufio.Reader) (string, error)
return "", err
}
if pass != pass2 {
return "", errors.New("Passphrases don't match")
return "", errors.New("passphrases don't match")
}
return pass, nil
}

View File

@ -53,7 +53,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
name = "inmemorykey"
} else {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a name for the key")
return errors.New("you must provide a name for the key")
}
name = args[0]
kb, err = GetKeyBase()
@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
return nil
}
// addOutput lets us json format the data
type addOutput struct {
Key keys.Info `json:"key"`
Seed string `json:"seed"`
}
func printCreate(info keys.Info, seed string) {
output := viper.Get(cli.OutputFlag)
switch output {
@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) {
fmt.Println(seed)
}
case "json":
out := addOutput{Key: info}
out, err := Bech32KeyOutput(info)
if err != nil {
panic(err)
}
if !viper.GetBool(flagNoBackup) {
out.Seed = seed
}

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"net/http"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
)
@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("[]"))
return
}
keysOutput := make([]KeyOutput, len(infos))
for i, info := range infos {
keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())}
keysOutput, err := Bech32KeysOutput(infos)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keysOutput, "", " ")
if err != nil {

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"net/http"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gorilla/mux"
keys "github.com/tendermint/go-crypto/keys"
@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
return
}
keyOutput := KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address())}
keyOutput, err := Bech32KeyOutput(info)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keyOutput, "", " ")
if err != nil {
w.WriteHeader(500)

View File

@ -6,7 +6,6 @@ import (
"github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
@ -22,6 +21,8 @@ const KeyDBName = "keys"
// keybase is used to make GetKeyBase a singleton
var keybase keys.Keybase
// TODO make keybase take a database not load from the directory
// initialize a keybase based on the configuration
func GetKeyBase() (keys.Keybase, error) {
rootDir := viper.GetString(cli.HomeFlag)
@ -47,29 +48,47 @@ func SetKeyBase(kb keys.Keybase) {
// used for outputting keys.Info over REST
type KeyOutput struct {
Name string `json:"name"`
Address sdk.Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
Name string `json:"name"`
Address string `json:"address"`
PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
}
func NewKeyOutput(info keys.Info) KeyOutput {
return KeyOutput{
Name: info.Name,
Address: sdk.Address(info.PubKey.Address().Bytes()),
PubKey: info.PubKey,
}
}
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
// create a list of KeyOutput in bech32 format
func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
kos := make([]KeyOutput, len(infos))
for i, info := range infos {
kos[i] = NewKeyOutput(info)
ko, err := Bech32KeyOutput(info)
if err != nil {
return nil, err
}
kos[i] = ko
}
return kos
return kos, nil
}
// create a KeyOutput in bech32 format
func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.PubKey.Address().Bytes()))
if err != nil {
return KeyOutput{}, err
}
bechPubKey, err := sdk.Bech32ifyAccPub(info.PubKey)
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: info.Name,
Address: bechAccount,
PubKey: bechPubKey,
}, nil
}
func printInfo(info keys.Info) {
ko := NewKeyOutput(info)
ko, err := Bech32KeyOutput(info)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@ -84,7 +103,10 @@ func printInfo(info keys.Info) {
}
func printInfos(infos []keys.Info) {
kos := NewKeyOutputs(infos)
kos, err := Bech32KeysOutput(infos)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@ -101,13 +123,5 @@ func printInfos(infos []keys.Info) {
}
func printKeyOutput(ko KeyOutput) {
bechAccount, err := sdk.Bech32ifyAcc(ko.Address)
if err != nil {
panic(err)
}
bechPubKey, err := sdk.Bech32ifyAccPub(ko.PubKey)
if err != nil {
panic(err)
}
fmt.Printf("%s\t%s\t%s\n", ko.Name, bechAccount, bechPubKey)
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
}

View File

@ -1,54 +0,0 @@
package lcd
// NOTE: COPIED VERBATIM FROM tendermint/tendermint/rpc/test/helpers.go
import (
"fmt"
"os"
"path/filepath"
"strings"
cmn "github.com/tendermint/tmlibs/common"
cfg "github.com/tendermint/tendermint/config"
)
var globalConfig *cfg.Config
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
// fmt.Println(p)
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
func randPort() int {
return int(cmn.RandUint16()/2 + 10000)
}
func makeAddrs() (string, string, string) {
start := randPort()
return fmt.Sprintf("tcp://0.0.0.0:%d", start),
fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
}
// GetConfig returns a config for the test cases as a singleton
func GetConfig() *cfg.Config {
if globalConfig == nil {
pathname := makePathname()
globalConfig = cfg.ResetTestRoot(pathname)
// and we use random ports to run in parallel
tm, rpc, _ := makeAddrs()
globalConfig.P2P.ListenAddress = tm
globalConfig.RPC.ListenAddress = rpc
globalConfig.TxIndex.IndexTags = "app.creator" // see kvstore application
}
return globalConfig
}

View File

@ -1,142 +1,115 @@
package lcd
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"regexp"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
cryptoKeys "github.com/tendermint/go-crypto/keys"
tmcfg "github.com/tendermint/tendermint/config"
nm "github.com/tendermint/tendermint/node"
p2p "github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
tmtypes "github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
client "github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
tests "github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
)
var (
coinDenom = "steak"
coinAmount = int64(10000000)
validatorAddr1 = ""
validatorAddr2 = ""
// XXX bad globals
name = "test"
password = "0123456789"
port string
seed string
sendAddr string
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
)
func TestKeys(t *testing.T) {
// empty keys
// XXX: the test comes with a key setup
/*
res, body := request(t, port, "GET", "/keys", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.Equal(t, "[]", body, "Expected an empty array")
*/
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
// get seed
res, body := request(t, port, "GET", "/keys/seed", nil)
res, body := Request(t, port, "GET", "/keys/seed", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
newSeed := body
reg, err := regexp.Compile(`([a-z]+ ){12}`)
require.Nil(t, err)
match := reg.MatchString(seed)
assert.True(t, match, "Returned seed has wrong foramt", seed)
assert.True(t, match, "Returned seed has wrong format", seed)
newName := "test_newname"
newPassword := "0987654321"
// add key
var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password))
res, body = request(t, port, "POST", "/keys", jsonStr)
res, body = Request(t, port, "POST", "/keys", jsonStr)
assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed")
jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed))
res, body = request(t, port, "POST", "/keys", jsonStr)
res, body = Request(t, port, "POST", "/keys", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
addr := body
assert.Len(t, addr, 40, "Returned address has wrong format", addr)
addr2 := body
assert.Len(t, addr2, 40, "Returned address has wrong format", addr2)
// existing keys
res, body = request(t, port, "GET", "/keys", nil)
res, body = Request(t, port, "GET", "/keys", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var m [2]keys.KeyOutput
err = cdc.UnmarshalJSON([]byte(body), &m)
require.Nil(t, err)
sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr)
addrAcc, _ := sdk.GetAccAddressHex(addr)
addr2Acc, err := sdk.GetAccAddressHex(addr2)
require.Nil(t, err)
addr2Bech32 := sdk.MustBech32ifyAcc(addr2Acc)
addrBech32 := sdk.MustBech32ifyAcc(addr)
assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly")
assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly")
assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly")
assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly")
assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
assert.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly")
assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
assert.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly")
// select key
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
res, body = request(t, port, "GET", keyEndpoint, nil)
res, body = Request(t, port, "GET", keyEndpoint, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var m2 keys.KeyOutput
err = cdc.UnmarshalJSON([]byte(body), &m2)
require.Nil(t, err)
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
assert.Equal(t, addrAcc, m2.Address, "Did not serve keys Address correctly")
assert.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly")
// update key
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
jsonStr = []byte(fmt.Sprintf(`{
"old_password":"%s",
"new_password":"12345678901"
}`, newPassword))
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// here it should say unauthorized as we changed the password before
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
require.Equal(t, http.StatusUnauthorized, res.StatusCode, body)
// delete key
jsonStr = []byte(`{"password":"12345678901"}`)
res, body = request(t, port, "DELETE", keyEndpoint, jsonStr)
res, body = Request(t, port, "DELETE", keyEndpoint, jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
}
func TestVersion(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
// node info
res, body := request(t, port, "GET", "/version", nil)
res, body := Request(t, port, "GET", "/version", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
@ -146,9 +119,11 @@ func TestVersion(t *testing.T) {
}
func TestNodeStatus(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
// node info
res, body := request(t, port, "GET", "/node_info", nil)
res, body := Request(t, port, "GET", "/node_info", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var nodeInfo p2p.NodeInfo
@ -158,21 +133,20 @@ func TestNodeStatus(t *testing.T) {
assert.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res)
// syncing
res, body = request(t, port, "GET", "/syncing", nil)
res, body = Request(t, port, "GET", "/syncing", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// we expect that there is no other node running so the syncing state is "false"
// we c
assert.Equal(t, "false", body)
}
func TestBlock(t *testing.T) {
tests.WaitForHeight(2, port)
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
var resultBlock ctypes.ResultBlock
res, body := request(t, port, "GET", "/blocks/latest", nil)
res, body := Request(t, port, "GET", "/blocks/latest", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultBlock)
@ -182,7 +156,7 @@ func TestBlock(t *testing.T) {
// --
res, body = request(t, port, "GET", "/blocks/1", nil)
res, body = Request(t, port, "GET", "/blocks/1", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = json.Unmarshal([]byte(body), &resultBlock)
@ -192,50 +166,62 @@ func TestBlock(t *testing.T) {
// --
res, body = request(t, port, "GET", "/blocks/1000000000", nil)
res, body = Request(t, port, "GET", "/blocks/1000000000", nil)
require.Equal(t, http.StatusNotFound, res.StatusCode, body)
}
func TestValidators(t *testing.T) {
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
defer cleanup()
var resultVals ctypes.ResultValidators
var resultVals rpc.ResultValidatorsOutput
res, body := request(t, port, "GET", "/validatorsets/latest", nil)
res, body := Request(t, port, "GET", "/validatorsets/latest", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
require.Nil(t, err, "Couldn't parse validatorset")
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr")
assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
// --
res, body = request(t, port, "GET", "/validatorsets/1", nil)
res, body = Request(t, port, "GET", "/validatorsets/1", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
require.Nil(t, err, "Couldn't parse validatorset")
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
// --
res, body = request(t, port, "GET", "/validatorsets/1000000000", nil)
res, body = Request(t, port, "GET", "/validatorsets/1000000000", nil)
require.Equal(t, http.StatusNotFound, res.StatusCode)
}
func TestCoinSend(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
require.NoError(t, err)
someFakeAddr := sdk.MustBech32ifyAcc(bz)
// query empty
//res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil)
res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil)
res, body := Request(t, port, "GET", "/accounts/"+someFakeAddr, nil)
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create TX
receiveAddr, resultTx := doSend(t, port, seed)
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was commited
@ -243,27 +229,31 @@ func TestCoinSend(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc = getAccount(t, sendAddr)
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
mycoins := coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
// query receiver
acc = getAccount(t, receiveAddr)
acc = getAccount(t, port, receiveAddr)
coins = acc.GetCoins()
mycoins = coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, int64(1), mycoins.Amount)
}
func TestIBCTransfer(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create TX
resultTx := doIBCTransfer(t, port, seed)
resultTx := doIBCTransfer(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
@ -272,72 +262,108 @@ func TestIBCTransfer(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc = getAccount(t, sendAddr)
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
mycoins := coins[0]
assert.Equal(t, coinDenom, mycoins.Denom)
assert.Equal(t, "steak", mycoins.Denom)
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
// TODO: query ibc egress packet state
}
func TestTxs(t *testing.T) {
// TODO: re-enable once we can get txs by tag
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
// query wrong
// res, body := request(t, port, "GET", "/txs", nil)
// require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
res, body := Request(t, port, "GET", "/txs", nil)
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// query empty
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.sender='%s'", "8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6"), nil)
// require.Equal(t, http.StatusOK, res.StatusCode, body)
// assert.Equal(t, "[]", body)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.Equal(t, "[]", body)
// create TX
_, resultTx := doSend(t, port, seed)
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx is findable
res, body := request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// // query sender
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.sender='%s'", addr), nil)
// require.Equal(t, http.StatusOK, res.StatusCode, body)
type txInfo struct {
Height int64 `json:"height"`
Tx sdk.Tx `json:"tx"`
Result abci.ResponseDeliverTx `json:"result"`
}
var indexedTxs []txInfo
// assert.NotEqual(t, "[]", body)
// check if tx is queryable
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
assert.NotEqual(t, "[]", body)
// // query receiver
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.receiver='%s'", receiveAddr), nil)
// require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
assert.Equal(t, 1, len(indexedTxs))
// assert.NotEqual(t, "[]", body)
// query sender
addrBech := sdk.MustBech32ifyAcc(addr)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", addrBech), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
require.Equal(t, 1, len(indexedTxs), "%v", indexedTxs) // there are 2 txs created with doSend
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
// query recipient
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=recipient_bech32='%s'", receiveAddrBech), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
require.NoError(t, err)
require.Equal(t, 1, len(indexedTxs))
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
}
func TestValidatorsQuery(t *testing.T) {
validators := getValidators(t)
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{})
require.Equal(t, 2, len(pks))
defer cleanup()
validators := getValidators(t, port)
assert.Equal(t, len(validators), 2)
// make sure all the validators were found (order unknown because sorted by owner addr)
foundVal1, foundVal2 := false, false
res1, res2 := hex.EncodeToString(validators[0].Owner), hex.EncodeToString(validators[1].Owner)
if res1 == validatorAddr1 || res2 == validatorAddr1 {
pk1Bech := sdk.MustBech32ifyValPub(pks[0])
pk2Bech := sdk.MustBech32ifyValPub(pks[1])
if validators[0].PubKey == pk1Bech || validators[1].PubKey == pk1Bech {
foundVal1 = true
}
if res1 == validatorAddr2 || res2 == validatorAddr2 {
if validators[0].PubKey == pk2Bech || validators[1].PubKey == pk2Bech {
foundVal2 = true
}
assert.True(t, foundVal1, "validatorAddr1 %v, res1 %v, res2 %v", validatorAddr1, res1, res2)
assert.True(t, foundVal2, "validatorAddr2 %v, res1 %v, res2 %v", validatorAddr2, res1, res2)
assert.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner)
assert.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner)
}
func TestBond(t *testing.T) {
func TestBonding(t *testing.T) {
name, password, denom := "test", "1234567890", "steak"
addr, seed := CreateAddr(t, "test", password, GetKB(t))
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
defer cleanup()
validator1Owner := pks[0].Address()
// create bond TX
resultTx := doBond(t, port, seed)
resultTx := doBond(t, port, seed, name, password, addr, validator1Owner)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was commited
@ -345,196 +371,42 @@ func TestBond(t *testing.T) {
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// query sender
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
coins := acc.GetCoins()
assert.Equal(t, int64(87), coins.AmountOf(coinDenom))
assert.Equal(t, int64(40), coins.AmountOf(denom))
// query candidate
bond := getDelegation(t, sendAddr, validatorAddr1)
assert.Equal(t, "10/1", bond.Shares.String())
}
// query validator
bond := getDelegation(t, port, addr, validator1Owner)
assert.Equal(t, "60/1", bond.Shares.String())
func TestUnbond(t *testing.T) {
//////////////////////
// testing unbonding
// create unbond TX
resultTx := doUnbond(t, port, seed)
resultTx = doUnbond(t, port, seed, name, password, addr, validator1Owner)
tests.WaitForHeight(resultTx.Height+1, port)
// query validator
bond = getDelegation(t, port, addr, validator1Owner)
assert.Equal(t, "30/1", bond.Shares.String())
// check if tx was commited
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// TODO fix shares fn in staking
// query sender
acc := getAccount(t, sendAddr)
coins := acc.GetCoins()
assert.Equal(t, int64(98), coins.AmountOf(coinDenom))
//acc := getAccount(t, sendAddr)
//coins := acc.GetCoins()
//assert.Equal(t, int64(98), coins.AmountOf(coinDenom))
// query candidate
bond := getDelegation(t, sendAddr, validatorAddr1)
assert.Equal(t, "9/1", bond.Shares.String())
}
//__________________________________________________________
// helpers
// strt TM and the LCD in process, listening on their respective sockets
func startTMAndLCD() (*nm.Node, net.Listener, error) {
dir, err := ioutil.TempDir("", "lcd_test")
if err != nil {
return nil, nil, err
}
viper.Set(cli.HomeFlag, dir)
kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
if err != nil {
return nil, nil, err
}
config := GetConfig()
config.Consensus.TimeoutCommit = 1000
config.Consensus.SkipTimeoutCommit = false
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db)
cdc = gapp.MakeCodec() // XXX
genesisFile := config.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
if err != nil {
return nil, nil, err
}
genDoc.Validators = append(genDoc.Validators,
tmtypes.GenesisValidator{
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
Power: 1,
Name: "val",
},
)
pk1 := genDoc.Validators[0].PubKey
pk2 := genDoc.Validators[1].PubKey
validatorAddr1 = hex.EncodeToString(pk1.Address())
validatorAddr2 = hex.EncodeToString(pk2.Address())
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
// test for simplicity
var appGenTxs [2]json.RawMessage
appGenTxs[0], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk1, pk1.Address(), "test_val1", true)
if err != nil {
return nil, nil, err
}
appGenTxs[1], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk2, pk2.Address(), "test_val2", true)
if err != nil {
return nil, nil, err
}
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
if err != nil {
return nil, nil, err
}
// add the sendAddr to genesis
var info cryptoKeys.Info
info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed
if err != nil {
return nil, nil, err
}
sendAddr = info.PubKey.Address().String() // XXX global
accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address())
accAuth.Coins = sdk.Coins{{"steak", 100}}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
if err != nil {
return nil, nil, err
}
genDoc.AppStateJSON = appState
// LCD listen address
var listenAddr string
listenAddr, port, err = server.FreeTCPAddr()
if err != nil {
return nil, nil, err
}
// XXX: need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
node, err := startTM(config, logger, genDoc, privVal, app)
if err != nil {
return nil, nil, err
}
lcd, err := startLCD(logger, listenAddr, cdc)
if err != nil {
return nil, nil, err
}
tests.WaitForStart(port)
return node, lcd, nil
}
// Create & start in-process tendermint node with memdb
// and in-process abci application.
// TODO: need to clean up the WAL dir or enable it to be not persistent
func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
n, err := nm.NewNode(cfg,
privVal,
proxy.NewLocalClientCreator(app),
genDocProvider,
dbProvider,
logger.With("module", "node"))
if err != nil {
return nil, err
}
err = n.Start()
if err != nil {
return nil, err
}
// wait for rpc
tests.WaitForRPC(GetConfig().RPC.ListenAddress)
logger.Info("Tendermint running!")
return n, err
}
// start the LCD. note this blocks!
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
handler := createHandler(cdc)
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
}
func request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
var res *http.Response
var err error
url := fmt.Sprintf("http://localhost:%v%v", port, path)
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
require.Nil(t, err)
res, err = http.DefaultClient.Do(req)
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
require.Nil(t, err)
output, err := ioutil.ReadAll(res.Body)
res.Body.Close()
require.Nil(t, err)
return res, string(output)
}
func getAccount(t *testing.T, sendAddr string) auth.Account {
// get the account to get the sequence
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
//_____________________________________________________________________________
// get the account to get the sequence
func getAccount(t *testing.T, port string, addr sdk.Address) auth.Account {
addrBech32 := sdk.MustBech32ifyAcc(addr)
res, body := Request(t, port, "GET", "/accounts/"+addrBech32, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var acc auth.Account
err := cdc.UnmarshalJSON([]byte(body), &acc)
@ -542,20 +414,34 @@ func getAccount(t *testing.T, sendAddr string) auth.Account {
return acc
}
func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctypes.ResultBroadcastTxCommit) {
func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) (receiveAddr sdk.Address, resultTx ctypes.ResultBroadcastTxCommit) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err)
receiveAddr = receiveInfo.PubKey.Address().String()
receiveAddr = receiveInfo.PubKey.Address()
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
// send
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
res, body := request(t, port, "POST", "/accounts/"+receiveAddr+"/send", jsonStr)
jsonStr := []byte(fmt.Sprintf(`{
"name":"%s",
"password":"%s",
"account_number":%d,
"sequence":%d,
"gas": 10000,
"amount":[
{
"denom": "%s",
"amount": 1
}
]
}`, name, password, accnum, sequence, "steak"))
res, body := Request(t, port, "POST", "/accounts/"+receiveAddrBech+"/send", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -564,21 +450,34 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
return receiveAddr, resultTx
}
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err)
receiveAddr := receiveInfo.PubKey.Address().String()
receiveAddr := receiveInfo.PubKey.Address()
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, addr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
// send
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
res, body := request(t, port, "POST", "/ibc/testchain/"+receiveAddr+"/send", jsonStr)
jsonStr := []byte(fmt.Sprintf(`{
"name":"%s",
"password": "%s",
"account_number":%d,
"sequence": %d,
"gas": 100000,
"amount":[
{
"denom": "%s",
"amount": 1
}
]
}`, name, password, accnum, sequence, "steak"))
res, body := Request(t, port, "POST", "/ibc/testchain/"+receiveAddrBech+"/send", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -587,9 +486,13 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
return resultTx
}
func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Delegation {
func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.Address) stake.Delegation {
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// get the account to get the sequence
res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil)
res, body := Request(t, port, "GET", "/stake/"+delegatorAddrBech+"/bonding_status/"+validatorAddrBech, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bond stake.Delegation
err := cdc.UnmarshalJSON([]byte(body), &bond)
@ -597,26 +500,32 @@ func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Dele
return bond
}
func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doBond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, delegatorAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// send
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"account_number": %d,
"sequence": %d,
"gas": 10000,
"delegate": [
{
"delegator_addr": "%x",
"delegator_addr": "%s",
"validator_addr": "%s",
"bond": { "denom": "%s", "amount": 10 }
"bond": { "denom": "%s", "amount": 60 }
}
],
"unbond": []
}`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
}`, name, password, accnum, sequence, delegatorAddrBech, validatorAddrBech, "steak"))
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -626,26 +535,32 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC
return results[0]
}
func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
func doUnbond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, sendAddr)
acc := getAccount(t, port, delegatorAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
// send
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"account_number": %d,
"sequence": %d,
"bond": [],
"gas": 10000,
"delegate": [],
"unbond": [
{
"delegator_addr": "%x",
"delegator_addr": "%s",
"validator_addr": "%s",
"shares": "1"
"shares": "30"
}
]
}`, name, password, sequence, acc.GetAddress(), validatorAddr1))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
}`, name, password, accnum, sequence, delegatorAddrBech, validatorAddrBech))
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -655,11 +570,11 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT
return results[0]
}
func getValidators(t *testing.T) []stake.Validator {
func getValidators(t *testing.T, port string) []stakerest.StakeValidatorOutput {
// get the account to get the sequence
res, body := request(t, port, "GET", "/stake/validators", nil)
res, body := Request(t, port, "GET", "/stake/validators", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validators stake.Validators
var validators []stakerest.StakeValidatorOutput
err := cdc.UnmarshalJSON([]byte(body), &validators)
require.Nil(t, err)
return validators

View File

@ -1,38 +0,0 @@
package lcd
import (
"fmt"
"os"
"testing"
nm "github.com/tendermint/tendermint/node"
)
var node *nm.Node
// See https://golang.org/pkg/testing/#hdr-Main
// for more details
func TestMain(m *testing.M) {
// start a basecoind node and LCD server in the background to test against
// run all the tests against a single server instance
node, lcd, err := startTMAndLCD()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
code := m.Run()
// tear down
// TODO: cleanup
// TODO: it would be great if TM could run without
// persiting anything in the first place
node.Stop()
node.Wait()
// just a listener ...
lcd.Close()
os.Exit(code)
}

View File

@ -25,48 +25,42 @@ import (
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
)
const (
flagListenAddr = "laddr"
flagCORS = "cors"
)
// ServeCommand will generate a long-running rest server
// (aka Light Client Daemon) that exposes functionality similar
// to the cli, but over rest
func ServeCommand(cdc *wire.Codec) *cobra.Command {
flagListenAddr := "laddr"
flagCORS := "cors"
cmd := &cobra.Command{
Use: "rest-server",
Short: "Start LCD (light-client daemon), a local REST server",
RunE: startRESTServerFn(cdc),
RunE: func(cmd *cobra.Command, args []string) error {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
With("module", "rest-server")
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
if err != nil {
return err
}
logger.Info("REST server started")
// Wait forever and cleanup
cmn.TrapSignal(func() {
err := listener.Close()
logger.Error("error closing listener", "err", err)
})
return nil
},
}
cmd.Flags().StringP(flagListenAddr, "a", "tcp://localhost:1317", "Address for server to listen on")
cmd.Flags().String(flagCORS, "", "Set to domains that can make CORS requests (* for all)")
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
return cmd
}
func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
With("module", "rest-server")
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
if err != nil {
return err
}
logger.Info("REST server started")
// Wait forever and cleanup
cmn.TrapSignal(func() {
err := listener.Close()
logger.Error("Error closing listener", "err", err)
})
return nil
}
}
func createHandler(cdc *wire.Codec) http.Handler {
r := mux.NewRouter()
r.HandleFunc("/version", version.RequestHandler).Methods("GET")

234
client/lcd/test_helpers.go Normal file
View File

@ -0,0 +1,234 @@
package lcd
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
crkeys "github.com/tendermint/go-crypto/keys"
tmcfg "github.com/tendermint/tendermint/config"
nm "github.com/tendermint/tendermint/node"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
// GetConfig returns a config for the test cases as a singleton
func GetConfig() *tmcfg.Config {
pathname := makePathname()
config := tmcfg.ResetTestRoot(pathname)
tmAddr, _, err := server.FreeTCPAddr()
if err != nil {
panic(err)
}
rcpAddr, _, err := server.FreeTCPAddr()
if err != nil {
panic(err)
}
config.P2P.ListenAddress = tmAddr
config.RPC.ListenAddress = rcpAddr
return config
}
// get the lcd test keybase
// note can't use a memdb because the request is expecting to interact with the default location
func GetKB(t *testing.T) crkeys.Keybase {
dir, err := ioutil.TempDir("", "lcd_test")
require.NoError(t, err)
viper.Set(cli.HomeFlag, dir)
keybase, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
require.NoError(t, err)
return keybase
}
// add an address to the store return name and password
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (addr sdk.Address, seed string) {
var info crkeys.Info
var err error
info, seed, err = kb.Create(name, password, crkeys.AlgoEd25519)
require.NoError(t, err)
addr = info.PubKey.Address()
return
}
// strt TM and the LCD in process, listening on their respective sockets
// nValidators = number of validators
// initAddrs = accounts to initialize with some steaks
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) (cleanup func(), validatorsPKs []crypto.PubKey, port string) {
config := GetConfig()
config.Consensus.TimeoutCommit = 1000
config.Consensus.SkipTimeoutCommit = false
config.TxIndex.IndexAllTags = true
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
privVal.Reset()
db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db)
cdc = gapp.MakeCodec() // XXX
genesisFile := config.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
require.NoError(t, err)
// add more validators
if nValidators < 1 {
panic("InitializeTestLCD must use at least one validator")
}
for i := 1; i < nValidators; i++ {
genDoc.Validators = append(genDoc.Validators,
tmtypes.GenesisValidator{
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
Power: 1,
Name: "val",
},
)
}
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
// test for simplicity
var appGenTxs []json.RawMessage
for _, gdValidator := range genDoc.Validators {
pk := gdValidator.PubKey
validatorsPKs = append(validatorsPKs, pk) // append keys for output
appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, pk.Address(), "test_val1", true)
require.NoError(t, err)
appGenTxs = append(appGenTxs, appGenTx)
}
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
require.NoError(t, err)
// add some tokens to init accounts
for _, addr := range initAddrs {
accAuth := auth.NewBaseAccountWithAddress(addr)
accAuth.Coins = sdk.Coins{{"steak", 100}}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
}
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
require.NoError(t, err)
genDoc.AppStateJSON = appState
// LCD listen address
var listenAddr string
listenAddr, port, err = server.FreeTCPAddr()
require.NoError(t, err)
// XXX: need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
node, err := startTM(config, logger, genDoc, privVal, app)
require.NoError(t, err)
lcd, err := startLCD(logger, listenAddr, cdc)
require.NoError(t, err)
//time.Sleep(time.Second)
//tests.WaitForHeight(2, port)
tests.WaitForStart(port)
tests.WaitForHeight(1, port)
// for use in defer
cleanup = func() {
node.Stop()
node.Wait()
lcd.Close()
}
return
}
// Create & start in-process tendermint node with memdb
// and in-process abci application.
// TODO: need to clean up the WAL dir or enable it to be not persistent
func startTM(tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
n, err := nm.NewNode(tmcfg,
privVal,
proxy.NewLocalClientCreator(app),
genDocProvider,
dbProvider,
logger.With("module", "node"))
if err != nil {
return nil, err
}
err = n.Start()
if err != nil {
return nil, err
}
// wait for rpc
tests.WaitForRPC(tmcfg.RPC.ListenAddress)
logger.Info("Tendermint running!")
return n, err
}
// start the LCD. note this blocks!
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
handler := createHandler(cdc)
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
}
// make a test lcd test request
func Request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
var res *http.Response
var err error
url := fmt.Sprintf("http://localhost:%v%v", port, path)
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
require.Nil(t, err)
res, err = http.DefaultClient.Do(req)
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
require.Nil(t, err)
output, err := ioutil.ReadAll(res.Body)
res.Body.Close()
require.Nil(t, err)
return res, string(output)
}

View File

@ -24,7 +24,7 @@ func BlockCommand() *cobra.Command {
Args: cobra.MaximumNArgs(1),
RunE: printBlock,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().StringSlice(flagSelect, []string{"header", "tx"}, "Fields to return (header|txs|results)")

View File

@ -18,7 +18,7 @@ const (
// XXX: remove this when not needed
func todoNotImplemented(_ *cobra.Command, _ []string) error {
return errors.New("TODO: Command not yet implemented")
return errors.New("todo: Command not yet implemented")
}
// AddCommands adds a number of rpc-related subcommands
@ -36,7 +36,7 @@ func initClientCommand() *cobra.Command {
RunE: todoNotImplemented,
}
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity")
cmd.Flags().String(flagCommit, "", "File with trusted and signed header")
cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)")

View File

@ -18,7 +18,7 @@ func statusCommand() *cobra.Command {
Short: "Query remote node for status",
RunE: printNodeStatus,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
return cmd
}

View File

@ -10,6 +10,8 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/tendermint/tendermint/types"
)
// TODO these next two functions feel kinda hacky based on their placement
@ -22,12 +24,44 @@ func ValidatorCommand() *cobra.Command {
Args: cobra.MaximumNArgs(1),
RunE: printValidators,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
return cmd
}
// Validator output in bech32 format
type ValidatorOutput struct {
Address string `json:"address"` // in bech32
PubKey string `json:"pub_key"` // in bech32
Accum int64 `json:"accum"`
VotingPower int64 `json:"voting_power"`
}
// Validators at a certain height output in bech32 format
type ResultValidatorsOutput struct {
BlockHeight int64 `json:"block_height"`
Validators []ValidatorOutput `json:"validators"`
}
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
bechAddress, err := sdk.Bech32ifyVal(validator.Address)
if err != nil {
return ValidatorOutput{}, err
}
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
if err != nil {
return ValidatorOutput{}, err
}
return ValidatorOutput{
Address: bechAddress,
PubKey: bechValPubkey,
Accum: validator.Accum,
VotingPower: validator.VotingPower,
}, nil
}
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
// get the node
node, err := ctx.GetNode()
@ -35,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
return nil, err
}
res, err := node.Validators(height)
validatorsRes, err := node.Validators(height)
if err != nil {
return nil, err
}
output, err := cdc.MarshalJSON(res)
outputValidatorsRes := ResultValidatorsOutput{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
}
for i := 0; i < len(validatorsRes.Validators); i++ {
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
if err != nil {
return nil, err
}
}
output, err := cdc.MarshalJSON(outputValidatorsRes)
if err != nil {
return nil, err
}
@ -96,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}

View File

@ -42,7 +42,7 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
},
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")

View File

@ -19,7 +19,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
// register REST routes
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, ctx)).Methods("GET")
// r.HandleFunc("/txs", SearchTxRequestHandler(cdc)).Methods("GET")
r.HandleFunc("/txs", SearchTxRequestHandlerFn(ctx, cdc)).Methods("GET")
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
// r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST")
}

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
@ -29,7 +30,11 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
tags := viper.GetStringSlice(flagTags)
output, err := searchTx(context.NewCoreContextFromViper(), cdc, tags)
txs, err := searchTxs(context.NewCoreContextFromViper(), cdc, tags)
if err != nil {
return err
}
output, err := cdc.MarshalJSON(txs)
if err != nil {
return err
}
@ -38,7 +43,7 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
},
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false once proofs built in
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
@ -47,13 +52,12 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
return cmd
}
func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte, error) {
func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInfo, error) {
if len(tags) == 0 {
return nil, errors.New("Must declare at least one tag to search")
return nil, errors.New("must declare at least one tag to search")
}
// XXX: implement ANY
query := strings.Join(tags, " AND ")
// get the node
node, err := ctx.GetNode()
if err != nil {
@ -74,11 +78,7 @@ func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte,
return nil, err
}
output, err := cdc.MarshalJSON(info)
if err != nil {
return nil, err
}
return output, nil
return info, nil
}
func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) {
@ -102,17 +102,44 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han
tag := r.FormValue("tag")
if tag == "" {
w.WriteHeader(400)
w.Write([]byte("You need to provide a tag to search for."))
w.Write([]byte("You need to provide at least a tag as a key=value pair to search for. Postfix the key with _bech32 to search bech32-encoded addresses or public keys"))
return
}
keyValue := strings.Split(tag, "=")
key := keyValue[0]
value := keyValue[1]
if strings.HasSuffix(key, "_bech32") {
bech32address := strings.Trim(value, "'")
prefix := strings.Split(bech32address, "1")[0]
bz, err := sdk.GetFromBech32(bech32address, prefix)
if err != nil {
w.WriteHeader(400)
w.Write([]byte(err.Error()))
return
}
tags := []string{tag}
output, err := searchTx(ctx, cdc, tags)
tag = strings.TrimRight(key, "_bech32") + "='" + sdk.Address(bz).String() + "'"
}
txs, err := searchTxs(ctx, cdc, []string{tag})
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
if len(txs) == 0 {
w.Write([]byte("[]"))
return
}
output, err := cdc.MarshalJSON(txs)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}

View File

@ -5,6 +5,7 @@ import (
"os"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -81,7 +82,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper))
// initialize BaseApp
app.SetInitChainer(app.initChainer)
@ -143,6 +145,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx)
app.accountMapper.SetAccount(ctx, acc)
}
@ -153,7 +156,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
}
// export the state of gaia for a genesis file
func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
@ -169,5 +172,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
Accounts: accounts,
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
}
return wire.MarshalJSONIndent(app.cdc, genState)
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, nil
}

View File

@ -1,101 +1,13 @@
package app
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/stake"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
// Construct some global addrs and txs for tests.
var (
chainID = "" // TODO
accName = "foobart"
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
priv2 = crypto.GenPrivKeyEd25519()
addr2 = priv2.PubKey().Address()
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
priv4 = crypto.GenPrivKeyEd25519()
addr4 = priv4.PubKey().Address()
coins = sdk.Coins{{"foocoin", 10}}
halfCoins = sdk.Coins{{"foocoin", 5}}
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
fee = auth.StdFee{
sdk.Coins{{"foocoin", 0}},
100000,
}
sendMsg1 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
sendMsg2 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{
bank.NewOutput(addr2, halfCoins),
bank.NewOutput(addr3, halfCoins),
},
}
sendMsg3 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, coins),
bank.NewInput(addr4, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, coins),
bank.NewOutput(addr3, coins),
},
}
sendMsg4 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr2, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr1, coins),
},
}
sendMsg5 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, manyCoins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, manyCoins),
},
}
)
func loggerAndDB() (log.Logger, dbm.DB) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
return logger, db
}
func newGaiaApp() *GaiaApp {
logger, db := loggerAndDB()
return NewGaiaApp(logger, db)
}
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
@ -119,382 +31,3 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
return nil
}
//_______________________________________________________________________
func TestMsgs(t *testing.T) {
gapp := newGaiaApp()
require.Nil(t, setGenesis(gapp))
msgs := []struct {
msg sdk.Msg
}{
{sendMsg1},
}
for i, m := range msgs {
// Run a CheckDeliver
SignCheckDeliver(t, gapp, m.msg, []int64{int64(i)}, false, priv1)
}
}
func TestGenesis(t *testing.T) {
logger, dbs := loggerAndDB()
gapp := NewGaiaApp(logger, dbs)
// Construct some genesis bytes to reflect GaiaAccount
pk := crypto.GenPrivKeyEd25519().PubKey()
addr := pk.Address()
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr,
Coins: coins,
}
err = setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
// reload app and ensure the account is still there
gapp = NewGaiaApp(logger, dbs)
ctx = gapp.BaseApp.NewContext(true, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
}
func TestMsgSendWithAccounts(t *testing.T) {
gapp := newGaiaApp()
// Construct some genesis bytes to reflect GaiaAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
// Construct genesis state
err = setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1.(*auth.BaseAccount))
// Run a CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "67foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Delivering again should cause replay error
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, false, priv1)
// bumping the txnonce number without resigning should be an auth error
tx := genTx(sendMsg1, []int64{0}, priv1)
tx.Signatures[0].Sequence = 1
res := gapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
SignCheckDeliver(t, gapp, sendMsg1, []int64{1}, true, priv1)
}
func TestMsgSendMultipleOut(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg2, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "47foocoin")
CheckBalance(t, gapp, addr3, "5foocoin")
}
func TestSengMsgMultipleInOut(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
acc4 := &auth.BaseAccount{
Address: addr4,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2, acc4)
assert.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr4, "32foocoin")
CheckBalance(t, gapp, addr2, "52foocoin")
CheckBalance(t, gapp, addr3, "10foocoin")
}
func TestMsgSendDependent(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
err = setGenesis(gapp, acc1)
require.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg4, []int64{0}, true, priv2)
// Check balances
CheckBalance(t, gapp, addr1, "42foocoin")
}
func TestIBCMsgs(t *testing.T) {
gapp := newGaiaApp()
sourceChain := "source-chain"
destChain := "dest-chain"
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
err := setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1)
packet := ibc.IBCPacket{
SrcAddr: addr1,
DestAddr: addr1,
Coins: coins,
SrcChain: sourceChain,
DestChain: destChain,
}
transferMsg := ibc.IBCTransferMsg{
IBCPacket: packet,
}
receiveMsg := ibc.IBCReceiveMsg{
IBCPacket: packet,
Relayer: addr1,
Sequence: 0,
}
SignCheckDeliver(t, gapp, transferMsg, []int64{0}, true, priv1)
CheckBalance(t, gapp, addr1, "")
SignCheckDeliver(t, gapp, transferMsg, []int64{1}, false, priv1)
SignCheckDeliver(t, gapp, receiveMsg, []int64{2}, true, priv1)
CheckBalance(t, gapp, addr1, "10foocoin")
SignCheckDeliver(t, gapp, receiveMsg, []int64{3}, false, priv1)
}
func TestStakeMsgs(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42steak")
require.Nil(t, err)
bondCoin, err := sdk.ParseCoin("10steak")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
res2 := gapp.accountMapper.GetAccount(ctxCheck, addr2)
require.Equal(t, acc1, res1)
require.Equal(t, acc2, res2)
// Create Validator
description := stake.NewDescription("foo_moniker", "", "", "")
createValidatorMsg := stake.NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description,
)
SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1)
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res1.GetCoins())
validator, found := gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, addr1, validator.Owner)
require.Equal(t, sdk.Bonded, validator.Status())
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
// check the bond that should have been created as well
bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1)
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
// Edit Validator
description = stake.NewDescription("bar_moniker", "", "", "")
editValidatorMsg := stake.NewMsgEditValidator(
addr1, description,
)
SignDeliver(t, gapp, editValidatorMsg, []int64{1}, true, priv1)
validator, found = gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, description, validator.Description)
// Delegate
delegateMsg := stake.NewMsgDelegate(
addr2, addr1, bondCoin,
)
SignDeliver(t, gapp, delegateMsg, []int64{0}, true, priv2)
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res2.GetCoins())
bond, found = gapp.stakeKeeper.GetDelegation(ctxDeliver, addr2, addr1)
require.True(t, found)
require.Equal(t, addr2, bond.DelegatorAddr)
require.Equal(t, addr1, bond.ValidatorAddr)
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
// Unbond
unbondMsg := stake.NewMsgUnbond(
addr2, addr1, "MAX",
)
SignDeliver(t, gapp, unbondMsg, []int64{1}, true, priv2)
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins, res2.GetCoins())
_, found = gapp.stakeKeeper.GetDelegation(ctxDeliver, addr2, addr1)
require.False(t, found)
}
//____________________________________________________________________________________
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res2 := gapp.accountMapper.GetAccount(ctxDeliver, addr)
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
}
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx {
sigs := make([]auth.StdSignature, len(priv))
for i, p := range priv {
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)),
Sequence: seq[i],
}
}
return auth.NewStdTx(msg, fee, sigs)
}
func SignCheckDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Run a Check
res := gapp.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res = gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
// XXX fix code or add explaination as to why using commit breaks a bunch of these tests
//gapp.Commit()
}
// XXX the only reason we are using Sign Deliver here is because the tests
// break on check tx the second time you use SignCheckDeliver in a test because
// the checktx state has not been updated likely because commit is not being
// called!
func SignDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res := gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
}

View File

@ -92,7 +92,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
overwrite := viper.GetBool(flagOWK)
name := viper.GetString(flagName)
if name == "" {
return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)")
return nil, nil, tmtypes.GenesisValidator{}, errors.New("must specify --name (validator moniker)")
}
var addr sdk.Address
@ -108,7 +108,8 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
return
}
cliPrint = json.RawMessage(bz)
return GaiaAppGenTxNF(cdc, pk, addr, name, overwrite)
appGenTx,_,validator,err = GaiaAppGenTxNF(cdc, pk, addr, name, overwrite)
return
}
// Generate a gaia genesis transaction without flags

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -50,7 +49,7 @@ func TestGaiaCLISend(t *testing.T) {
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak"))
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
time.Sleep(time.Second * 2) // waiting for some blocks to pass
tests.WaitForNextHeightTM(port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
@ -59,7 +58,7 @@ func TestGaiaCLISend(t *testing.T) {
// test autosequencing
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
time.Sleep(time.Second * 2) // waiting for some blocks to pass
tests.WaitForNextHeightTM(port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak"))
@ -96,7 +95,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
require.NoError(t, err)
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
tests.WaitForNextHeightTM(port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
@ -112,7 +111,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
executeWrite(t, cvStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
tests.WaitForNextHeightTM(port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
@ -131,7 +130,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
executeWrite(t, unbondStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
tests.WaitForNextHeightTM(port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
@ -150,6 +149,8 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) {
require.NoError(t, err)
}
proc.Wait()
// bz := proc.StdoutBuffer.Bytes()
// fmt.Println("EXEC WRITE", string(bz))
}
func executeInit(t *testing.T, cmdStr string) (chainID string) {
@ -170,7 +171,13 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey)
var ko keys.KeyOutput
keys.UnmarshalJSON([]byte(out), &ko)
return ko.Address, ko.PubKey
address, err := sdk.GetAccAddressBech32(ko.Address)
require.NoError(t, err)
pk, err := sdk.GetAccPubKeyBech32(ko.PubKey)
require.NoError(t, err)
return address, pk
}
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {

View File

@ -6,6 +6,7 @@ import (
"github.com/spf13/cobra"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -26,7 +27,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
server.ConstructAppCreator(newApp, "gaia"),
server.ConstructAppExporter(exportAppState, "gaia"))
server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
@ -37,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewGaiaApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
gapp := app.NewGaiaApp(logger, db)
return gapp.ExportAppStateJSON()
return gapp.ExportAppStateAndValidators()
}

View File

@ -0,0 +1,35 @@
# Gaiadebug
Simple tool for simple debugging.
We try to accept both hex and base64 formats and provide a useful response.
Note we often encode bytes as hex in the logs, but as base64 in the JSON.
## Pubkeys
The following give the same result:
```
gaiadebug pubkey TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4=
gaiadebug pubkey 4D94D09DFA8EB22F3D49EA17567230FAD9C5267AF85FCA950B453C02C126164E
```
## Txs
Pass in a hex/base64 tx and get back the full JSON
```
gaiadebug tx <hex or base64 transaction>
```
## Hack
This is a command with boilerplate for using Go as a scripting language to hack
on an existing Gaia state.
Currently we have an example for the state of gaia-6001 after it
[crashed](https://github.com/cosmos/cosmos-sdk/blob/master/cmd/gaia/testnets/STATUS.md#june-13-2018-230-est---published-postmortem-of-gaia-6001-failure).
If you run `gaiadebug hack $HOME/.gaiad` on that
state, it will do a binary search on the state history to find when the state
invariant was violated.

View File

@ -0,0 +1,243 @@
package main
import (
"encoding/base64"
"encoding/hex"
"fmt"
"os"
"path"
"github.com/spf13/cobra"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
)
func runHackCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected 1 arg")
}
// ".gaiad"
dataDir := args[0]
dataDir = path.Join(dataDir, "data")
// load the app
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
db, err := dbm.NewGoLevelDB("gaia", dataDir)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
app := NewGaiaApp(logger, db)
// print some info
id := app.LastCommitID()
lastBlockHeight := app.LastBlockHeight()
fmt.Println("ID", id)
fmt.Println("LastBlockHeight", lastBlockHeight)
//----------------------------------------------------
// XXX: start hacking!
//----------------------------------------------------
// eg. gaia-6001 testnet bug
// We paniced when iterating through the "bypower" keys.
// The following powerKey was there, but the corresponding "trouble" validator did not exist.
// So here we do a binary search on the past states to find when the powerKey first showed up ...
// owner of the validator the bonds, gets revoked, later unbonds, and then later is still found in the bypower store
trouble := hexToBytes("D3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
// this is his "bypower" key
powerKey := hexToBytes("05303030303030303030303033FFFFFFFFFFFF4C0C0000FFFED3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
topHeight := lastBlockHeight
bottomHeight := int64(0)
checkHeight := topHeight
for {
// load the given version of the state
err = app.LoadVersion(checkHeight, app.keyMain)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
ctx := app.NewContext(true, abci.Header{})
// check for the powerkey and the validator from the store
store := ctx.KVStore(app.keyStake)
res := store.Get(powerKey)
val, _ := app.stakeKeeper.GetValidator(ctx, trouble)
fmt.Println("checking height", checkHeight, res, val)
if res == nil {
bottomHeight = checkHeight
} else {
topHeight = checkHeight
}
checkHeight = (topHeight + bottomHeight) / 2
}
}
func base64ToPub(b64 string) crypto.PubKeyEd25519 {
data, _ := base64.StdEncoding.DecodeString(b64)
var pubKey crypto.PubKeyEd25519
copy(pubKey[:], data)
return pubKey
}
func hexToBytes(h string) []byte {
trouble, _ := hex.DecodeString(h)
return trouble
}
//--------------------------------------------------------------------------------
// NOTE: This is all copied from gaia/app/app.go
// so we can access internal fields!
const (
appName = "GaiaApp"
)
// default home directories for expected binaries
var (
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
)
// Extended ABCI application
type GaiaApp struct {
*bam.BaseApp
cdc *wire.Codec
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyIBC *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
keySlashing *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
slashingKeeper slashing.Keeper
}
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
cdc := MakeCodec()
// create your application object
var app = &GaiaApp{
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
cdc: cdc,
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),
keyStake: sdk.NewKVStoreKey("stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
}
// define the accountMapper
app.accountMapper = auth.NewAccountMapper(
app.cdc,
app.keyAccount, // target store
&auth.BaseAccount{}, // prototype
)
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
// initialize BaseApp
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
return app
}
// custom tx codec
func MakeCodec() *wire.Codec {
var cdc = wire.NewCodec()
ibc.RegisterWire(cdc)
bank.RegisterWire(cdc)
stake.RegisterWire(cdc)
slashing.RegisterWire(cdc)
auth.RegisterWire(cdc)
sdk.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
return cdc
}
// application updates every end block
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
return abci.ResponseBeginBlock{
Tags: tags.ToKVPairs(),
}
}
// application updates every end block
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
}
}
// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
// TODO is this now the whole genesis file?
var genesisState gaia.GenesisState
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
app.accountMapper.SetAccount(ctx, acc)
}
// load the initial stake information
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
return abci.ResponseInitChain{}
}

View File

@ -0,0 +1,159 @@
package main
import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/spf13/cobra"
crypto "github.com/tendermint/go-crypto"
)
func init() {
rootCmd.AddCommand(txCmd)
rootCmd.AddCommand(pubkeyCmd)
rootCmd.AddCommand(hackCmd)
rootCmd.AddCommand(rawBytesCmd)
}
var rootCmd = &cobra.Command{
Use: "gaiadebug",
Short: "Gaia debug tool",
SilenceUsage: true,
}
var txCmd = &cobra.Command{
Use: "tx",
Short: "Decode a gaia tx from hex or base64",
RunE: runTxCmd,
}
var pubkeyCmd = &cobra.Command{
Use: "pubkey",
Short: "Decode a pubkey from hex or base64",
RunE: runPubKeyCmd,
}
var hackCmd = &cobra.Command{
Use: "hack",
Short: "Boilerplate to Hack on an existing state by scripting some Go...",
RunE: runHackCmd,
}
var rawBytesCmd = &cobra.Command{
Use: "raw-bytes",
Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex",
RunE: runRawBytesCmd,
}
func runRawBytesCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
stringBytes := args[0]
stringBytes = strings.Trim(stringBytes, "[")
stringBytes = strings.Trim(stringBytes, "]")
spl := strings.Split(stringBytes, " ")
byteArray := []byte{}
for _, s := range spl {
b, err := strconv.Atoi(s)
if err != nil {
return err
}
byteArray = append(byteArray, byte(b))
}
fmt.Printf("%X\n", byteArray)
return nil
}
func runPubKeyCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
pubkeyString := args[0]
// try hex, then base64
pubkeyBytes, err := hex.DecodeString(pubkeyString)
if err != nil {
var err2 error
pubkeyBytes, err2 = base64.StdEncoding.DecodeString(pubkeyString)
if err2 != nil {
return fmt.Errorf(`Expected hex or base64. Got errors:
hex: %v,
base64: %v
`, err, err2)
}
}
cdc := gaia.MakeCodec()
var pubKey crypto.PubKeyEd25519
copy(pubKey[:], pubkeyBytes)
pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey)
if err != nil {
return err
}
fmt.Println("Address:", pubKey.Address())
fmt.Printf("Hex: %X\n", pubkeyBytes)
fmt.Println("JSON (base64):", string(pubKeyJSONBytes))
return nil
}
func runTxCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
txString := args[0]
// try hex, then base64
txBytes, err := hex.DecodeString(txString)
if err != nil {
var err2 error
txBytes, err2 = base64.StdEncoding.DecodeString(txString)
if err2 != nil {
return fmt.Errorf(`Expected hex or base64. Got errors:
hex: %v,
base64: %v
`, err, err2)
}
}
var tx = auth.StdTx{}
cdc := gaia.MakeCodec()
err = cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return err
}
bz, err := cdc.MarshalJSON(tx)
if err != nil {
return err
}
buf := bytes.NewBuffer([]byte{})
err = json.Indent(buf, bz, "", " ")
if err != nil {
return err
}
fmt.Println(buf.String())
return nil
}
func main() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
os.Exit(0)
}

258
cmd/gaia/testnets/README.md Normal file
View File

@ -0,0 +1,258 @@
# Connect to the `gaia-6002` Testnet
Note: We are aware this documentation is sub-par. We are working to
improve the tooling and the documentation to make this process as painless as
possible. In the meantime, join the
[Validator Chat](https://riot.im/app/#/room/#cosmos_validators:matrix.org)
for technical support. Thanks very much for your patience. :)
## Setting Up a New Node
These instructions are for setting up a brand new full node from scratch. If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet).
### Install Go
Install `go` by following the [official docs](https://golang.org/doc/install).
**Go 1.10+** is required for the Cosmos SDK.
### Install Cosmos SDK
Next, let's install the testnet's version of the Cosmos SDK.
```
mkdir -p $GOPATH/src/github.com/cosmos
cd $GOPATH/src/github.com/cosmos
git clone https://github.com/cosmos/cosmos-sdk
cd cosmos-sdk && git checkout v0.19.0
make get_tools && make get_vendor_deps && make install
```
That will install the `gaiad` and `gaiacli` binaries. Verify that everything is OK:
```
gaiad version
0.19.0-<commit>
```
### Node Setup
Create the required configuration files:
```
gaiad init
```
Name your node by editing the `moniker` in `$HOME/.gaiad/config/config.toml`. Note that only ASCII characters are supported. Using Unicode renders your node unconnectable.
```
# A custom human readable name for this node
moniker = "<your_custom_name>"
```
Your full node has been initialized! Please skip to [Genesis & Seeds](#genesis--seeds).
## Upgrading From Previous Testnet
These instructions are for full nodes that have ran on previous testnets and would like to upgrade to the latest testnet.
### Reset Data
First, remove the outdated files and reset the data.
```
rm $HOME/.gaiad/config/addrbook.json $HOME/.gaiad/config/genesis.json
gaiad unsafe_reset_all
```
Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before,
your node will still try to connect to them, but may fail if they haven't also
been upgraded.
**WARNING:** Make sure that every node has a unique `priv_validator.json`. Do not copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign.
### Software Upgrade
Now it is time to upgrade the software:
```
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
git fetch --all && git checkout v0.19.0
make update_tools && make get_vendor_deps && make install
```
Your full node has been cleanly upgraded!
## Genesis & Seeds
### Copy the Genesis File
Copy the testnet's `genesis.json` file and place it in `gaiad`'s config directory.
```
mkdir -p $HOME/.gaiad/config
cp -a $GOPATH/src/github.com/cosmos/cosmos-sdk/cmd/gaia/testnets/gaia-6002/genesis.json $HOME/.gaiad/config/genesis.json
```
### Add Seed Nodes
Your node needs to know how to find peers. You'll need to add healthy seed nodes to `$HOME/.gaiad/config/config.toml`. Here are some seed nodes you can use:
```
# Comma separated list of seed nodes to connect to
seeds = "38aa9bec3998f12ae9088b21a2d910d19d565c27@gaia-6002.coinculture.net:46656,80a35a46ce09cfb31ee220c8141a25e73e0b239b@seed.cosmos.cryptium.ch:46656,80a35a46ce09cfb31ee220c8141a25e73e0b239b@35.198.166.171:46656,032fa56301de335d835057fb6ad9f7ce2242a66d@165.227.236.213:46656"
```
You can also [ask other validators](https://riot.im/app/#/room/#cosmos_validators:matrix.org) for a persistent peer and add it under the `persistent_peers` key. For more information on seeds and peers, [read this](https://github.com/tendermint/tendermint/blob/develop/docs/using-tendermint.md#peers).
## Run a Full Node
Start the full node with this command:
```
gaiad start
```
Check that everything is running smoothly:
```
gaiacli status
```
View the status of the network with the [Cosmos Explorer](https://explorecosmos.network). Once your full node syncs up to the current block height, you should see it appear on the [list of full nodes](https://explorecosmos.network/validators). If it doesn't show up, that's ok--the Explorer does not connect to every node.
## Generate Keys
You'll need a private and public key pair \(a.k.a. `sk, pk` respectively\) to be able to receive funds, send txs, bond tx, etc.
To generate a new key \(default _ed25519_ elliptic curve\):
```
gaiacli keys add <your_key_name>
```
Next, you will have to create a passphrase. Save the _seed_ _phrase_ in a safe place in case you forget the password.
If you check your private keys, you'll now see `<your_key_name>`:
```
gaiacli keys show <your_key_name>
```
You can see all your available keys by typing:
```
gaiacli keys list
```
View the validator pubkey for your node by typing:
```
gaiad tendermint show_validator
```
Save your address and pubkey to environment variables for later use:
```
MYADDR=<your_newly_generated_address>
MYPUBKEY=<your_newly_generated_public_key>
```
**WARNING:** We strongly recommend NOT using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
## Get Tokens
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org).
After receiving tokens to your address, you can view your account's balance by typing:
```
gaiacli account <your_newly_generated_address>
```
Note: When you query an account balance with zero tokens, you will get this error: `No account with address <your_newly_generated_address> was found in the state.` This is expected! We're working on improving our error messages.
## Send Tokens
```
gaiacli send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --name=<key_name> --to=<destination_address>
```
Note: The `--amount` flag accepts the format `--amount=<value|coin_name>`.
Now, view the updated balances of the origin and destination accounts:
```
gaiacli account <origin_address>
gaiacli account <destination_address>
```
You can also check your balance at a given block by using the `--block` flag:
```
gaiacli account <your_address> --block=<block_height>
```
## Run a Validator Node
[Validators](https://cosmos.network/validators) are responsible for committing new blocks to the blockchain through voting. A validator's stake is slashed if they become unavailable, double sign a transaction, or don't cast their votes. If you only want to run a full node, a VM in the cloud is fine. However, if you are want to become a validator for the Hub's `mainnet`, you should research hardened setups. Please read [Sentry Node Architecture](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#how-can-validators-protect-themselves-from-denial-of-service-attacks) to protect your node from DDOS and ensure high-availability. Also see the [technical requirements](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#technical-requirements)). There's also more info on our [website](https://cosmos.network/validators).
Your `pubkey` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
```
gaiad tendermint show_validator
```
Next, craft your `gaiacli stake create-validator` command:
```
gaiacli stake create-validator --amount=5steak --pubkey=<your_node_pubkey> --address-validator=<your_address> --moniker=satoshi --chain-id=<name_of_the_testnet_chain> --name=<key_name>
```
You can add more information to the validator, such as`--website`, `--keybase-sig`, or `--details`. Here's how:
```
gaiacli stake edit-validator --details="To the cosmos !" --website="https://cosmos.network"
```
View the validator's information with this command:
```
gaiacli stake validator --address-validator=<your_address> --chain-id=<name_of_the_testnet_chain>
```
To check that the validator is active, look for it here:
```
gaiacli advanced tendermint validator-set
```
**Note:** To be in the validator set, you need to have more total voting power than the 100th validator.
## Delegating to a Validator
On the upcoming mainnet, you can delegate `atom` to a validator. These [delegators](https://cosmos.network/resources/delegators) can receive part of the validator's fee revenue. Read more about the [Cosmos Token Model](https://github.com/cosmos/cosmos/raw/master/Cosmos_Token_Model.pdf).
### Bond Tokens
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator:
```
gaiacli stake delegate --amount=10steak --address-delegator=<your_address> --address-validator=<bonded_validator_address> --name=<key_name> --chain-id=<name_of_testnet_chain>
```
While tokens are bonded, they are pooled with all the other bonded tokens in the network. Validators and delegators obtain a percentage of shares that equal their stake in this pool.
### Unbond Tokens
If for any reason the validator misbehaves, or you want to unbond a certain amount of tokens, use this following command. You can unbond a specific amount of`shares`\(eg:`12.1`\) or all of them \(`MAX`\).
```
gaiacli stake unbond --address-delegator=<your_address> --address-validator=<bonded_validator_address> --shares=MAX --name=<key_name> --chain-id=<name_of_testnet_chain>
```
You can check your balance and your stake delegation to see that the unbonding went through successfully.
```
gaiacli account <your_address>
gaiacli stake delegation --address-delegator=<your_address> --address-validator=<bonded_validator_address> --chain-id=<name_of_testnet_chain>
```

101
cmd/gaia/testnets/STATUS.md Normal file
View File

@ -0,0 +1,101 @@
# TESTNET STATUS
## *June 13, 2018, 17:00 EST* - Gaia-6002 is making blocks!
- Gaia-6002 is live and making blocks
- Absent validators have been slashed and revoked
- Currently live with 17 validators
## *June 13, 2018, 4:30 EST* - New Testnet Gaia-6002
- After fixing bugs from gaia-6001, especially [issue
#1197](https://github.com/cosmos/cosmos-sdk/issues/1197), we are announcing a
new testnet, Gaia-6002
- Gaia-6002 has the same genesis file as Gaia-6001, just with the chain-id
updated
- Update from previous testnet [here](https://github.com/cosmos/cosmos-sdk/tree/master/cmd/gaia/testnets#upgrading-from-previous-testnet)
## *June 13, 2018, 4:30 EST* - New Release
- Released gaia
[v0.19.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.19.0)
- Includes various bug-fixes for staking found on Gaia-6001
## *June 13, 2018, 2:30 EST* - Published Postmortem of Gaia-6001 failure
- A bug in the design of the staking data model caused a sanity check to fail
- Full writeup
[here](https://github.com/cosmos/cosmos-sdk/issues/1197#issuecomment-396823021)
## *June 10, 2018, 8:30 EST* - Gaia-6001 consensus failure
- Validator unbonding and revocation activity caused a consensus failure
- There is a bug in the staking module that must be fixed
- The team is taking its time to look into this and release a fix following a
proper protocol for hotfix upgrades to the testnet
- Please stay tuned!
## *June 9, 2018, 14:00 EST* - New Release
- Released gaia
[v0.18.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.18.0) with
update for Tendermint
[v0.20.0](https://github.com/tendermint/tendermint/releases/tag/v0.20.0)
- Includes bug fix for declaring candidacy from the command line
## *June 8, 2018, 23:30 EST* - Gaia-6001 is making blocks
- +2/3 of the voting power is finally online for Gaia-6001 and it is making
blocks!
- This is a momentous achievement - a successful asynchronous decentralized
testnet launch
- Congrats everyone!
## *June 8, 2018, 12:00 EST* - New Testnet Gaia-6001
- After some confusion around testnet deployment and a contention testnet
hardfork, a new genesis file and network was released for `gaia-6001`
## *June 7, 2018, 9:00 EST* - New Testnet Gaia-6000
- Released a new `genesis.json` file for `gaia-6000`
- Initial validators include those that were most active in
the gaia-5001 testnet
- Join the network via gaia `v0.18.0-rc0`
## *June 5, 2018, 21:00 EST* - New Release
- Released gaia
[v0.17.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.5)
with update for Tendermint
[v0.19.9](https://github.com/tendermint/tendermint/releases/tag/v0.19.9)
- Fixes many bugs!
- evidence gossipping
- mempool deadlock
- WAL panic
- memory leak
- Please update to this to put a stop to the rampant invalid evidence gossiping
:)
## *May 31, 2018, 14:00 EST* - New Release
- Released gaia
[v0.17.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.4) with update for Tendermint v0.19.7
- Fixes a WAL bug and some more
- Please update to this if you have trouble restarting a node
## *May 31, 2018, 2:00 EST* - Testnet Halt
- A validator equivocated last week and Evidence is being rampantly gossipped
- Peers that can't process the evidence (either too far behind or too far ahead) are disconnecting from the peers that
sent it, causing high peer turn-over
- The high peer turn-over may be causing a memory-leak, resulting in some nodes
crashing and the testnet halting
- We need to fix some issues in the EvidenceReactor to address this and also
investigate the possible memory-leak
## *May 29, 2018* - New Release
- Released v0.17.3 with update for Tendermint v0.19.6
- Fixes fast-sync bug
- Please update to this to sync with the testnet

View File

@ -0,0 +1,20 @@
{
"node_id": "1ebc5ca705b3ae1c06a0888ff1287ada82149dc3",
"ip": "138.68.77.24",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
},
"power": 100,
"name": "adrian"
},
"app_gen_tx": {
"name": "default",
"address": "D9C12CB5186FE0018179742FD3110EE534C63460",
"pub_key": {
"type": "AC26791624DE60",
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "c272ae3cff7558db2c6195eea38fd43fd08406dc",
"ip": "206.189.31.178",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
},
"power": 100,
"name": "anton"
},
"app_gen_tx": {
"name": "default",
"address": "E766088FD171906289617F60BF0014C46F0F85EC",
"pub_key": {
"type": "AC26791624DE60",
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "aef085c4bfed0c1ffc6705f2e1e3bf85e5164600",
"ip": "45.77.53.208",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
},
"power": 100,
"name": "aurel"
},
"app_gen_tx": {
"name": "aurel",
"address": "10B0899E05A486AE4E5589C39587DF7E9A185872",
"pub_key": {
"type": "AC26791624DE60",
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "b0dd378c3fbc4c156cd6d302a799f0d2e4227201",
"ip": "159.89.121.174",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
},
"power": 100,
"name": "bucky"
},
"app_gen_tx": {
"name": "bucky",
"address": "935E48ED79F1006ED135553768E1D9A768747CF6",
"pub_key": {
"type": "AC26791624DE60",
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "e25603602d8cf8542570ad0e311d50f55f497f85",
"ip": "158.69.63.13",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
},
"power": 100,
"name": "cwgoes"
},
"app_gen_tx": {
"name": "cwgoes",
"address": "328FBB8EA315D070DF908982A5F91A3618001D20",
"pub_key": {
"type": "AC26791624DE60",
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "aabf05a67b2f399807dc602d05bf97b0ed283ac2",
"ip": "116.62.62.39",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
},
"power": 100,
"name": "iris"
},
"app_gen_tx": {
"name": "=suyu",
"address": "4B5BE759EB23B0D76C6A60636BD0E3111178794E",
"pub_key": {
"type": "AC26791624DE60",
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "79466a03e9d4b4648a7dd8cead1fa7121ce76ee3",
"ip": "34.235.130.1",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
},
"power": 100,
"name": "lino"
},
"app_gen_tx": {
"name": "lino",
"address": "5A007B81A25AF34B829B79DA508A26E12180BCDB",
"pub_key": {
"type": "AC26791624DE60",
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "adb290585a2753bf1a520c76802b0dab3dffa895",
"ip": "34.201.21.179",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
},
"power": 100,
"name": "pbostrom"
},
"app_gen_tx": {
"name": "default",
"address": "109720515B4F8C0858DA3521E448262334534FFD",
"pub_key": {
"type": "AC26791624DE60",
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "678503e6c8f50db7279c7da3cb9b072aac4bc0d5",
"ip": "35.193.188.125",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
},
"power": 100,
"name": "polsdam"
},
"app_gen_tx": {
"name": "poldsam",
"address": "FA929191B04C5DB222AFC6F15C63EF48CCC864C5",
"pub_key": {
"type": "AC26791624DE60",
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "3519f05985394107e0b2e285361b7e012adb1113",
"ip": "54.209.118.64",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
},
"power": 100,
"name": "staked"
},
"app_gen_tx": {
"name": "default",
"address": "935E04662697134905706A4CCDB822AC6FC11C2E",
"pub_key": {
"type": "AC26791624DE60",
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "8a2802fb25d352f3e7e277559a4f683780c3ef22",
"ip": "167.99.191.184",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
},
"power": 100,
"name": ""
},
"app_gen_tx": {
"name": "zach",
"address": "9D5723057702E2090405AB5D3B48C45B9ABF4377",
"pub_key": {
"type": "AC26791624DE60",
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
}
}
}

View File

@ -0,0 +1,20 @@
{
"node_id": "30b45459e4881680c0ef1750fde136fefa6c3b98",
"ip": "35.184.182.143",
"validator": {
"pub_key": {
"type": "AC26791624DE60",
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
},
"power": 100,
"name": "zaki"
},
"app_gen_tx": {
"name": "zaki",
"address": "ECE57661F0CDCF28EED257B72F86240E57F4A612",
"pub_key": {
"type": "AC26791624DE60",
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -78,7 +78,7 @@ window. Here run:
::
basecli init --node=tcp://localhost:46657 --genesis=$HOME/.basecoin/genesis.json
basecli init --node=tcp://localhost:26657 --genesis=$HOME/.basecoin/genesis.json
If you provide the genesis file to basecli, it can calculate the proper
chainID and validator hash. Basecli needs to get this information from

View File

@ -49,7 +49,7 @@ initialize the light-client and send a transaction:
::
countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json
countercli init --node=tcp://localhost:26657 --genesis=$HOME/.counter/genesis.json
YOU=$(countercli keys get friend | awk '{print $2}')
countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1

View File

@ -39,18 +39,18 @@ and ports. It should look like:
::
proxy_app = "tcp://127.0.0.1:46668"
proxy_app = "tcp://127.0.0.1:26668"
moniker = "anonymous"
fast_sync = true
db_backend = "leveldb"
log_level = "state:info,*:error"
[rpc]
laddr = "tcp://0.0.0.0:46667"
laddr = "tcp://0.0.0.0:26667"
[p2p]
laddr = "tcp://0.0.0.0:46666"
seeds = "0.0.0.0:46656"
laddr = "tcp://0.0.0.0:26666"
seeds = "0.0.0.0:26656"
Start Nodes
-----------
@ -69,14 +69,14 @@ account:
::
gaia client init --chain-id=gaia-test --node=tcp://localhost:46657
gaia client init --chain-id=gaia-test --node=tcp://localhost:26657
gaia client query account 5D93A6059B6592833CBC8FA3DA90EE0382198985
To see what tendermint considers the validator set is, use:
::
curl localhost:46657/validators
curl localhost:26657/validators
and compare the information in this file: ``~/.gaia1/priv_validator.json``. The ``address`` and ``pub_key`` fields should match.

View File

@ -49,7 +49,7 @@ Finally, let's initialize the gaia client to interact with the testnet:
::
gaia client init --chain-id=gaia-1 --node=tcp://localhost:46657
gaia client init --chain-id=gaia-1 --node=tcp://localhost:26657
and check our balance:

View File

@ -41,7 +41,7 @@ paths:
type: string
listen_addr:
type: string
example: 192.168.56.1:46656
example: 192.168.56.1:26656
version:
description: Tendermint version
type: string
@ -102,7 +102,7 @@ paths:
- application/json
responses:
200:
description: 12 word Seed
description: 16 word Seed
schema:
type: string
/keys/{name}:
@ -204,7 +204,7 @@ paths:
parameters:
- in: path
name: address
description: Account address
description: Account address in bech32 format
required: true
type: string
get:
@ -222,7 +222,7 @@ paths:
parameters:
- in: path
name: address
description: Account address
description: Account address in bech32 format
required: true
type: string
post:
@ -255,18 +255,6 @@ paths:
description: Tx was send and will probably be added to the next block
400:
description: The Tx was malformated
/accounts/{address}/nonce:
parameters:
- in: path
name: address
description: Account address
required: true
type: string
get:
summary: Get the nonce for a certain account
responses:
200:
description: Plaintext nonce i.e. "4" defaults to "0"
/blocks/latest:
get:
summary: Get the latest block
@ -304,9 +292,14 @@ paths:
200:
description: The validator set at the latest block height
schema:
type: array
items:
$ref: "#/definitions/Delegate"
type: object
properties:
block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
/validatorsets/{height}:
parameters:
- in: path
@ -322,9 +315,14 @@ paths:
200:
description: The validator set at a specific block height
schema:
type: array
items:
$ref: "#/definitions/Delegate"
type: object
properties:
block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
404:
description: Block at height not available
# /txs:
@ -549,7 +547,20 @@ paths:
definitions:
Address:
type: string
example: DF096FDE8D380FA5B2AD20DB2962C82DDEA1ED9B
description: bech32 encoded addres
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorAddress:
type: string
description: bech32 encoded addres
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
PubKey:
type: string
description: bech32 encoded public key
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorPubKey:
type: string
description: bech32 encoded public key
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
Coins:
type: object
properties:
@ -652,16 +663,6 @@ definitions:
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
Pubkey:
$ref: "#/definitions/PubKey"
PubKey:
type: object
properties:
type:
type: string
enum:
- ed25519
data:
type: string
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
Account:
type: object
properties:
@ -753,17 +754,19 @@ definitions:
type: array
items:
type: object
Delegate:
Validator:
type: object
properties:
address:
$ref: '#/definitions/ValidatorAddress'
pub_key:
$ref: "#/definitions/PubKey"
$ref: "#/definitions/ValidatorPubKey"
power:
type: number
example: 1000
name:
type: string
example: "159.89.3.34"
accum:
type: number
example: 1000
# Added by API Auto Mocking Plugin
host: virtserver.swaggerhub.com
basePath: /faboweb1/Cosmos-LCD-2/1.0.0

View File

@ -232,12 +232,14 @@ a standard form:
type StdSignature struct {
crypto.PubKey // optional
crypto.Signature
Sequence int64
AccountNumber int64
Sequence int64
}
It contains the signature itself, as well as the corresponding account's
sequence number. The sequence number is expected to increment every time a
message is signed by a given account. This prevents "replay attacks", where
It contains the signature itself, as well as the corresponding account's account and
sequence numbers. The sequence number is expected to increment every time a
message is signed by a given account. The account number stays the same and is assigned
when the account is first generated. These prevent "replay attacks", where
the same message could be executed over and over again.
The ``StdSignature`` can also optionally include the public key for verifying the

View File

@ -291,7 +291,7 @@ To confirm for certain the new validator is active, ask the tendermint node:
::
curl localhost:46657/validators
curl localhost:26657/validators
If you now kill either node, blocks will stop streaming in, because
there aren't enough validators online. Turn it back on and they will

View File

@ -66,7 +66,7 @@ To confirm for certain the new validator is active, check tendermint:
::
curl localhost:46657/validators
curl localhost:26657/validators
Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase.

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -145,6 +146,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx)
app.accountMapper.SetAccount(ctx, acc)
}
@ -155,7 +157,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
}
// Custom logic for state export
func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
@ -173,5 +175,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
genState := types.GenesisState{
Accounts: accounts,
}
return wire.MarshalJSONIndent(app.cdc, genState)
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, err
}

View File

@ -1,8 +1,6 @@
package app
import (
"encoding/json"
"fmt"
"os"
"testing"
@ -13,8 +11,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/stake"
abci "github.com/tendermint/abci/types"
@ -23,74 +19,10 @@ import (
"github.com/tendermint/tmlibs/log"
)
// Construct some global addrs and txs for tests.
var (
chainID = "" // TODO
accName = "foobart"
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
priv2 = crypto.GenPrivKeyEd25519()
addr2 = priv2.PubKey().Address()
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
priv4 = crypto.GenPrivKeyEd25519()
addr4 = priv4.PubKey().Address()
coins = sdk.Coins{{"foocoin", 10}}
halfCoins = sdk.Coins{{"foocoin", 5}}
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
fee = auth.StdFee{
sdk.Coins{{"foocoin", 0}},
100000,
}
sendMsg1 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
sendMsg2 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{
bank.NewOutput(addr2, halfCoins),
bank.NewOutput(addr3, halfCoins),
},
}
sendMsg3 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, coins),
bank.NewInput(addr4, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, coins),
bank.NewOutput(addr3, coins),
},
}
sendMsg4 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr2, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr1, coins),
},
}
sendMsg5 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, manyCoins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, manyCoins),
},
}
)
func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
genaccs := make([]*types.GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName})
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, "foobart"})
}
genesisState := types.GenesisState{
@ -111,79 +43,11 @@ func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
return nil
}
func loggerAndDB() (log.Logger, dbm.DB) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
return logger, db
}
func newBasecoinApp() *BasecoinApp {
logger, db := loggerAndDB()
return NewBasecoinApp(logger, db)
}
//_______________________________________________________________________
func TestMsgs(t *testing.T) {
bapp := newBasecoinApp()
require.Nil(t, setGenesis(bapp))
msgs := []struct {
msg sdk.Msg
}{
{sendMsg1},
}
for i, m := range msgs {
// Run a CheckDeliver
SignCheckDeliver(t, bapp, m.msg, []int64{int64(i)}, false, priv1)
}
}
func TestSortGenesis(t *testing.T) {
logger, db := loggerAndDB()
bapp := NewBasecoinApp(logger, db)
// Note the order: the coins are unsorted!
coinDenom1, coinDenom2 := "foocoin", "barcoin"
genState := fmt.Sprintf(`{
"accounts": [{
"address": "%s",
"coins": [
{
"denom": "%s",
"amount": 10
},
{
"denom": "%s",
"amount": 20
}
]
}]
}`, addr1.String(), coinDenom1, coinDenom2)
// Initialize the chain
vals := []abci.Validator{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: []byte(genState)})
bapp.Commit()
// Unsorted coins means invalid
err := sendMsg5.ValidateBasic()
require.Equal(t, sdk.CodeInvalidCoins, err.Code(), err.ABCILog())
// Sort coins, should be valid
sendMsg5.Inputs[0].Coins.Sort()
sendMsg5.Outputs[0].Coins.Sort()
err = sendMsg5.ValidateBasic()
require.Nil(t, err)
// Ensure we can send
SignCheckDeliver(t, bapp, sendMsg5, []int64{0}, true, priv1)
}
func TestGenesis(t *testing.T) {
logger, db := loggerAndDB()
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
bapp := NewBasecoinApp(logger, db)
// Construct some genesis bytes to reflect basecoin/types/AppAccount
@ -211,318 +75,3 @@ func TestGenesis(t *testing.T) {
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, acc, res1)
}
func TestMsgChangePubKey(t *testing.T) {
bapp := newBasecoinApp()
// Construct some genesis bytes to reflect basecoin/types/AppAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: coins,
}
// Construct genesis state
err = setGenesis(bapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
// Run a CheckDeliver
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, bapp, addr1, "67foocoin")
CheckBalance(t, bapp, addr2, "10foocoin")
changePubKeyMsg := auth.MsgChangeKey{
Address: addr1,
NewPubKey: priv2.PubKey(),
}
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
acc := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
// send a MsgChangePubKey
SignCheckDeliver(t, bapp, changePubKeyMsg, []int64{1}, true, priv1)
acc = bapp.accountMapper.GetAccount(ctxDeliver, addr1)
assert.True(t, priv2.PubKey().Equals(acc.GetPubKey()))
// signing a SendMsg with the old privKey should be an auth error
tx := genTx(sendMsg1, []int64{2}, priv1)
res := bapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the new correct priv key should work
SignCheckDeliver(t, bapp, sendMsg1, []int64{2}, true, priv2)
// Check balances
CheckBalance(t, bapp, addr1, "57foocoin")
CheckBalance(t, bapp, addr2, "20foocoin")
}
func TestMsgSendWithAccounts(t *testing.T) {
bapp := newBasecoinApp()
// Construct some genesis bytes to reflect basecoin/types/AppAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: coins,
}
// Construct genesis state
err = setGenesis(bapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
// Run a CheckDeliver
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, bapp, addr1, "67foocoin")
CheckBalance(t, bapp, addr2, "10foocoin")
// Delivering again should cause replay error
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, false, priv1)
// bumping the txnonce number without resigning should be an auth error
tx := genTx(sendMsg1, []int64{0}, priv1)
tx.Signatures[0].Sequence = 1
res := bapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1)
}
func TestMsgSendMultipleOut(t *testing.T) {
bapp := newBasecoinApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
// Construct genesis state
err = setGenesis(bapp, acc1, acc2)
require.Nil(t, err)
// Simulate a Block
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, bapp, addr1, "32foocoin")
CheckBalance(t, bapp, addr2, "47foocoin")
CheckBalance(t, bapp, addr3, "5foocoin")
}
func TestSengMsgMultipleInOut(t *testing.T) {
bapp := newBasecoinApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
acc4 := auth.BaseAccount{
Address: addr4,
Coins: genCoins,
}
err = setGenesis(bapp, acc1, acc2, acc4)
assert.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, bapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
// Check balances
CheckBalance(t, bapp, addr1, "32foocoin")
CheckBalance(t, bapp, addr4, "32foocoin")
CheckBalance(t, bapp, addr2, "52foocoin")
CheckBalance(t, bapp, addr3, "10foocoin")
}
func TestMsgSendDependent(t *testing.T) {
bapp := newBasecoinApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
// Construct genesis state
err = setGenesis(bapp, acc1)
require.Nil(t, err)
err = setGenesis(bapp, acc1)
assert.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, bapp, addr1, "32foocoin")
CheckBalance(t, bapp, addr2, "10foocoin")
// Simulate a Block
SignCheckDeliver(t, bapp, sendMsg4, []int64{0}, true, priv2)
// Check balances
CheckBalance(t, bapp, addr1, "42foocoin")
}
func TestMsgQuiz(t *testing.T) {
bapp := newBasecoinApp()
// Construct genesis state
// Construct some genesis bytes to reflect basecoin/types/AppAccount
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: nil,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
// Construct genesis state
genesisState := map[string]interface{}{
"accounts": []*types.GenesisAccount{
types.NewGenesisAccount(acc1),
},
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
require.Nil(t, err)
// Initialize the chain (nil)
vals := []abci.Validator{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
}
func TestIBCMsgs(t *testing.T) {
bapp := newBasecoinApp()
sourceChain := "source-chain"
destChain := "dest-chain"
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: coins,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
err := setGenesis(bapp, baseAcc)
assert.Nil(t, err)
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
packet := ibc.IBCPacket{
SrcAddr: addr1,
DestAddr: addr1,
Coins: coins,
SrcChain: sourceChain,
DestChain: destChain,
}
transferMsg := ibc.IBCTransferMsg{
IBCPacket: packet,
}
receiveMsg := ibc.IBCReceiveMsg{
IBCPacket: packet,
Relayer: addr1,
Sequence: 0,
}
SignCheckDeliver(t, bapp, transferMsg, []int64{0}, true, priv1)
CheckBalance(t, bapp, addr1, "")
SignCheckDeliver(t, bapp, transferMsg, []int64{1}, false, priv1)
SignCheckDeliver(t, bapp, receiveMsg, []int64{2}, true, priv1)
CheckBalance(t, bapp, addr1, "10foocoin")
SignCheckDeliver(t, bapp, receiveMsg, []int64{3}, false, priv1)
}
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx {
sigs := make([]auth.StdSignature, len(priv))
for i, p := range priv {
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)),
Sequence: seq[i],
}
}
return auth.NewStdTx(msg, fee, sigs)
}
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Run a Check
res := bapp.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
// Simulate a Block
bapp.BeginBlock(abci.RequestBeginBlock{})
res = bapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
bapp.EndBlock(abci.RequestEndBlock{})
//bapp.Commit()
}
func CheckBalance(t *testing.T, bapp *BasecoinApp, addr sdk.Address, balExpected string) {
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr)
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
}

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -27,7 +28,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
server.ConstructAppCreator(newApp, "basecoin"),
server.ConstructAppExporter(exportAppState, "basecoin"))
server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.basecoind")
@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewBasecoinApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
bapp := app.NewBasecoinApp(logger, db)
return bapp.ExportAppStateJSON()
return bapp.ExportAppStateAndValidators()
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
}
// Custom logic for state export
func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
}
return wire.MarshalJSONIndent(app.cdc, genState)
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
return appState, validators, nil
}

View File

@ -2,7 +2,6 @@ package app
import (
"encoding/json"
"fmt"
"os"
"testing"
@ -10,12 +9,8 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
@ -23,101 +18,9 @@ import (
"github.com/tendermint/tmlibs/log"
)
// Construct some global addrs and txs for tests.
var (
chainID = "" // TODO
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
coins = sdk.Coins{{"foocoin", 10}}
fee = auth.StdFee{
sdk.Coins{{"foocoin", 0}},
1000000,
}
sendMsg = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
quizMsg1 = cool.MsgQuiz{
Sender: addr1,
CoolAnswer: "icecold",
}
quizMsg2 = cool.MsgQuiz{
Sender: addr1,
CoolAnswer: "badvibesonly",
}
setTrendMsg1 = cool.MsgSetTrend{
Sender: addr1,
Cool: "icecold",
}
setTrendMsg2 = cool.MsgSetTrend{
Sender: addr1,
Cool: "badvibesonly",
}
setTrendMsg3 = cool.MsgSetTrend{
Sender: addr1,
Cool: "warmandkind",
}
)
func loggerAndDB() (log.Logger, dbm.DB) {
func TestGenesis(t *testing.T) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
return logger, db
}
func newDemocoinApp() *DemocoinApp {
logger, db := loggerAndDB()
return NewDemocoinApp(logger, db)
}
//_______________________________________________________________________
func TestMsgs(t *testing.T) {
bapp := newDemocoinApp()
msgs := []struct {
msg sdk.Msg
}{
{sendMsg},
{quizMsg1},
{setTrendMsg1},
}
sequences := []int64{0}
for i, m := range msgs {
sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, m.msg))
tx := auth.NewStdTx(m.msg, fee, []auth.StdSignature{{
PubKey: priv1.PubKey(),
Signature: sig,
}})
// just marshal/unmarshal!
txBytes, err := bapp.cdc.MarshalBinary(tx)
require.NoError(t, err, "i: %v", i)
// Run a Check
cres := bapp.CheckTx(txBytes)
assert.Equal(t, sdk.CodeUnknownAddress,
sdk.CodeType(cres.Code), "i: %v, log: %v", i, cres.Log)
// Simulate a Block
bapp.BeginBlock(abci.RequestBeginBlock{})
dres := bapp.DeliverTx(txBytes)
assert.Equal(t, sdk.CodeUnknownAddress,
sdk.CodeType(dres.Code), "i: %v, log: %v", i, dres.Log)
}
}
func TestGenesis(t *testing.T) {
logger, db := loggerAndDB()
bapp := NewDemocoinApp(logger, db)
// Construct some genesis bytes to reflect democoin/types/AppAccount
@ -156,272 +59,3 @@ func TestGenesis(t *testing.T) {
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, acc, res1)
}
func TestMsgSendWithAccounts(t *testing.T) {
bapp := newDemocoinApp()
// Construct some genesis bytes to reflect democoin/types/AppAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: coins,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
// Construct genesis state
genesisState := map[string]interface{}{
"accounts": []*types.GenesisAccount{
types.NewGenesisAccount(acc1),
},
"cool": map[string]string{
"trend": "ice-cold",
},
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
require.Nil(t, err)
// Initialize the chain
vals := []abci.Validator{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
// Sign the tx
sequences := []int64{0}
sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, sendMsg))
tx := auth.NewStdTx(sendMsg, fee, []auth.StdSignature{{
PubKey: priv1.PubKey(),
Signature: sig,
}})
// Run a Check
res := bapp.Check(tx)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
// Simulate a Block
bapp.BeginBlock(abci.RequestBeginBlock{})
res = bapp.Deliver(tx)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
// Check balances
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
// Delivering again should cause replay error
res = bapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInvalidSequence), sdk.ABCICodeType(res.Code), res.Log)
// bumping the txnonce number without resigning should be an auth error
tx.Signatures[0].Sequence = 1
res = bapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), sdk.ABCICodeType(res.Code), res.Log)
// resigning the tx with the bumped sequence should work
sequences = []int64{1}
sig = priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, tx.Msg))
tx.Signatures[0].Signature = sig
res = bapp.Deliver(tx)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
}
func TestMsgMine(t *testing.T) {
bapp := newDemocoinApp()
// Construct genesis state
// Construct some genesis bytes to reflect democoin/types/AppAccount
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: nil,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
// Construct genesis state
genesisState := map[string]interface{}{
"accounts": []*types.GenesisAccount{
types.NewGenesisAccount(acc1),
},
"cool": map[string]string{
"trend": "ice-cold",
},
"pow": map[string]uint64{
"difficulty": 1,
"count": 0,
},
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
require.Nil(t, err)
// Initialize the chain (nil)
vals := []abci.Validator{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
// Mine and check for reward
mineMsg1 := pow.GenerateMsgMine(addr1, 1, 2)
SignCheckDeliver(t, bapp, mineMsg1, 0, true)
CheckBalance(t, bapp, "1pow")
// Mine again and check for reward
mineMsg2 := pow.GenerateMsgMine(addr1, 2, 3)
SignCheckDeliver(t, bapp, mineMsg2, 1, true)
CheckBalance(t, bapp, "2pow")
// Mine again - should be invalid
SignCheckDeliver(t, bapp, mineMsg2, 1, false)
CheckBalance(t, bapp, "2pow")
}
func TestMsgQuiz(t *testing.T) {
bapp := newDemocoinApp()
// Construct genesis state
// Construct some genesis bytes to reflect democoin/types/AppAccount
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: nil,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
// Construct genesis state
genesisState := map[string]interface{}{
"accounts": []*types.GenesisAccount{
types.NewGenesisAccount(acc1),
},
"cool": map[string]string{
"trend": "ice-cold",
},
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
require.Nil(t, err)
// Initialize the chain (nil)
vals := []abci.Validator{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
// Set the trend, submit a really cool quiz and check for reward
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
CheckBalance(t, bapp, "69icecold")
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
CheckBalance(t, bapp, "69icecold")
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
CheckBalance(t, bapp, "138icecold")
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
CheckBalance(t, bapp, "138icecold")
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
CheckBalance(t, bapp, "69badvibesonly,138icecold")
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
}
func TestHandler(t *testing.T) {
bapp := newDemocoinApp()
sourceChain := "source-chain"
destChain := "dest-chain"
vals := []abci.Validator{}
baseAcc := auth.BaseAccount{
Address: addr1,
Coins: coins,
}
acc1 := &types.AppAccount{baseAcc, "foobart"}
genesisState := map[string]interface{}{
"accounts": []*types.GenesisAccount{
types.NewGenesisAccount(acc1),
},
"cool": map[string]string{
"trend": "ice-cold",
},
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
require.Nil(t, err)
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
// A checkTx context (true)
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
packet := ibc.IBCPacket{
SrcAddr: addr1,
DestAddr: addr1,
Coins: coins,
SrcChain: sourceChain,
DestChain: destChain,
}
transferMsg := ibc.IBCTransferMsg{
IBCPacket: packet,
}
receiveMsg := ibc.IBCReceiveMsg{
IBCPacket: packet,
Relayer: addr1,
Sequence: 0,
}
SignCheckDeliver(t, bapp, transferMsg, 0, true)
CheckBalance(t, bapp, "")
SignCheckDeliver(t, bapp, transferMsg, 1, false)
SignCheckDeliver(t, bapp, receiveMsg, 2, true)
CheckBalance(t, bapp, "10foocoin")
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
}
// TODO describe the use of this function
func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, expPass bool) {
// Sign the tx
tx := auth.NewStdTx(msg, fee, []auth.StdSignature{{
PubKey: priv1.PubKey(),
Signature: priv1.Sign(auth.StdSignBytes(chainID, []int64{seq}, fee, msg)),
Sequence: seq,
}})
// Run a Check
res := bapp.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
// Simulate a Block
bapp.BeginBlock(abci.RequestBeginBlock{})
res = bapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
bapp.EndBlock(abci.RequestEndBlock{})
//bapp.Commit()
}
func CheckBalance(t *testing.T, bapp *DemocoinApp, balExpected string) {
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
}

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewDemocoinApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
dapp := app.NewDemocoinApp(logger, db)
return dapp.ExportAppStateJSON()
return dapp.ExportAppStateAndValidators()
}
func main() {
@ -63,7 +64,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
server.ConstructAppCreator(newApp, "democoin"),
server.ConstructAppExporter(exportAppState, "democoin"))
server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.democoind")

View File

@ -0,0 +1,105 @@
package cool
import (
"testing"
"github.com/stretchr/testify/assert"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
bank "github.com/cosmos/cosmos-sdk/x/bank"
)
var (
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
quizMsg1 = MsgQuiz{
Sender: addr1,
CoolAnswer: "icecold",
}
quizMsg2 = MsgQuiz{
Sender: addr1,
CoolAnswer: "badvibesonly",
}
setTrendMsg1 = MsgSetTrend{
Sender: addr1,
Cool: "icecold",
}
setTrendMsg2 = MsgSetTrend{
Sender: addr1,
Cool: "badvibesonly",
}
setTrendMsg3 = MsgSetTrend{
Sender: addr1,
Cool: "warmandkind",
}
)
// initialize the mock application for this module
func getMockApp(t *testing.T) *mock.App {
mapp := mock.NewApp()
RegisterWire(mapp.Cdc)
keyCool := sdk.NewKVStoreKey("cool")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
keeper := NewKeeper(keyCool, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("cool", NewHandler(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
mapp.CompleteSetup(t, []*sdk.KVStoreKey{keyCool})
return mapp
}
// overwrite the mock init chainer
func getInitChainer(mapp *mock.App, keeper Keeper, newTrend string) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req)
keeper.setTrend(ctx, newTrend)
return abci.ResponseInitChain{}
}
}
func TestMsgQuiz(t *testing.T) {
mapp := getMockApp(t)
// Construct genesis state
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: nil,
}
accs := []auth.Account{acc1}
// Initialize the chain (nil)
mock.SetGenesis(mapp, accs)
// A checkTx context (true)
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
// Set the trend, submit a really cool quiz and check for reward
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg1, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{1}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 69}})
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg2, []int64{0}, []int64{2}, false, priv1) // result without reward
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 69}})
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{3}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 138}})
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg2, []int64{0}, []int64{4}, true, priv1) // reset the trend
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{5}, false, priv1) // the same answer will nolonger do!
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 138}})
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg2, []int64{0}, []int64{6}, true, priv1) // earlier answer now relavent again
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", 69}, {"icecold", 138}})
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg3, []int64{0}, []int64{7}, false, priv1) // expect to fail to set the trend to something which is not cool
}

View File

@ -16,5 +16,5 @@ const (
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error {
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer))
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("incorrect cool answer: %v", answer))
}

View File

@ -0,0 +1,83 @@
package pow
import (
"testing"
"github.com/stretchr/testify/assert"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
)
var (
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
)
// initialize the mock application for this module
func getMockApp(t *testing.T) *mock.App {
mapp := mock.NewApp()
RegisterWire(mapp.Cdc)
keyPOW := sdk.NewKVStoreKey("pow")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
config := Config{"pow", 1}
keeper := NewKeeper(keyPOW, config, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("pow", keeper.Handler)
mapp.SetInitChainer(getInitChainer(mapp, keeper))
mapp.CompleteSetup(t, []*sdk.KVStoreKey{keyPOW})
return mapp
}
// overwrite the mock init chainer
func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req)
genesis := Genesis{
Difficulty: 1,
Count: 0,
}
InitGenesis(ctx, keeper, genesis)
return abci.ResponseInitChain{}
}
}
func TestMsgMine(t *testing.T) {
mapp := getMockApp(t)
// Construct genesis state
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: nil,
}
accs := []auth.Account{acc1}
// Initialize the chain (nil)
mock.SetGenesis(mapp, accs)
// A checkTx context (true)
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1)
// Mine and check for reward
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg1, []int64{0}, []int64{0}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 1}})
// Mine again and check for reward
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg2, []int64{0}, []int64{1}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 2}})
// Mine again - should be invalid
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg2, []int64{0}, []int64{1}, false, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 2}})
}

View File

@ -23,21 +23,21 @@ const (
func codeToDefaultMsg(code CodeType) string {
switch code {
case CodeInvalidDifficulty:
return "Insuffient difficulty"
return "insuffient difficulty"
case CodeNonexistentDifficulty:
return "Nonexistent difficulty"
return "nonexistent difficulty"
case CodeNonexistentReward:
return "Nonexistent reward"
return "nonexistent reward"
case CodeNonexistentCount:
return "Nonexistent count"
return "nonexistent count"
case CodeInvalidProof:
return "Invalid proof"
return "invalid proof"
case CodeNotBelowTarget:
return "Not below target"
return "not below target"
case CodeInvalidCount:
return "Invalid count"
return "invalid count"
case CodeUnknownRequest:
return "Unknown request"
return "unknown request"
default:
return sdk.CodeToDefaultMsg(code)
}

View File

@ -50,7 +50,7 @@ func main() {
}
// Start the ABCI server
srv, err := server.NewServer("0.0.0.0:46658", "socket", baseApp)
srv, err := server.NewServer("0.0.0.0:26658", "socket", baseApp)
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -9,7 +9,7 @@
- name: Gather status
uri:
body_format: json
url: "http://{{inventory_hostname}}:46657/status"
url: "http://{{inventory_hostname}}:26657/status"
register: status
- name: Print status

View File

@ -5,6 +5,7 @@ import (
"path/filepath"
abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
@ -13,8 +14,8 @@ import (
// and other flags (?) to start
type AppCreator func(string, log.Logger) (abci.Application, error)
// AppExporter dumps all app state to JSON-serializable structure
type AppExporter func(home string, log log.Logger) (json.RawMessage, error)
// AppExporter dumps all app state to JSON-serializable structure and returns the current validator set
type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error)
// ConstructAppCreator returns an application generation function
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
@ -30,12 +31,12 @@ func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name s
}
// ConstructAppExporter returns an application export function
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter {
return func(rootDir string, logger log.Logger) (json.RawMessage, error) {
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error), name string) AppExporter {
return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB(name, dataDir)
if err != nil {
return nil, err
return nil, nil, err
}
return appFn(logger, db)
}

View File

@ -18,15 +18,16 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
Short: "Export state to JSON",
RunE: func(cmd *cobra.Command, args []string) error {
home := viper.GetString("home")
appState, err := appExporter(home, ctx.Logger)
appState, validators, err := appExporter(home, ctx.Logger)
if err != nil {
return errors.Errorf("Error exporting state: %v\n", err)
return errors.Errorf("error exporting state: %v\n", err)
}
doc, err := tmtypes.GenesisDocFromFile(ctx.Config.GenesisFile())
if err != nil {
return err
}
doc.AppStateJSON = appState
doc.Validators = validators
encoded, err := wire.MarshalJSONIndent(cdc, doc)
if err != nil {
return err

View File

@ -20,7 +20,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
tmtypes "github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
pvm "github.com/tendermint/tendermint/privval"
tmcli "github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
@ -255,7 +255,7 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
if len(persistentPeers) == 0 {
comma = ""
}
persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, genTx.NodeID, genTx.IP)
persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP)
}
return

View File

@ -7,7 +7,7 @@ import (
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/mock"
"github.com/cosmos/cosmos-sdk/server/mock"
"github.com/cosmos/cosmos-sdk/wire"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
)

View File

@ -9,8 +9,8 @@ import (
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/node"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common"
)
@ -37,7 +37,7 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
// basic flags for abci app
cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint")
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:46658", "Listen address")
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address")
// AddNodeFlags adds support for all tendermint-specific command line options
tcmd.AddNodeFlags(cmd)
@ -55,7 +55,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
svr, err := server.NewServer(addr, "socket", app)
if err != nil {
return errors.Errorf("Error creating listener: %v\n", err)
return errors.Errorf("error creating listener: %v\n", err)
}
svr.SetLogger(ctx.Logger.With("module", "abci-server"))
svr.Start()

View File

@ -9,7 +9,7 @@ import (
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/mock"
"github.com/cosmos/cosmos-sdk/server/mock"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
@ -40,7 +40,7 @@ func TestStartStandAlone(t *testing.T) {
svrAddr, _, err := FreeTCPAddr()
require.Nil(t, err)
svr, err := server.NewServer(svrAddr, "socket", app)
require.Nil(t, err, "Error creating listener")
require.Nil(t, err, "error creating listener")
svr.SetLogger(logger.With("module", "abci-server"))
svr.Start()

View File

@ -10,7 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/types/priv_validator"
pvm "github.com/tendermint/tendermint/privval"
)
// ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout
@ -72,7 +72,7 @@ func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
Short: "Reset blockchain database, priv_validator.json file, and the logger",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.Config
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)
tcmd.ResetAll(cfg.DBDir(), cfg.P2P.AddrBookFile(), cfg.PrivValidatorFile(), ctx.Logger)
return nil
},
}

View File

@ -89,7 +89,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
id := CommitID{}
store, err := rs.loadCommitStoreFromParams(id, storeParams)
if err != nil {
return fmt.Errorf("Failed to load rootMultiStore: %v", err)
return fmt.Errorf("failed to load rootMultiStore: %v", err)
}
rs.stores[key] = store
}
@ -112,7 +112,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
storeParams := rs.storesParams[key]
store, err := rs.loadCommitStoreFromParams(commitID, storeParams)
if err != nil {
return fmt.Errorf("Failed to load rootMultiStore: %v", err)
return fmt.Errorf("failed to load rootMultiStore: %v", err)
}
newStores[key] = store
}
@ -120,7 +120,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
// If any CommitStoreLoaders were not used, return error.
for key := range rs.storesParams {
if _, ok := newStores[key]; !ok {
return fmt.Errorf("Unused CommitStoreLoader: %v", key)
return fmt.Errorf("unused CommitStoreLoader: %v", key)
}
}
@ -399,14 +399,14 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) {
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)
cInfoBytes := db.Get([]byte(cInfoKey))
if cInfoBytes == nil {
return commitInfo{}, fmt.Errorf("Failed to get rootMultiStore: no data")
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: no data")
}
// Parse bytes.
var cInfo commitInfo
err := cdc.UnmarshalBinary(cInfoBytes, &cInfo)
if err != nil {
return commitInfo{}, fmt.Errorf("Failed to get rootMultiStore: %v", err)
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: %v", err)
}
return cInfo, nil
}

View File

@ -7,16 +7,65 @@ import (
"time"
amino "github.com/tendermint/go-amino"
tmclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
)
// Uses localhost
func WaitForHeight(height int64, port string) {
// Wait for the next tendermint block from the Tendermint RPC
// on localhost
func WaitForNextHeightTM(port string) {
url := fmt.Sprintf("http://localhost:%v", port)
cl := tmclient.NewHTTP(url, "/websocket")
resBlock, err := cl.Block(nil)
if err != nil {
panic(err)
}
waitForHeightTM(resBlock.Block.Height+1, url)
}
// Wait for the given height from the Tendermint RPC
// on localhost
func WaitForHeightTM(height int64, port string) {
url := fmt.Sprintf("http://localhost:%v", port)
waitForHeightTM(height, url)
}
func waitForHeightTM(height int64, url string) {
cl := tmclient.NewHTTP(url, "/websocket")
for {
// get url, try a few times
var resBlock *ctypes.ResultBlock
var err error
INNER:
for i := 0; i < 5; i++ {
resBlock, err = cl.Block(nil)
if err == nil {
break INNER
}
time.Sleep(time.Millisecond * 200)
}
if err != nil {
panic(err)
}
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
if resBlock.Block != nil &&
resBlock.Block.Height >= height {
fmt.Println("HEIGHT", resBlock.Block.Height)
return
}
time.Sleep(time.Millisecond * 100)
}
}
// Wait for height from the LCD API on localhost
func WaitForHeight(height int64, port string) {
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
waitForHeight(height, url)
}
func waitForHeight(height int64, url string) {
for {
// get url, try a few times
var res *http.Response
var err error
@ -25,7 +74,7 @@ func WaitForHeight(height int64, port string) {
if err == nil {
break
}
time.Sleep(time.Second)
time.Sleep(time.Millisecond * 200)
}
if err != nil {
panic(err)
@ -45,7 +94,8 @@ func WaitForHeight(height int64, port string) {
panic(err)
}
if resultBlock.Block.Height >= height {
if resultBlock.Block != nil &&
resultBlock.Block.Height >= height {
return
}
time.Sleep(time.Millisecond * 100)

View File

@ -26,21 +26,57 @@ func Bech32ifyAcc(addr Address) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
}
// MustBech32ifyAcc panics on bech32-encoding failure
func MustBech32ifyAcc(addr Address) string {
enc, err := Bech32ifyAcc(addr)
if err != nil {
panic(err)
}
return enc
}
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
}
// MustBech32ifyAccPub panics on bech32-encoding failure
func MustBech32ifyAccPub(pub crypto.PubKey) string {
enc, err := Bech32ifyAccPub(pub)
if err != nil {
panic(err)
}
return enc
}
// Bech32ifyVal returns the bech32 encoded string for a validator address
func bech32ifyVal(addr Address) (string, error) {
func Bech32ifyVal(addr Address) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
}
// MustBech32ifyVal panics on bech32-encoding failure
func MustBech32ifyVal(addr Address) string {
enc, err := Bech32ifyVal(addr)
if err != nil {
panic(err)
}
return enc
}
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
}
// MustBech32ifyValPub pancis on bech32-encoding failure
func MustBech32ifyValPub(pub crypto.PubKey) string {
enc, err := Bech32ifyValPub(pub)
if err != nil {
panic(err)
}
return enc
}
// create an Address from a string
func GetAccAddressHex(address string) (addr Address, err error) {
if len(address) == 0 {
@ -55,13 +91,28 @@ func GetAccAddressHex(address string) (addr Address, err error) {
// create an Address from a string
func GetAccAddressBech32(address string) (addr Address, err error) {
bz, err := getFromBech32(address, Bech32PrefixAccAddr)
bz, err := GetFromBech32(address, Bech32PrefixAccAddr)
if err != nil {
return nil, err
}
return Address(bz), nil
}
// create a Pubkey from a string
func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
bz, err := GetFromBech32(address, Bech32PrefixAccPub)
if err != nil {
return nil, err
}
pk, err = crypto.PubKeyFromBytes(bz)
if err != nil {
return nil, err
}
return pk, nil
}
// create an Address from a hex string
func GetValAddressHex(address string) (addr Address, err error) {
if len(address) == 0 {
@ -76,16 +127,16 @@ func GetValAddressHex(address string) (addr Address, err error) {
// create an Address from a bech32 string
func GetValAddressBech32(address string) (addr Address, err error) {
bz, err := getFromBech32(address, Bech32PrefixValAddr)
bz, err := GetFromBech32(address, Bech32PrefixValAddr)
if err != nil {
return nil, err
}
return Address(bz), nil
}
//Decode a validator publickey into a public key
// decode a validator public key into a PubKey
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
bz, err := getFromBech32(pubkey, Bech32PrefixValPub)
bz, err := GetFromBech32(pubkey, Bech32PrefixValPub)
if err != nil {
return nil, err
}
@ -98,7 +149,8 @@ func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
return pk, nil
}
func getFromBech32(bech32str, prefix string) ([]byte, error) {
// decode a bytestring from a bech32-encoded string
func GetFromBech32(bech32str, prefix string) ([]byte, error) {
if len(bech32str) == 0 {
return nil, errors.New("must provide non-empty string")
}
@ -108,7 +160,7 @@ func getFromBech32(bech32str, prefix string) ([]byte, error) {
}
if hrp != prefix {
return nil, fmt.Errorf("Invalid bech32 prefix. Expected %s, Got %s", prefix, hrp)
return nil, fmt.Errorf("invalid bech32 prefix. Expected %s, Got %s", prefix, hrp)
}
return bz, nil

View File

@ -280,7 +280,7 @@ func ParseCoin(coinStr string) (coin Coin, err error) {
matches := reCoin.FindStringSubmatch(coinStr)
if matches == nil {
err = fmt.Errorf("Invalid coin expression: %s", coinStr)
err = fmt.Errorf("invalid coin expression: %s", coinStr)
return
}
denomStr, amountStr := matches[2], matches[1]
@ -316,7 +316,7 @@ func ParseCoins(coinsStr string) (coins Coins, err error) {
// Validate coins before returning.
if !coins.IsValid() {
return nil, fmt.Errorf("ParseCoins invalid: %#v", coins)
return nil, fmt.Errorf("parseCoins invalid: %#v", coins)
}
return coins, nil

View File

@ -68,31 +68,31 @@ const (
func CodeToDefaultMsg(code CodeType) string {
switch code {
case CodeInternal:
return "Internal error"
return "internal error"
case CodeTxDecode:
return "Tx parse error"
return "tx parse error"
case CodeInvalidSequence:
return "Invalid sequence"
return "invalid sequence"
case CodeUnauthorized:
return "Unauthorized"
return "unauthorized"
case CodeInsufficientFunds:
return "Insufficent funds"
return "insufficent funds"
case CodeUnknownRequest:
return "Unknown request"
return "unknown request"
case CodeInvalidAddress:
return "Invalid address"
return "invalid address"
case CodeInvalidPubKey:
return "Invalid pubkey"
return "invalid pubkey"
case CodeUnknownAddress:
return "Unknown address"
return "unknown address"
case CodeInsufficientCoins:
return "Insufficient coins"
return "insufficient coins"
case CodeInvalidCoins:
return "Invalid coins"
return "invalid coins"
case CodeOutOfGas:
return "Out of gas"
return "out of gas"
default:
return fmt.Sprintf("Unknown code %d", code)
return fmt.Sprintf("unknown code %d", code)
}
}
@ -183,7 +183,7 @@ type sdkError struct {
// Implements ABCIError.
func (err *sdkError) Error() string {
return fmt.Sprintf("Error{%d:%d,%#v}", err.codespace, err.code, err.err)
return fmt.Sprintf("error{%d:%d,%#v}", err.codespace, err.code, err.err)
}
// Implements ABCIError.

View File

@ -32,6 +32,7 @@ func BondStatusToString(b BondStatus) string {
// validator for a delegated proof of stake system
type Validator interface {
GetMoniker() string // moniker of the validator
GetStatus() BondStatus // status of the validator
GetOwner() Address // owner address to receive/return validators coins
GetPubKey() crypto.PubKey // validation pubkey

View File

@ -5,4 +5,5 @@ import wire "github.com/cosmos/cosmos-sdk/wire"
// Register the sdk message type
func RegisterWire(cdc *wire.Codec) {
cdc.RegisterInterface((*Msg)(nil), nil)
cdc.RegisterInterface((*Tx)(nil), nil)
}

View File

@ -1,15 +1,11 @@
//nolint
package version
// when updating these,
// remember to also update examples/basecoin/tests/cli/rpc.sh
// TODO improve
const Maj = "0"
const Min = "18"
const Min = "20"
const Fix = "0"
const Version = "0.18.0-dev"
const Version = "0.20.0-dev"
// GitCommit set by build flags
var GitCommit = ""

View File

@ -17,6 +17,9 @@ type Account interface {
GetPubKey() crypto.PubKey // can return nil.
SetPubKey(crypto.PubKey) error
GetAccountNumber() int64
SetAccountNumber(int64) error
GetSequence() int64
SetSequence(int64) error
@ -36,10 +39,11 @@ var _ Account = (*BaseAccount)(nil)
// Extend this by embedding this in your AppAccount.
// See the examples/basecoin/types/account.go for an example.
type BaseAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
PubKey crypto.PubKey `json:"public_key"`
Sequence int64 `json:"sequence"`
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
PubKey crypto.PubKey `json:"public_key"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
}
func NewBaseAccountWithAddress(addr sdk.Address) BaseAccount {
@ -84,6 +88,17 @@ func (acc *BaseAccount) SetCoins(coins sdk.Coins) error {
return nil
}
// Implements Account
func (acc *BaseAccount) GetAccountNumber() int64 {
return acc.AccountNumber
}
// Implements Account
func (acc *BaseAccount) SetAccountNumber(accNumber int64) error {
acc.AccountNumber = accNumber
return nil
}
// Implements sdk.Account.
func (acc *BaseAccount) GetSequence() int64 {
return acc.Sequence

View File

@ -14,7 +14,7 @@ const (
)
// NewAnteHandler returns an AnteHandler that checks
// and increments sequence numbers, checks signatures,
// and increments sequence numbers, checks signatures & account numbers,
// and deducts fees from the first signer.
func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
@ -46,11 +46,15 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
true
}
// Get the sign bytes (requires all sequence numbers and the fee)
// Get the sign bytes (requires all account & sequence numbers and the fee)
sequences := make([]int64, len(signerAddrs))
for i := 0; i < len(signerAddrs); i++ {
sequences[i] = sigs[i].Sequence
}
accNums := make([]int64, len(signerAddrs))
for i := 0; i < len(signerAddrs); i++ {
accNums[i] = sigs[i].AccountNumber
}
fee := stdTx.Fee
chainID := ctx.ChainID()
// XXX: major hack; need to get ChainID
@ -58,7 +62,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
if chainID == "" {
chainID = viper.GetString("chain-id")
}
signBytes := StdSignBytes(ctx.ChainID(), sequences, fee, msg)
signBytes := StdSignBytes(ctx.ChainID(), accNums, sequences, fee, msg)
// Check sig and nonce and collect signer accounts.
var signerAccs = make([]Account, len(signerAddrs))
@ -117,6 +121,13 @@ func processSig(
return nil, sdk.ErrUnknownAddress(addr.String()).Result()
}
// Check account number.
accnum := acc.GetAccountNumber()
if accnum != sig.AccountNumber {
return nil, sdk.ErrInvalidSequence(
fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result()
}
// Check and increment sequence number.
seq := acc.GetSequence()
if seq != sig.Sequence {

View File

@ -52,15 +52,15 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code)
}
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee) sdk.Tx {
signBytes := StdSignBytes(ctx.ChainID(), seqs, fee, msg)
return newTestTxWithSignBytes(msg, privs, seqs, fee, signBytes)
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee) sdk.Tx {
signBytes := StdSignBytes(ctx.ChainID(), accNums, seqs, fee, msg)
return newTestTxWithSignBytes(msg, privs, accNums, seqs, fee, signBytes)
}
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee, signBytes []byte) sdk.Tx {
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee, signBytes []byte) sdk.Tx {
sigs := make([]StdSignature, len(privs))
for i, priv := range privs {
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), Sequence: seqs[i]}
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), AccountNumber: accNums[i], Sequence: seqs[i]}
}
tx := NewStdTx(msg, fee, sigs)
return tx
@ -87,18 +87,18 @@ func TestAnteHandlerSigErrors(t *testing.T) {
fee := newStdFee()
// test no signatures
privs, seqs := []crypto.PrivKey{}, []int64{}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accNums, seqs := []crypto.PrivKey{}, []int64{}, []int64{}
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
// test num sigs dont match GetSigners
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accNums, seqs = []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
// test an unrecognized account
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accNums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{0, 0}
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
// save the first account, but second is still unrecognized
@ -108,6 +108,61 @@ func TestAnteHandlerSigErrors(t *testing.T) {
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
}
// Test logic around account number checking with one signer and many signers.
func TestAnteHandlerAccountNumbers(t *testing.T) {
// setup
ms, capKey, capKey2 := setupMultiStore()
cdc := wire.NewCodec()
RegisterBaseAccount(cdc)
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
anteHandler := NewAnteHandler(mapper, feeCollector)
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
// keys and addresses
priv1, addr1 := privAndAddr()
priv2, addr2 := privAndAddr()
// set the accounts
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
acc1.SetCoins(newCoins())
mapper.SetAccount(ctx, acc1)
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
acc2.SetCoins(newCoins())
mapper.SetAccount(ctx, acc2)
// msg and signatures
var tx sdk.Tx
msg := newTestMsg(addr1)
fee := newStdFee()
// test good tx from one signer
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
// new tx from wrong account number
seqs = []int64{1}
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
// from correct account number
seqs = []int64{1}
tx = newTestTx(ctx, msg, privs, []int64{0}, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
// new tx with another signer and incorrect account numbers
msg = newTestMsg(addr1, addr2)
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{1, 0}, []int64{2, 0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
// correct account numbers
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{2, 0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
}
// Test logic around sequence checking with one signer and many signers.
func TestAnteHandlerSequences(t *testing.T) {
// setup
@ -137,8 +192,8 @@ func TestAnteHandlerSequences(t *testing.T) {
fee := newStdFee()
// test good tx from one signer
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
// test sending it again fails (replay protection)
@ -146,13 +201,13 @@ func TestAnteHandlerSequences(t *testing.T) {
// fix sequence, should pass
seqs = []int64{1}
tx = newTestTx(ctx, msg, privs, seqs, fee)
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
// new tx with another signer and correct sequences
msg = newTestMsg(addr1, addr2)
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{2, 0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{2, 0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
// replay fails
@ -160,18 +215,18 @@ func TestAnteHandlerSequences(t *testing.T) {
// tx from just second signer with incorrect sequence fails
msg = newTestMsg(addr2)
privs, seqs = []crypto.PrivKey{priv2}, []int64{0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{1}, []int64{0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
// fix the sequence and it passes
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, fee)
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, []int64{1}, fee)
checkValidTx(t, anteHandler, ctx, tx)
// another tx from both of them that passes
msg = newTestMsg(addr1, addr2)
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{3, 2}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{3, 2}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
}
@ -196,13 +251,13 @@ func TestAnteHandlerFees(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := newTestMsg(addr1)
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
fee := NewStdFee(100,
sdk.Coin{"atom", 150},
)
// signer does not have enough funds to pay the fee
tx = newTestTx(ctx, msg, privs, seqs, fee)
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds)
acc1.SetCoins(sdk.Coins{{"atom", 149}})
@ -249,8 +304,8 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
fee3.Amount[0].Amount += 100
// test good tx and signBytes
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
chainID := ctx.ChainID()
@ -259,37 +314,39 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
cases := []struct {
chainID string
accnums []int64
seqs []int64
fee StdFee
msg sdk.Msg
code sdk.CodeType
}{
{chainID2, []int64{1}, fee, msg, codeUnauth}, // test wrong chain_id
{chainID, []int64{2}, fee, msg, codeUnauth}, // test wrong seqs
{chainID, []int64{1, 2}, fee, msg, codeUnauth}, // test wrong seqs
{chainID, []int64{1}, fee, newTestMsg(addr2), codeUnauth}, // test wrong msg
{chainID, []int64{1}, fee2, newTestMsg(addr2), codeUnauth}, // test wrong fee
{chainID, []int64{1}, fee3, newTestMsg(addr2), codeUnauth}, // test wrong fee
{chainID2, []int64{0}, []int64{1}, fee, msg, codeUnauth}, // test wrong chain_id
{chainID, []int64{0}, []int64{2}, fee, msg, codeUnauth}, // test wrong seqs
{chainID, []int64{0}, []int64{1, 2}, fee, msg, codeUnauth}, // test wrong seqs
{chainID, []int64{1}, []int64{1}, fee, msg, codeUnauth}, // test wrong accnum
{chainID, []int64{0}, []int64{1}, fee, newTestMsg(addr2), codeUnauth}, // test wrong msg
{chainID, []int64{0}, []int64{1}, fee2, msg, codeUnauth}, // test wrong fee
{chainID, []int64{0}, []int64{1}, fee3, msg, codeUnauth}, // test wrong fee
}
privs, seqs = []crypto.PrivKey{priv1}, []int64{1}
for _, cs := range cases {
tx := newTestTxWithSignBytes(
msg, privs, seqs, fee,
StdSignBytes(cs.chainID, cs.seqs, cs.fee, cs.msg),
msg, privs, accnums, seqs, fee,
StdSignBytes(cs.chainID, cs.accnums, cs.seqs, cs.fee, cs.msg),
)
checkInvalidTx(t, anteHandler, ctx, tx, cs.code)
}
// test wrong signer if public key exist
privs, seqs = []crypto.PrivKey{priv2}, []int64{1}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{0}, []int64{1}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
// test wrong signer if public doesn't exist
msg = newTestMsg(addr2)
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
tx = newTestTx(ctx, msg, privs, seqs, fee)
privs, accnums, seqs = []crypto.PrivKey{priv1}, []int64{1}, []int64{0}
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
}
@ -320,9 +377,9 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
// test good tx and set public key
msg := newTestMsg(addr1)
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
fee := newStdFee()
tx = newTestTx(ctx, msg, privs, seqs, fee)
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
checkValidTx(t, anteHandler, ctx, tx)
acc1 = mapper.GetAccount(ctx, addr1)
@ -330,7 +387,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
// test public key not found
msg = newTestMsg(addr2)
tx = newTestTx(ctx, msg, privs, seqs, fee)
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
sigs := tx.(StdTx).GetSignatures()
sigs[0].PubKey = nil
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
@ -339,7 +396,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
assert.Nil(t, acc2.GetPubKey())
// test invalid signature and public key
tx = newTestTx(ctx, msg, privs, seqs, fee)
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
acc2 = mapper.GetAccount(ctx, addr2)

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